/* ============================================================
   EVEN GROUND — Design System
   Vanilla CSS · Custom Properties · Fluid Typography
   Identity: Warm, editorial, documentary, grounded
   ============================================================ */

/* --- Reset & Base ----------------------------------------- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* --- Design Tokens --------------------------------------- */
:root {
  /* Brand palette — derived from partner map graphic */
  --navy:        #1a2e4a;
  --navy-light:  #2a4468;
  --navy-dark:   #0f1d30;
  --green:       #3d7a3e;
  --green-light: #4a9a4b;
  --green-dark:  #2d5a2e;
  --gold:        #e8b84b;
  --gold-light:  #f0cc6e;
  --gold-soft:   rgba(232, 184, 75, 0.15);
  --gold-dark:   #c99a30;

  /* Neutrals — warm-tinted, not cold gray */
  --white:       #ffffff;
  --cream:       #faf8f4;
  --cream-dark:  #f2efe8;
  --sand:        #e8e4db;
  --stone:       #c5bfb3;
  --earth:       #8a8275;
  --charcoal:    #4a4540;
  --ink:         #2c2824;

  /* Semantic */
  --bg-primary:     var(--cream);
  --bg-secondary:   var(--white);
  --bg-dark:        var(--navy-dark);
  --bg-accent:      var(--green);
  --text-primary:   var(--ink);
  --text-secondary: var(--earth);
  --text-heading:   var(--navy);
  --text-on-dark:   var(--cream);
  --text-on-accent: var(--white);
  --border-light:   var(--sand);
  --border-dark:    rgba(255, 255, 255, 0.12);

  /* Typography — fluid with clamp() */
  --font-family:    'Montserrat', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-xs:        clamp(0.7rem,   0.65rem + 0.25vw,  0.8rem);
  --font-sm:        clamp(0.8rem,   0.75rem + 0.25vw,  0.9rem);
  --font-base:      clamp(0.95rem,  0.88rem + 0.35vw,  1.1rem);
  --font-lg:        clamp(1.1rem,   1rem + 0.5vw,      1.35rem);
  --font-xl:        clamp(1.35rem,  1.15rem + 1vw,     1.8rem);
  --font-2xl:       clamp(1.7rem,   1.4rem + 1.5vw,    2.5rem);
  --font-3xl:       clamp(2.2rem,   1.8rem + 2vw,      3.2rem);
  --font-display:   clamp(2.8rem,   2.2rem + 3vw,      4.5rem);

  /* Spacing — fluid */
  --space-xs:   clamp(0.25rem, 0.2rem + 0.25vw,  0.5rem);
  --space-sm:   clamp(0.5rem,  0.4rem + 0.5vw,   0.875rem);
  --space-md:   clamp(1rem,    0.8rem + 1vw,      1.5rem);
  --space-lg:   clamp(1.5rem,  1.2rem + 1.5vw,    2.5rem);
  --space-xl:   clamp(2.5rem,  2rem + 2.5vw,      4rem);
  --space-2xl:  clamp(4rem,    3rem + 4vw,        7rem);
  --space-3xl:  clamp(6rem,    4.5rem + 6vw,      10rem);

  /* Anchor offset — single source of truth for in-page scroll landings.
     JS (initAnchorOffset) overwrites this with the measured scrolled-nav
     height + breathing room. This value is the no-JS fallback. */
  --anchor-offset: 4.5rem;

  /* Layout */
  --content-width:   72rem;
  --narrow-width:    60rem;
  --wide-width:      90rem;

  /* Radius */
  --radius-sm:   0.25rem;
  --radius-md:   0.5rem;
  --radius-lg:   1rem;
  --radius-xl:   1.5rem;
  --radius-full: 62.5rem;

  /* Shadows — warm, not cold */
  --shadow-sm:    0 1px 3px rgba(44, 40, 36, 0.06), 0 1px 2px rgba(44, 40, 36, 0.04);
  --shadow-md:    0 4px 12px rgba(44, 40, 36, 0.08);
  --shadow-lg:    0 8px 24px rgba(44, 40, 36, 0.1);
  --shadow-xl:    0 16px 48px rgba(44, 40, 36, 0.12);
  /* Editorial title shadow — three layers:
     1. A tight hard shadow (no blur) sits just below the glyph edge for
        clean definition that doesn't muddy the photo underneath.
     2. A short soft shadow gives mid-distance lift.
     3. A wide diffuse shadow grounds the text on busy backgrounds. */
  --shadow-text:
    0 1px 0 rgba(0, 0, 0, 0.55),
    0 3px 8px rgba(0, 0, 0, 0.45),
    0 14px 36px rgba(0, 0, 0, 0.40);

  /* Alert/accent — for "issue" labels and similar warning context */
  --red:         #c44545;
  --red-light:   #f08080;

  /* Transitions */
  --ease-out:     cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out:  cubic-bezier(0.45, 0, 0.55, 1);
  --duration:     0.5s;
  --duration-fast: 0.3s;
  --duration-slow: 0.8s;
}


/* --- Global Styles --------------------------------------- */
/* --- Intro / splash screen ---------------------------------
   Minimal Lottie-style loading indicator: "LOADING" label above a thin
   bar with a gold segment sliding across it. Holds until the hero's first
   slide has loaded, then fades out. */
.intro {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: var(--navy-dark);
  display: grid;
  place-items: center;
  align-content: center;
  gap: 0.9rem;
  opacity: 1;
  visibility: visible;
  transition: opacity 0.9s ease-out, visibility 0s linear 0.9s;
}
.intro.is-dismissed {
  opacity: 0;
  visibility: hidden;
}
.intro__label {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: rgba(250, 248, 244, 0.65);
  margin: 0;
  padding-left: 0.4em;                       /* optical balance for tracked text */
}
.intro__bar {
  width: clamp(8rem, 14vw, 12rem);
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  position: relative;
  overflow: hidden;
}
.intro__bar::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 45%;
  /* Brand palette flows past as the segment slides across — green into
     gold into cream, the three core EG colours. */
  background: linear-gradient(
    90deg,
    var(--green)  0%,
    var(--gold)  50%,
    var(--cream) 100%
  );
  border-radius: 2px;
  animation: intro-bar-slide 1.8s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes intro-bar-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}
@media (prefers-reduced-motion: reduce) {
  .intro__bar::after { animation: none; left: 30%; opacity: 0.7; }
}

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Prevent the trackpad-wiggle white sliver — any element that's a few
     pixels wider than the viewport (carousel scrollers, decorative orbs,
     etc.) is clipped at the document edge instead of leaking sideways.
     `clip` doesn't create a scrollport (unlike `hidden`), so position:sticky
     and other layout features stay intact. */
  overflow-x: clip;
}

body {
  font-family: var(--font-family);
  font-size: var(--font-base);
  line-height: 1.7;
  color: var(--text-primary);
  background-color: var(--bg-primary);
  overflow-x: clip;                          /* belt-and-braces for older Chromium */
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: var(--green);
  text-decoration: none;
  transition: color var(--duration) var(--ease-out);
  -webkit-user-drag: none;
}
a:hover {
  color: var(--green-light);
}
img {
  -webkit-user-drag: none;
}


/* --- Typography ------------------------------------------ */
h1, h2, h3, h4, h5, h6 {
  color: var(--text-heading);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  /* Balance wrapping so headlines never orphan a single word on the
     last line (no more "you" sitting alone after a 7-word line). */
  text-wrap: balance;
}

h1 { font-size: var(--font-display); }
h2 { font-size: var(--font-3xl); }
h3 { font-size: var(--font-2xl); }
h4 { font-size: var(--font-xl); }
h5 { font-size: var(--font-lg); }

p + p { margin-top: 1em; }

.eyebrow {
  display: inline-block;
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--green);
  background: transparent;
  border: 2px solid var(--green);
  padding: 0.4em 1.2em;
  border-radius: var(--radius-full);
  margin-bottom: var(--space-md);
}

/* On dark / hero backgrounds, keep the outlined-pill treatment for
   consistency — use the lighter green so the outline + text stay legible
   against navy. */
.section--dark .eyebrow,
.hero .eyebrow,
.page-hero .eyebrow {
  background: transparent;
  color: var(--green-light);
  border-color: var(--green-light);
}

.lead {
  font-size: var(--font-lg);
  line-height: 1.6;
  color: var(--text-secondary);
}

blockquote {
  position: relative;
  padding: var(--space-lg) var(--space-xl);
  margin: var(--space-xl) 0;
  font-size: var(--font-xl);
  font-weight: 500;
  font-style: italic;
  line-height: 1.5;
  color: var(--navy);
  border-left: 4px solid var(--gold);
  background: var(--gold-soft);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
}

blockquote cite {
  display: block;
  margin-top: var(--space-sm);
  font-size: var(--font-sm);
  font-style: normal;
  font-weight: 600;
  color: var(--text-secondary);
}

.section--green blockquote cite {
  color: var(--gold-light);
}


/* --- Layout Utilities ------------------------------------ */
.container {
  width: 100%;
  max-width: var(--content-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

.container--narrow {
  max-width: var(--narrow-width);
}

.section {
  padding-block: var(--space-xl);
  background-color: var(--bg-primary);
  position: relative;
  scroll-margin-top: 0;  /* land section top at the viewport top — see initSmoothScroll */
}
/* #stories keeps extra top padding so the previous hero clears as it
   scrolls out; nav clearance itself is handled by --anchor-offset. */
.section#stories {
  padding-top: var(--space-2xl);
}

/* Full-viewport section — for the home-page "deck" pattern where each
   section reads as a complete stage when navigated to. Content vertically
   centres inside the viewport. Filler sections (the Mandela quote, etc.)
   deliberately do NOT use this so they punctuate the flow. */
.section--full {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* scroll-margin-top inherited from .section (--anchor-offset) */
  /* Symmetric generous padding — content centres in viewport, with even
     breathing room above and below. The pill nav floats over the top
     portion of this padding; content has clearance because of the padding
     itself, not via asymmetric offset. */
  padding-block: var(--space-2xl);
}

/* Inside a full-viewport section, content scales up so it fills the stage
   instead of floating in negative space. Scoped to .section--full only —
   never bleeds into other places that reuse the same components. */

/* Constrain content width inside the stage so cards/stats/etc. feel
   proportional rather than sprawled. The section's own padding-block plus
   this max-width creates the comfortable breathing margin on all four sides. */
.section--full > .container {
  max-width: 76rem;
}

/* Generous gap between grid items so cards don't crowd each other */
.section--full .grid {
  gap: var(--space-xl);
}

/* Section header gets dramatic editorial weight + room to breathe before content */
.section--full .section-header {
  margin-bottom: var(--space-xl);
  max-width: 48rem;
  margin-inline: auto;
}
/* The partners carousel adds its own `padding-block: var(--space-lg)`
   above the cards, so the section-header doesn't need to stack a second
   gap on top of it. Tightens the header-to-cards distance. */
#partners .section-header {
  margin-bottom: var(--space-sm);
}
.section--full .section-header h2 {
  font-size: clamp(2.5rem, 1.8rem + 3vw, 4.25rem);
  /* Was -0.025em — far too tight at this display size: adjacent f's in
     "Difference" collided into one glyph. Near-neutral tracking + ligatures
     off keeps them cleanly separate while staying editorial. */
  letter-spacing: -0.005em;
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "dlig" 0;
  line-height: 1.05;
}
.section--full .section-header .eyebrow {
  font-size: var(--font-sm);
  padding: 0.45em 1.35em;
}
.section--full .section-header .lead {
  font-size: var(--font-lg);
  margin-top: var(--space-md);
}

/* Pillar cards inside a full stage: even interior padding, slightly larger
   title. The flex centering inside the card (defined on .pillar-card itself)
   keeps content middle-aligned when the grid stretches cards to match heights. */
.section--full .pillar-card {
  padding: var(--space-lg);
}
.section--full .pillar-card__title {
  font-size: var(--font-xl);
  margin-bottom: var(--space-sm);
}

/* No column-width cap — narrow cards force the verbose copy into too many
   lines, making cards tall and elongated. Wider cards (1fr each in the
   container) give the text room to wrap in fewer lines, keeping cards
   closer to square. */

/* Stats: huge numbers but each tile gets enough horizontal room so the
   widest values ("200,000+") don't overflow into the neighbour. */
.section--full .stats {
  gap: var(--space-xl) var(--space-2xl);
  max-width: 72rem;
  margin-inline: auto;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.section--full .stat__number {
  font-size: clamp(2.5rem, 1.8rem + 2.8vw, 4.5rem);
  margin-bottom: var(--space-sm);
  white-space: nowrap;
}
.section--full .stat__label {
  font-size: var(--font-base);
  letter-spacing: 0.1em;
}


/* ====== Impact rings — colour-outlined stat badges =========
   Each stat sits inside a fully-drawn SVG ring. The ring colours
   differentiate the data points (they don't indicate progress or
   completion targets). On scroll into view, each ring draws itself
   to full circle in sync with the counter incrementing inside.
   =========================================================== */
.impact-rings {
  display: grid;
  grid-template-columns: 1fr;             /* mobile: stacked */
  gap: var(--space-lg);
  max-width: 78rem;
  margin-inline: auto;
  align-items: start;
}
@media (min-width: 640px) {
  .impact-rings { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  /* Desktop: all four on one line, tight rhythm */
  .impact-rings {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-md);
  }
}
.impact-ring {
  text-align: center;
}
.impact-ring__circle {
  position: relative;
  width: clamp(10rem, 8rem + 3vw, 13rem);
  height: clamp(10rem, 8rem + 3vw, 13rem);
  margin: 0 auto var(--space-md);
}
.impact-ring__circle svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);            /* start drawing from top */
}
.impact-ring__circle circle {
  fill: none;
  stroke-width: 6;
  stroke-linecap: round;
}
.impact-ring__track {
  stroke: var(--sand);
}
.impact-ring__fill {
  stroke: var(--ring-color, var(--green));
  stroke-dasharray: 264;                 /* circumference of r=42 ≈ 263.89 */
  stroke-dashoffset: 264;
  transition: stroke-dashoffset 1.4s var(--ease-out);
}
.impact-ring--green-light { --ring-color: var(--green-light); }
.impact-ring--gold        { --ring-color: var(--gold); }
.impact-ring--navy        { --ring-color: var(--navy); }
.impact-ring--red-light   { --ring-color: var(--red-light); }
.impact-rings.is-in-view .impact-ring__fill {
  stroke-dashoffset: 0;                  /* always fully drawn — no target meaning */
}
.impact-ring__text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.impact-ring__number {
  font-size: clamp(1.75rem, 1.4rem + 1vw, 2.5rem);
  font-weight: 860;                          /* variable-font display weight — reads as an audited figure */
  color: var(--navy);
  line-height: 1;
  letter-spacing: -0.03em;
  white-space: nowrap;
  /* Tabular lining figures so 7,066 / 200,000+ align like annual-report data */
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}
/* Suffix (e.g. the "+" on 200,000+) matches the number colour so it reads clearly */
.num-suffix { color: inherit; }
.impact-ring__label {
  font-size: var(--font-xs);
  font-weight: 500;                          /* lighter than the figure — opens the weight contrast */
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-secondary);
  line-height: 1.4;
  max-width: 14rem;
  margin-inline: auto;
}

/* Impact section sits on navy. The eyebrow + H2 stay outside as standard
   section-header treatment (green-light pill, white H2 from .section--dark).
   The rings sit inside a cream card so the data reads as a contained artifact
   against the dark backdrop. */
.impact-card {
  background: var(--cream);
  border-radius: clamp(1.25rem, 0.5rem + 1.5vw, 2rem);
  padding: clamp(2rem, 1rem + 4vw, 4rem) clamp(1.5rem, 0.75rem + 2.5vw, 3.5rem);
  max-width: 84rem;
  margin-inline: auto;
  box-shadow: 0 30px 80px -40px rgba(0, 0, 0, 0.45);
}

/* Board photos: comfortably-sized, generous gap so the grid feels like
   a deliberate composition rather than a sheet of thumbnails */
.section--full .board-grid {
  /* Two rows (5+4) must fit a laptop viewport with the heading clear of
     the fixed nav — width accommodates five portraits across. */
  gap: var(--space-xl) var(--space-lg);
  max-width: 64rem;
  margin-inline: auto;
}
.section--full .board-member__photo {
  width: clamp(6.5rem, 5rem + 3.5vw, 9rem);
  height: clamp(6.5rem, 5rem + 3.5vw, 9rem);
}
.section--full .board-member__name {
  font-size: var(--font-base);
  margin-top: var(--space-sm);
}

/* Subscribe / closing CTA — typographic gravity */
.section--full .newsletter-form input,
.section--full .newsletter-form .btn {
  font-size: var(--font-base);
  padding: 0.95em 1.5em;
}

.section--lg {
  padding-block: var(--space-3xl);
}

/* Mobile breathing room — bump section padding so adjacent sections never
   read as cramped against each other. Touch readers need more vertical
   space between blocks than dense desktop pages, since they can't see
   neighbouring context at a glance.

   IMPORTANT: also release `min-height: 100svh` on .story-hero and
   .section--full at this breakpoint. Those sections force a full-viewport
   height even when their content is shorter, which puts the leftover
   space OUTSIDE the padding box — making any padding bump invisible on
   sections like #partners whose content (carousel) doesn't fill a phone
   viewport. The team section already grew past 100svh on its own, which
   is why its padding-block change *was* visible. */
@media (max-width: 640px) {
  .story-hero,
  .section--full {
    min-height: 0;
  }
  .section {
    padding-block: 5rem;
  }
  .section--full,
  .section--lg {
    padding-block: 7rem;
  }
  #partners.section {
    padding-block: 8rem;
  }
  .story-hero__content {
    padding-block: 1.5rem 7rem;
  }
}

.section--dark {
  background-color: var(--bg-dark);
  color: var(--text-on-dark);
}
.section--dark h2,
.section--dark h3,
.section--dark h4 {
  color: var(--white);
}
.section--dark .lead {
  color: rgba(250, 248, 244, 0.75);
}

.section--cream {
  background-color: var(--cream-dark);
}

.section--green {
  background-color: var(--green);
  color: var(--text-on-accent);
}
.section--green h2,
.section--green h3 {
  color: var(--white);
}
.section--green .eyebrow {
  background: rgba(255, 255, 255, 0.2);
  color: var(--white);
}

.section-header {
  text-align: center;
  max-width: var(--content-width);
  margin-inline: auto;
  margin-bottom: var(--space-lg);
}


.section-header h2 {
  margin-bottom: var(--space-sm);
  /* Kept at the base 700 weight: bumping to 800 made adjacent f's collide
     ("Difference"). The typographic elevation lives in the stat numbers /
     tabular figures / variable font instead, which don't have this issue. */
}

.grid {
  display: grid;
  gap: var(--space-lg);
}

.grid--3 { grid-template-columns: 1fr; }

@media (min-width: 640px) {
  .grid--3 { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 960px) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
}


/* --- Buttons --------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.75em 1.75em;
  font-family: var(--font-family);
  font-size: var(--font-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 2px solid transparent;
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: transform var(--duration) var(--ease-out), box-shadow var(--duration) var(--ease-out), background-color var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out), color var(--duration) var(--ease-out);
  text-decoration: none;
  line-height: 1;
}

.btn--primary {
  background: var(--green);
  color: var(--white);
  border-color: var(--green);
}
.btn--primary:hover {
  background: var(--green-light);
  border-color: var(--green-light);
  color: var(--white);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.btn--gold {
  background: var(--gold);
  color: var(--navy-dark);
  border-color: var(--gold);
  font-weight: 700;
}
.btn--gold:hover {
  background: var(--gold-light);
  border-color: var(--gold-light);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.btn--ghost {
  background: transparent;
  color: var(--white);
  border-color: rgba(255, 255, 255, 0.3);
}
.btn--ghost:hover {
  background: var(--white);
  border-color: var(--white);
  color: var(--navy-dark);
}
/* Touch devices have no hover state, so a thin transparent ghost button
   gets lost on busy photo heroes. Render it as the hover treatment by
   default — solid white, navy text — on devices that can't hover. */
@media (hover: none) {
  .btn--ghost {
    background: var(--white);
    border-color: var(--white);
    color: var(--navy-dark);
  }
}

.btn--white {
  background: var(--white);
  color: var(--green);
  border-color: var(--white);
  font-weight: 700;
}
.btn--white:hover {
  background: var(--cream);
  color: var(--green-dark);
  border-color: var(--cream);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.btn--lg {
  padding: 1em 2.5em;
  font-size: var(--font-base);
}

.btn:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(232, 184, 75, 0.2);
}


/* ===========================================================
   NAVIGATION — Dynamic-Island pill
   ===========================================================
   The nav itself is a fixed positioning wrapper that pads the pill
   away from the viewport edges. The .nav__inner IS the pill —
   navy by default (white on project pages), border-radius full,
   equal padding on all sides. Logo / links / Donate-now button all
   sit inside the pill. The donate button hugs the right edge with
   the same gap above/below/right (the pill's own --nav-pad).
   =========================================================== */
:root {
  /* Pill geometry — tight vertical so the pill matches the donate button's
     height rather than feeling chunky. Horizontal padding stays generous
     so the first/last menu items don't crowd the edge. */
  --nav-pad: 0.25rem;
  --nav-pad-x: 1.1rem;
  --nav-pad-scrolled: 0.2rem;
  --nav-pad-x-scrolled: 0.9rem;
  --nav-link-px: 0.85rem;
  --nav-logo-h: 2rem;
  --nav-logo-h-scrolled: 1.6rem;
}

/* ===========================================================
   Cross-document page transitions (View Transitions API)
   -----------------------------------------------------------
   Navigations between separate pages cross-fade softly instead of
   hard-cutting white, and the nav bar + logo hold still across the
   load — the site reads as one continuous experience. Pure CSS; the
   at-rule is silently ignored by browsers that don't support it
   (they keep today's instant navigation), and reduced-motion opts out.
   =========================================================== */
@view-transition { navigation: auto; }
.nav        { view-transition-name: eg-nav; }
.nav__brand { view-transition-name: eg-logo; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 0.22s; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding: var(--space-md) clamp(0.75rem, 1.5vw, 1.5rem) 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;     /* logo / pill / donate */
  align-items: center;
  gap: var(--space-md);
  pointer-events: none;
  transition: padding 0.5s var(--ease-out);
}
/* Scrolled bar surface — full-width navy bar that fades in on scroll.
   In non-scrolled state this pseudo is hidden; the pill itself lives
   directly on .nav__inner so it exactly wraps the menu cluster (and
   the green Stories tab welds cleanly to its right edge). */
.nav::before {
  content: '';
  position: absolute;
  pointer-events: none;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(180deg, rgba(26, 46, 74, 0.86) 0%, rgba(15, 29, 48, 0.92) 100%);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 8px 24px -12px rgba(0, 0, 0, 0.40);
  opacity: 0;
  z-index: -1;
  transition: opacity 0.45s var(--ease-out);
}
.nav.scrolled {
  padding: 0.6rem clamp(0.75rem, 1.5vw, 1.5rem);
}
.nav.scrolled::before {
  opacity: 1;
}

.nav__brand {
  pointer-events: auto;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  /* Drop shadow ensures the white logo reads cleanly on photographs */
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.35));
  transition: transform 0.4s var(--ease-out);
}

.nav__inner {
  pointer-events: auto;       /* the menu group is interactive */
  justify-self: center;
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--nav-pad) var(--nav-pad-x);
  position: relative;
  z-index: 1;
  /* Pill surface lives directly on this element so it perfectly wraps
     the menu cluster — green Stories tab welds to the visible right
     edge with zero navy bleed. Scrolled state fades this to transparent
     and the full-width .nav::before bar takes over. */
  background: linear-gradient(180deg, rgba(26, 46, 74, 0.86) 0%, rgba(15, 29, 48, 0.92) 100%);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-radius: 9999px;
  box-shadow: 0 6px 20px -10px rgba(0, 0, 0, 0.35);
  transition:
    padding 0.4s var(--ease-out),
    background 0.45s var(--ease-out),
    border-radius 0.55s var(--ease-out),
    box-shadow 0.45s var(--ease-out);
}
.nav.scrolled .nav__inner {
  padding: var(--nav-pad-scrolled) var(--nav-pad-x-scrolled);
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.nav__logo {
  /* Bumped — logo is outside the pill now and can scale to the page chrome. */
  height: clamp(2.5rem, 2.2rem + 0.6vw, 3rem);
  width: auto;
  object-fit: contain;
  object-position: left center;
  transition: height 0.4s var(--ease-out);
}
.nav.scrolled .nav__logo {
  height: clamp(2rem, 1.8rem + 0.4vw, 2.5rem);
}

.nav__links {
  display: none;
  list-style: none;
  gap: 0.25rem;                /* tight — each link has its own padding */
  align-items: center;
  margin: 0 auto;              /* push to centre, donate button sits on the right */
}

.nav__links a,
.nav__dropdown-link,
.nav__dropdown-trigger {
  color: var(--white);
  font-family: var(--font-family);
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.4rem var(--nav-link-px);
  border-radius: var(--radius-full);
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  transition: color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out);
}
.nav__links a:hover,
.nav__dropdown-link:hover,
.nav__dropdown-trigger:hover,
.nav__dropdown.is-open .nav__dropdown-trigger {
  color: var(--gold-light);
}
.nav__links a[aria-current="page"],
.nav__dropdown-link[aria-current="page"] {
  color: var(--gold);
}

/* Partners "label + chevron" split — link goes to #partners, chevron-only
   button opens the dropdown. Visually they sit as one unit. */
.nav__dropdown-link {
  padding-right: 0;                         /* tight to the chevron beside it */
}
.nav__dropdown-trigger {
  padding-left: 0.15rem;                    /* hairline gap from the label */
  padding-right: var(--nav-link-px);
  position: relative;
}
/* Invisible hit-area extension — keeps the visible chevron compact while
   guaranteeing a 44x44 tap target for touch devices. */
.nav__dropdown-trigger::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 44px);
  height: max(100%, 44px);
}
.nav__chevron {
  transition: transform var(--duration-fast) var(--ease-out);
}
.nav__dropdown.is-open .nav__chevron {
  transform: rotate(180deg);
}

/* Dropdown panel */
.nav__dropdown {
  position: relative;
  /* inline-flex collapses the whitespace between <a>Partners</a> and the
     <button> chevron — without it the rendered space between them was
     ~5px from HTML formatting, which broke the "label + chevron read as
     one unit" intent. */
  display: inline-flex;
  align-items: center;
}
.nav__dropdown-panel {
  position: absolute;
  top: calc(100% + 0.75rem);
  left: 50%;
  transform: translateX(-50%) translateY(-0.5rem);
  min-width: 16rem;
  max-width: calc(100vw - 2rem);            /* prevents clipping at narrow widths */
  list-style: none;
  margin: 0;
  padding: 0.5rem;
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.18), 0 2px 6px rgba(0, 0, 0, 0.08);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
  z-index: 110;
}
.nav__dropdown.is-open .nav__dropdown-panel {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.nav__dropdown-panel li + li {
  margin-top: 0.1rem;
}
.nav__dropdown-panel a {
  display: block;
  padding: 0.6rem 0.9rem;
  color: var(--navy);
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: var(--radius-md);
  background: transparent;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.nav__dropdown-panel a:hover {
  background: var(--cream-dark);
  color: var(--navy-dark);
}
.nav__dropdown-panel a[aria-current="page"] {
  color: var(--green);
}

/* Donate button in the nav: layout only — colours come from .btn--gold
   (gold bg, navy-dark text). Lives nested in the right corner of the pill
   with extra right-margin to optically balance the pill's rounded edge. */
.nav__donate {
  display: none;
  pointer-events: auto;
  justify-self: end;
  /* Soft cast shadow so the gold button has presence against any backdrop */
  box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.35);
}
.nav__donate.btn {
  /* Vertical padding tuned so the donate button matches the pill's natural
     height: 0.95em on font-xs at line-height:1 reaches the same total as
     the pill's nav-pad + link line-height:1.5 stack. */
  padding: 0.95em 1.5em;
  font-size: var(--font-xs);
  letter-spacing: 0.08em;
  /* Keep "Donate Now" on a single line at every viewport — the right grid
     column will grow to fit (min-content floor on the 1fr track) rather
     than wrapping the button text onto two lines. */
  white-space: nowrap;
}

/* ====== Project-page nav theme ============================
   Brand green pill on project pages — the white logo reads cleanly,
   the gold Donate button still pops, and the green carries the
   "you're in the partner section" signal. */
/* Project pages — paint the pill (and the scrolled bar) green instead of navy. */
.page-project .nav__inner,
.page-project .nav::before {
  background: var(--green);
}
.page-project .nav__links a {
  color: var(--white);
}
.page-project .nav__links a:hover:not([aria-current="page"]) {
  color: var(--gold-light);
}
.page-project .nav__links a[aria-current="page"] {
  color: var(--gold);
}
.page-project .nav__hamburger span {
  background: var(--white);
}

/* Donate button stays gold/yellow everywhere — the URL bar + hero content
   already signal "you are here" on the donate page; no need to flip the
   button colour and lose the CTA pattern consistency across the site. */


/* ===========================================================
   Stories tab — green CTA welded to the right end of the pill.
   The pill's own padding is negated on three sides so the tab
   bleeds top + right + bottom out to the pill's rounded edge,
   inheriting that rounding on its right corners. Reads as a
   tab appended to the nav, not a button floating inside it —
   the signal that Stories leaves the SPA into its own page.
   =========================================================== */
.nav__links li:has(> .nav__stories) {
  display: flex;
  align-self: stretch;
  /* Keep the default .nav__links gap AND the previous item's full
     right padding intact — total ~1.1rem of navy breathing room
     between SUBSCRIBE's letterform and the white Stories tab. */
  margin-left: 0;
}
.nav__stories {
  margin: calc(var(--nav-pad) * -1)
          calc(var(--nav-pad-x) * -1)
          calc(var(--nav-pad) * -1)
          0;
  /* Left padding compensates for the negative margin on the parent <li>
     so the "Stories" label keeps comfortable breathing room from where
     Subscribe's text ends. Right padding accounts for the right margin
     bleed so the label isn't pinched against the pill's curved edge. */
  padding: 0 calc(var(--nav-pad-x) + 0.4rem) 0 calc(var(--nav-link-px) + 1.1rem) !important;
  background: var(--white) !important;
  color: var(--green) !important;
  font-weight: 800 !important;
  border-radius: 0 9999px 9999px 0;
  display: inline-flex;
  align-items: center;
  align-self: stretch;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    padding 0.4s var(--ease-out),
    margin 0.4s var(--ease-out),
    border-radius 0.55s var(--ease-out);
}
.nav__stories:hover {
  background: var(--cream) !important;
  color: var(--green) !important;
}
/* The label is its own inline-block so it can grow on hover without
   dragging the surrounding pill geometry with it — restrained scale
   on a tight ease, no spring overshoot. Editorial, not bouncy. */
.nav__stories-label {
  display: inline-block;
  transform-origin: center;
  transition: transform 0.35s var(--ease-out);
}
.nav__stories:hover .nav__stories-label,
.nav__stories:focus-visible .nav__stories-label {
  transform: scale(1.06);
}
@media (prefers-reduced-motion: reduce) {
  .nav__stories-label,
  .nav__stories:hover .nav__stories-label {
    transition: none;
    transform: none;
  }
}
/* Scrolled state — the navy pill bg fades into a full-width bar, so
   the Stories tab releases from the pill edge and becomes a fully-
   rounded standalone pill floating in the navy bar. */
.nav.scrolled .nav__links li:has(> .nav__stories) {
  align-self: center;
  margin-left: 0.5rem;
}
.nav.scrolled .nav__stories {
  margin: 0;
  padding: 0.5rem 1.1rem !important;
  border-radius: 9999px;
}


/* ===========================================================
   Stories-page theme — single class convention, token-driven.
   .page-stories flips the navy palette tokens to a forest set
   at body scope. Every surface that consumes --navy / --navy-
   dark / --navy-light / --bg-dark (footer, .section--dark,
   .section--spotlight, .page-hero gradient, headings, nav__
   mobile, story-card titles…) retints automatically — no
   per-surface override required. Surfaces that paint with
   literal RGBA values (the nav pill and the spotlight radial)
   are the only declared exceptions below.
   =========================================================== */
.page-stories {
  --navy-dark:  #0f2a15;
  --navy:       #1f4720;
  --navy-light: #2d5a2e;
  --bg-dark:    #0f2a15;
}

/* Nav pill + scrolled bar — both painted with literal RGBA gradients
   (not tokens), so they need an explicit forest-gradient override. */
.page-stories .nav__inner,
.page-stories .nav::before {
  background: linear-gradient(
    180deg,
    rgba(45, 90, 46, 0.92) 0%,
    rgba(15, 42, 21, 0.96) 100%
  );
}
.page-stories .nav.scrolled .nav__inner {
  background: transparent;
}
.page-stories .nav.scrolled::before {
  background: linear-gradient(
    180deg,
    rgba(45, 90, 46, 0.94) 0%,
    rgba(15, 42, 21, 0.98) 100%
  );
}

/* Stories tab inverts on the stories page — cream stamp on the forest
   pill signals "you are here," same convention as aria-current. */
.page-stories .nav__stories,
.page-stories .nav__stories:hover {
  background: var(--cream) !important;
  color: var(--green) !important;
}

/* Spotlight closer keeps its custom radial pool but in green/gold. */
.page-stories .section--spotlight::before {
  background:
    radial-gradient(ellipse 70% 50% at 50% 60%, rgba(232, 184, 75, 0.18) 0%, transparent 65%),
    radial-gradient(ellipse 90% 60% at 50% 60%, rgba(74, 154, 75, 0.55) 0%, transparent 70%);
}

/* Eyebrow pills on the stories page wear brand gold — reads as the
   "feature/editorial" tag against the forest sections. */
.page-stories .eyebrow,
.page-stories .section--dark .eyebrow,
.page-stories .page-hero .eyebrow {
  color: var(--gold);
  border-color: var(--gold);
}


.nav__hamburger {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.75rem;
  min-width: 44px;
  min-height: 44px;
}

.nav__hamburger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--white);
  transition: all var(--duration-fast) var(--ease-out);
  transform-origin: center;
}

.nav__hamburger.open span:nth-child(1) {
  transform: rotate(45deg) translate(5px, 5px);
}
.nav__hamburger.open span:nth-child(2) {
  opacity: 0;
}
.nav__hamburger.open span:nth-child(3) {
  transform: rotate(-45deg) translate(5px, -5px);
}

/* Mobile nav overlay — z-index above .nav (100) so the pill doesn't peek
   through. overscroll-behavior locks background scroll on touch devices. */
.nav__mobile {
  position: fixed;
  inset: 0;
  background: var(--navy-dark);
  z-index: 101;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;          /* anchor top, scroll if needed */
  gap: 0.25rem;                          /* tight — typography carries the rhythm */
  padding: 5rem 1rem 3rem;               /* clear of the nav, room at bottom */
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-out);
  overscroll-behavior: contain;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.nav__mobile.open {
  opacity: 1;
  pointer-events: auto;
}

.nav__mobile a {
  color: var(--white);
  font-size: var(--font-base);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.55rem 1rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.nav__mobile a:hover {
  color: var(--gold);
}

.nav__mobile-section {
  color: var(--gold-light);
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin: 0.75rem 0 0.25rem;            /* tighter section header rhythm */
}
.nav__mobile a[aria-current="page"] {
  color: var(--gold);
}

@media (min-width: 1200px) {
  .nav__links { display: flex; }
  .nav__donate { display: inline-flex; }
  .nav__hamburger { display: none; }
}

/* Below 1200px the 8-item nav can't fit inside the pill without items
   spilling past the rounded edges, so collapse to the hamburger menu.
   The centred pill is hidden and the grid reflows: logo left, hamburger
   right. The hamburger floats free against the photo with a soft drop
   shadow to stay legible on busy backdrops.

   On scroll, the full-width bar emerges (navy by default, green on
   .page-project) to keep the logo + hamburger crisp as photography
   passes underneath. */
@media (max-width: 1199.98px) {
  .nav {
    grid-template-columns: auto 1fr auto;
  }
  .nav::before {
    display: none;                            /* hidden at top of page */
  }
  .nav.scrolled::before {
    display: block;                           /* full-width bar on scroll */
  }
  .nav__inner {
    justify-self: end;
    padding: 0;
    background: transparent;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .nav__hamburger {
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.45));
  }
  .nav.scrolled .nav__hamburger {
    filter: none;                             /* the bar gives it contrast now */
  }
}


/* --- Hero ------------------------------------------------ */
.hero {
  position: relative;
  height: 100svh;
  overflow: hidden;
}

.hero__bg {
  /* Fixed to the viewport so the slideshow stays in place while content
     scrolls over it — readers who want to peek at the photo can scroll
     the text out of the way. z-index:-1 keeps it behind the in-flow
     content but covered by every subsequent section's background.
     Navy fallback prevents a flash of cream body bg before slide 1
     decodes (now that the intro splash gate is gone). */
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background-color: var(--navy-dark);
}
/* Shallow depth-of-field vignette — backdrop-filter blurs everything
   behind this overlay, then a radial mask makes the centre transparent
   (= no blur visible there) and the edges opaque (= blur shows). The
   slideshow stays sharp where the eye lands and softens at the corners,
   giving the hero a cinematic, lens-like feel. */
.hero__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  -webkit-mask-image: radial-gradient(ellipse 65% 75% at 50% 45%, transparent 30%, black 90%);
          mask-image: radial-gradient(ellipse 65% 75% at 50% 45%, transparent 30%, black 90%);
}

/* Hero slideshow — slides are absolutely stacked, fading in/out via
   opacity only. No transform animation, no movement of the photograph
   itself. Each slide is a still photograph that crossfades cleanly into
   the next. */
.hero__slideshow .hero__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;               /* bias toward upper-mid where faces sit */
  opacity: 0;
  transition: opacity 1.8s ease-in-out;
  will-change: opacity;
  /* Editorial colour grade — slight contrast bump + subtle desaturation
     so every photo in the rotation lands in the same tonal range and
     pops cleanly against the vignette. */
  filter: contrast(1.06) saturate(0.92) brightness(0.98);
}

/* Per-slide object-position overrides — biases the crop on slides whose
   subject isn't at the default centre-upper. Slide 1 (kids with hands
   up) needs to favour the LEFT so the foreground children are framed. */
.hero__slideshow .hero__slide:nth-child(1) { object-position: 30% 40%; }
.hero__slideshow .hero__slide.is-active {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .hero__slideshow .hero__slide {
    transition: opacity 0.3s linear;
  }
}

/* Ken Burns — a slow cinematic push-in on whichever slide is showing, so
   the hero breathes instead of sitting flat. These keyframes are applied
   PER SLIDE by JS (initHeroSlideshow) with a duration synced to the slide
   cycle and `forwards` fill, so each photo pushes in for exactly its time
   on screen: the motion never freezes mid-slide and the outgoing slide
   keeps its zoom through the crossfade (no snap-back). Time-based, never
   scroll-based — the old scroll-driven hero zoom was removed for the
   "growing slide 1" + iOS address-bar jitter, none of which applies here.
   Linear so the push-in is constant-speed, not easing to a stop. Both
   values >=1 so object-fit: cover never exposes an edge. JS only applies it
   on desktop with motion allowed; mobile + reduced-motion stay static. */
@keyframes hero-kenburns {
  from { transform: scale(1); }
  to   { transform: scale(1.12); }
}

/* Cinematic vignette + subtle bottom darkening for title legibility.
   The heavy navy haze that used to live here muddied bright photos; this
   replaces it with a pure dark vignette (edges, no colour cast) plus a
   light bottom gradient that's just enough to let the title's combo
   shadow do its work. */
.hero__overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    /* Bottom-only darkening for title — light, no blue cast */
    linear-gradient(180deg, transparent 55%, rgba(0, 0, 0, 0.50) 100%),
    /* Vignette: bright in centre-upper, darker toward edges/corners */
    radial-gradient(ellipse 90% 75% at 50% 40%, transparent 45%, rgba(0, 0, 0, 0.55) 100%);
}

.hero__content {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  padding: var(--space-2xl) var(--space-md) var(--space-3xl);
  text-align: center;
  will-change: transform, opacity;
}

/* Hero eyebrow — solid white pill with green text, same treatment as
   .page-hero--has-photo .eyebrow so it reads cleanly over the slideshow.
   Sits above the title with tight spacing. */
.hero__eyebrow {
  display: inline-block;
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--green);
  background: var(--white);
  padding: 0.45em 1.35em;
  border-radius: var(--radius-full);
  margin: 0 0 var(--space-md);
}

.hero__title {
  font-size: var(--font-display);
  color: var(--white);
  margin: 0 auto var(--space-lg);
  max-width: 22ch;                          /* hold the 2-line composition together */
  letter-spacing: -0.03em;
  line-height: 1.05;
  text-shadow: var(--shadow-text);
}

.hero__subtitle {
  font-size: clamp(0.9rem, 0.82rem + 0.3vw, 1.05rem);
  font-weight: 500;
  color: var(--white);                    /* white text on the brand-green plate */
  max-width: 44rem;
  margin: 0 auto var(--space-xl);
  line-height: 1.55;
  padding: 0.7rem 1.4rem;
  /* Brand-green plate — translucent so the slideshow still shows
     through subtly; backdrop blur softens the photo so the white type
     reads cleanly on top. */
  background: rgba(61, 122, 62, 0.92);    /* --green at 92% — dense enough for white text */
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  border-radius: var(--radius-lg);
  text-shadow: none;
}

.hero__actions {
  display: flex;
  gap: var(--space-md);
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--space-lg);
}

.hero__scroll-hint {
  position: absolute;
  bottom: var(--space-md);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  animation: gentle-float 3s ease-in-out infinite;
}

.hero__scroll-hint svg {
  width: 28px;
  height: 28px;
  color: rgba(255, 255, 255, 0.6);
}

@keyframes gentle-float {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(10px); }
}


/* --- Pillars (How We Work) -------------------------------
   Three cards, three rows: icon · title · text.
   Using grid (not flex centering) so each row sits at the same vertical
   position across all three cards regardless of content length. Icons
   anchor top, titles reserve space for two lines, paragraphs fill the
   remainder — so first lines of body copy align across the row. */
.pillar-card {
  background: var(--white);
  border-radius: var(--radius-xl);
  padding: var(--space-xl) var(--space-md);
  text-align: center;
  border: 1px solid var(--sand);
  border-top: 5px solid var(--sand);
  transition: transform var(--duration) var(--ease-out), box-shadow var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
  /* Grid keeps row positions consistent across cards. Per-row margins (not
     grid gap) so the icon→title gap can be tight while title→text stays
     generous. */
  display: grid;
  grid-template-rows: auto auto 1fr;        /* icon | title (with min-height) | text */
  gap: 0;
  justify-items: center;
}

.pillar-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--gold);
  border-top-color: var(--gold);
}

.pillar-card__icon {
  /* Larger, fixed dimensions — never scales with content. */
  width: clamp(4.5rem, 3.75rem + 2vw, 6rem);
  height: clamp(4.5rem, 3.75rem + 2vw, 6rem);
  margin: 0 0 var(--space-xs);              /* tight to the title below */
  object-fit: contain;
}

/* Title reserves room for two lines so first line of body copy aligns across
   all three cards regardless of how the title wraps. Anchored to the TOP of
   its reserved space (flex-start) so 1-line titles sit close to the icon
   instead of floating in the middle. */
.pillar-card .pillar-card__title {
  color: var(--navy);
  font-size: var(--font-lg);
  line-height: 1.25;
  min-height: 2.5em;                       /* 2 lines @ 1.25 line-height */
  margin: 0 0 var(--space-md);             /* breathing room before body */
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.pillar-card .pillar-card__text {
  font-size: var(--font-sm);
  color: var(--text-secondary);
  line-height: 1.6;
  margin: 0;
}


/* --- Story Section (Our Story) --------------------------- */
/* --- Our Story: full-bleed editorial split -----------------
   Same pattern as the partner project hero (.project-hero) — image
   fills the left half edge-to-edge, content fills the right half on a
   solid cream backdrop. No container, no rounded corners, no overlap.

   Mobile (<768px): stacks vertically — photo on top, content below. */
.story-hero {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100svh;
  background: var(--cream);
  overflow: hidden;
  scroll-margin-top: 0;  /* land section top at the viewport top — see initSmoothScroll */
  /* The section sits mid-page; the previous section's bottom padding gives
     the photo all the room it needs above. No extra padding-top required. */
}
@media (min-width: 768px) {
  .story-hero {
    grid-template-columns: 1fr 1fr;          /* equal halves */
  }
}

.story-hero__photo {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--cream-dark);
}
.story-hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (min-width: 768px) {
  .story-hero__photo {
    aspect-ratio: auto;
    height: 100%;
  }
}

/* Cinematic scroll treatment — gives the "Two Decades of Partnership"
   section gravity. The photo is held slightly overscaled and JS drifts it
   vertically as the section travels through the viewport (see
   initStoryParallax in main.js). Transform-only + rAF + IntersectionObserver
   so it stays on the compositor and never thrashes layout — not the
   background-attachment/unthrottled approach that jittered before. The
   resting >1 scale keeps the image larger than its frame so the drift can
   never expose an edge. JS only touches it when motion is allowed, so under
   prefers-reduced-motion (and with JS off) the image is a clean static
   cover at scale 1. */
.story-hero__photo img {
  transform-origin: center;
}

.story-hero__content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--space-xl) var(--space-lg);
}
@media (min-width: 768px) {
  .story-hero__content {
    /* Asymmetric block padding. The section lands with its top at the
       viewport top and the translucent nav floats over it, so the content
       column needs a generous TOP pad to keep the "Our Story" eyebrow clear
       of the nav — this is the tallest section's content (two paragraphs),
       so when it centres on a laptop-height screen it would otherwise ride
       up under the bar. Bottom keeps a comfortable, smaller pad. Inline
       padding is asymmetric: generous on the left to separate copy from the
       photo, moderate on the right. */
    padding-top: clamp(6rem, 9svh + 2rem, 8.5rem);
    padding-bottom: clamp(2.5rem, 5svh, 5rem);
    padding-left: clamp(2.25rem, 4vw, 4rem);
    padding-right: clamp(1.5rem, 2.5vw, 2.5rem);
  }
}
.story-hero__inner {
  max-width: 32rem;
  margin: 0 auto;
}
@media (min-width: 768px) {
  .story-hero__inner {
    /* Anchor copy to the left of the content column AND allow it to
       breathe wider (36rem) so the long paragraphs read in cleaner
       lines rather than crowded by the right edge of the column. */
    margin: 0 auto 0 0;
    max-width: 36rem;
  }
}

.story-hero__content .eyebrow {
  color: var(--green);
  font-size: var(--font-xs);
  margin-bottom: var(--space-md);
}
.story-hero__content h2 {
  font-size: clamp(2.25rem, 1.6rem + 2.5vw, 3.75rem);
  letter-spacing: -0.025em;
  line-height: 1.05;
  margin-bottom: var(--space-md);
}
.story-hero__content p {
  color: var(--text-primary);
  font-size: var(--font-base);
  line-height: 1.7;
  margin-bottom: var(--space-md);
}

/* --- Impact Stats ---------------------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-xl);
  text-align: center;
}

.stat__number {
  font-size: var(--font-3xl);
  font-weight: 800;
  color: var(--gold);
  line-height: 1;
  margin-bottom: var(--space-xs);
}

.section--dark .stat__number {
  color: var(--gold-light);
}

.stat__label {
  font-size: var(--font-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-secondary);
}

.section--dark .stat__label {
  color: rgba(250, 248, 244, 0.8);
}


/* --- Impact Areas ---------------------------------------- */
.impact-area {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-lg);
  padding: var(--space-lg) 0 var(--space-xl);
}

@media (min-width: 768px) {
  .impact-area {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

.impact-area__col {
  padding: var(--space-lg);
  border-radius: var(--radius-lg);
  background: var(--cream-dark);
  border-top: 5px solid var(--sand);
}

.impact-area__col:nth-child(1) { border-top-color: var(--red); }
.impact-area__col:nth-child(2) { border-top-color: var(--green); }
.impact-area__col:nth-child(3) { border-top-color: var(--gold); }

.impact-area__label {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: var(--font-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: var(--space-sm);
}

.impact-area__label--issue   { color: var(--red); }
.impact-area__label--vision  { color: var(--green); }
.impact-area__label--success { color: var(--gold-dark); }

/* When the Focus section sits on navy (.section--dark), the three sub-cards
   (Issue/Vision/Success) sit directly on the navy backdrop — their cream-dark
   panels carry the contrast on their own, no outer wrapping card needed. The
   `p` inside the panels still needs the light-bg colour since the panels are
   cream, not navy. */
.section--dark .impact-area p {
  color: var(--text-primary);
}

/* Subtle visual distinction from the Impact section above — a faint radial
   spotlight bleeds from the centre to give Focus its own zone while staying
   inside the navy band. Pure CSS, no SVG asset needed. */
.section--focus {
  background-image:
    radial-gradient(ellipse 80% 50% at 50% 35%, rgba(42, 68, 104, 0.55) 0%, transparent 70%);
  background-color: var(--navy-dark);
  overflow: hidden;                          /* keeps the slide track contained */
}

/* --- Premium grain overlay ------------------------------------------
   Sandblasted noise texture lifted from the Google Marketing Live
   visual language. Implemented as a SINGLE viewport-fixed layer on
   body::after so the noise pattern has one origin and zero seams
   between sections. Per-section grain pseudos caused visible "tear"
   bands at every boundary because each pseudo had its own noise
   origin starting at (0,0) — patterns didn't tile across sections.

   The SVG generator <filter id="premium-grain"> is inlined at the top
   of every HTML body. Mix-blend-mode binds the grain into whatever's
   underneath without graying out the colours. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 99;                               /* under the nav (z:100) */
  filter: url(#premium-grain);
  mix-blend-mode: overlay;
  opacity: 0.15;                             /* low — grain on EVERYTHING */
}
/* Opt-in per-element grain stays available as a utility, but the
   page-wide layer above usually does the job. */
.has-grain {
  position: relative;
  isolation: isolate;
}
.has-grain::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  filter: url(#premium-grain);
  mix-blend-mode: overlay;
  opacity: 0.25;
  z-index: 0;
  border-radius: inherit;
}


/* Stage lighting for any dark CTA / closer — a brighter, more focused
   centre pool than .section--focus so the headline reads as a moment.
   Combine with .section--dark.

   The radial pool lives on a ::before pseudo that extends 10rem ABOVE
   the section's top edge, so the gradient bleeds gently into whatever
   navy section sits above (no visible seam where the lit area starts).
   Container content gets z-index:1 so it paints over the pseudo. */
.section--spotlight {
  background-color: var(--navy-dark);
  position: relative;
  overflow: visible;
}
.section--spotlight::before {
  content: '';
  position: absolute;
  inset: -10rem 0 0 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(ellipse 70% 50% at 50% 60%, rgba(61, 122, 62, 0.18) 0%, transparent 65%),
    radial-gradient(ellipse 90% 60% at 50% 60%, rgba(54, 86, 130, 0.55) 0%, transparent 70%);
}
.section--spotlight > * {
  position: relative;
  z-index: 1;
}

/* --- Focus tabs --------------------------------------------
   Tab strip lives directly under the section header — three category
   labels (Education / Health / Youth) act as both nav and content header.
   Selected tab is gold with an underline; siblings are muted cream.
   The panels below fade-swap in place. */
.focus-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1rem, 0.5rem + 2vw, 2.5rem);
  margin-top: 0;                            /* the .section--full header below already pads */
  margin-bottom: var(--space-md);
  border-bottom: 1px solid rgba(250, 248, 244, 0.08);
  padding-bottom: 0.1rem;
}
/* Inside a full-viewport stage the header takes less bottom margin so the
   tab strip + panel can occupy the centre comfortably. */
.section--focus.section--full .section-header {
  margin-bottom: var(--space-lg);
}

/* Hard-cap the Focus section at 100svh on tablet+ — the boxes inside adjust
   to fit, the navy backdrop stays a stable single-viewport stage no matter
   which tab is active. Mobile keeps the min-height fallback so cards can
   stack naturally without crushing text. */
@media (min-width: 768px) {
  .section--focus.section--full {
    height: 100svh;
    min-height: 0;
  }
  /* Inside the Focus stage, the panel area uses a smaller card padding so
     text fits comfortably on shorter laptops without overflow. */
  .section--focus .impact-area__col {
    padding: var(--space-md) var(--space-lg);
  }
  .section--focus .impact-area p {
    font-size: var(--font-sm);
    line-height: 1.55;
  }
}
.focus-tab {
  appearance: none;
  background: transparent;
  border: none;
  font-family: inherit;
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.35rem);
  font-weight: 700;
  letter-spacing: -0.005em;
  color: rgba(250, 248, 244, 0.45);
  padding: 0.75em 0.5em 0.85em;             /* 44px+ tap target on mobile */
  min-height: 2.75rem;
  cursor: pointer;
  position: relative;
  transition: color 0.3s var(--ease-out);
}
@media (min-width: 640px) {
  .focus-tab {
    padding: 0.5em 0.25em 0.7em;
    min-height: 0;
  }
}
.focus-tab:hover { color: rgba(250, 248, 244, 0.85); }
.focus-tab[aria-selected="true"] {
  color: var(--gold);
}
/* On mobile, drop the second word from "Health & Nutrition" and "Youth
   Development" so all three tabs fit one line each — the panel content
   below carries the full label. */
@media (max-width: 640px) {
  .focus-tab__rest { display: none; }
}
.focus-tab::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%) scaleX(0);
  transform-origin: center;
  width: 70%;
  height: 2px;
  background: var(--gold);
  border-radius: 2px;
  transition: transform 0.35s var(--ease-out);
}
.focus-tab[aria-selected="true"]::after {
  transform: translateX(-50%) scaleX(1);
}

/* All three panels share one grid cell so the container always sizes to
   the tallest panel — switching tabs swaps the visible panel WITHOUT
   resizing the section (no jumpy 100svh background).

   Motion sequence is JS-coordinated through three explicit states:
   - `.is-leaving`   — outgoing panel: opacity 1 → 0, translateY(0) → 20px
                       (settles downward as it fades out)
   - `.is-entering`  — incoming panel: instantly positioned at translateY(-20px)
                       opacity 0, visibility visible. No transition — this is
                       the start frame.
   - `.is-active`    — final state: opacity 1, translateY(0). Transition fires
                       FROM the entering frame, so the panel slides IN FROM
                       ABOVE while fading in.
   Both halves move in the same downward direction → reads as content passing
   gracefully through, not two ghosts overlapping. */
.focus-panels {
  display: grid;
}
.focus-panel {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(0);
}
/* Easing — Apple-style strong deceleration: quick start, long settle.
   Matches the curve used in iOS sheet/navigation transitions. */
.focus-panel.is-leaving {
  visibility: visible;
  opacity: 0;
  transform: translateY(24px) scale(0.985);
  transition:
    opacity 0.7s cubic-bezier(0.32, 0.72, 0, 1),
    transform 0.85s cubic-bezier(0.32, 0.72, 0, 1);
}
.focus-panel.is-entering {
  visibility: visible;
  opacity: 0;
  transform: translateY(-24px) scale(0.985);
  transition: none;                          /* this IS the start frame */
}
.focus-panel.is-active {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0) scale(1);
  transition:
    opacity 0.85s cubic-bezier(0.32, 0.72, 0, 1),
    transform 1s cubic-bezier(0.32, 0.72, 0, 1);
}
.focus-panel .impact-area { padding: 0; margin: 0; }   /* tighter to the tab strip */

/* Stagger the three sub-cards inside an active panel so each one enters
   a beat behind the last — without this, switching tabs reads as nothing
   changed (all three cards arrive simultaneously and look similar). */
.focus-panel .impact-area__col {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 0.55s cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 0.65s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.focus-panel.is-active .impact-area__col {
  opacity: 1;
  transform: translateY(0);
}
.focus-panel.is-active .impact-area__col:nth-child(1) { transition-delay: 0.05s; }
.focus-panel.is-active .impact-area__col:nth-child(2) { transition-delay: 0.13s; }
.focus-panel.is-active .impact-area__col:nth-child(3) { transition-delay: 0.21s; }

@media (prefers-reduced-motion: reduce) {
  .focus-panel,
  .focus-panel.is-leaving,
  .focus-panel.is-entering,
  .focus-panel.is-active {
    transition: opacity 0.2s linear;
    transform: none;
  }
  .focus-panel .impact-area__col {
    transition: opacity 0.2s linear;
    transform: none;
  }
  .focus-panel.is-active .impact-area__col:nth-child(1),
  .focus-panel.is-active .impact-area__col:nth-child(2),
  .focus-panel.is-active .impact-area__col:nth-child(3) {
    transition-delay: 0s;
  }
}


/* ====== Partners carousel — horizontal 2-col cards =========
   Mobile: card stacks vertically (photo top, text bottom).
   ≥640px: card is a 5:2 rectangle = square photo on the left,
   wider text panel on the right. Card centred when scrolled into view;
   neighbours peek dimmed at the edges as a scroll cue.
   ============================================================ */
.partner-carousel-wrap {
  position: relative;
  /* Full-bleed: pull out of the container so the carousel spans the
     viewport edge-to-edge. Cards now enter from / exit to the actual
     screen edges, not the container's padding line. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}
.partner-grid {
  display: flex;
  gap: var(--space-lg);
  overflow-x: auto;
  overflow-y: hidden;
  /* mandatory + scroll-snap-stop:always on each card forces the carousel
     to settle on exactly one card per swipe/flick — same behaviour as
     swipe-card apps (Tinder, Hinge). A hard flick can't skip past
     multiple cards. */
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-block: var(--space-lg);
  /* Small inline padding only — infinite-scroll clones ensure cards are
     always present on either side, so we don't need the big centering
     padding that used to leave dead space at the edges. */
  padding-inline: var(--space-md);
}
.partner-grid::-webkit-scrollbar { display: none; }
.partner-grid:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 4px;
  border-radius: var(--radius-md);
}

/* Carousel scroll indicator dots — tight under the cards so the section
   fits below the nav pill without dots being clipped on shorter viewports */
.carousel-dots {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: var(--space-sm);
}

/* Partners section: minimal vertical padding on DESKTOP so the wide
   carousel + dots both fit in viewport after navigation. On mobile the
   carousel doesn't compete for vertical space, so the mobile breakpoint
   rule earlier in the file gives this section a generous padding-block
   instead. Scoping to min-width:641px keeps this from clobbering the
   mobile rule via cascade order. */
@media (min-width: 641px) {
  #partners.section {
    padding-block: var(--space-lg);
  }
}

.carousel-dots button {
  /* Visible dot stays small via box-shadow inset technique: actual element
     is 44x44 for touch, but the painted dot is 0.5rem via background-clip. */
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.3);
  background-clip: content-box;
  padding: calc((44px - 0.5rem) / 2);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out);
}

.carousel-dots button.active {
  /* Active dot stretches to a pill via inner padding; outer tap area
     stays 44x44 so touch targets remain consistent. */
  background: var(--gold);
  padding-inline: calc((44px - 1.5rem) / 2);
}

/* Scroll hint text — mobile-only, AA contrast */
.carousel-hint {
  display: none;
  text-align: center;
  margin-top: var(--space-sm);
  font-size: var(--font-xs);
  color: rgba(250, 248, 244, 0.75);
  letter-spacing: 0.05em;
}
@media (max-width: 640px) {
  .carousel-hint { display: block; }
}

/* Card shell — mobile-first stacked, becomes 2-col on ≥640px.
   Side cards (off-centre): photo gets a navy haze + desaturated; text
   panel stays legible but dim. Active card: haze fades away, full colour. */
.partner-card {
  position: relative;
  flex: 0 0 clamp(20rem, 85vw, 22rem);
  scroll-snap-align: center;
  scroll-snap-stop: always;          /* one card per flick — no multi-skip */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto auto;
  background: var(--white);
  border-radius: var(--radius-lg);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);

  filter: saturate(0.45);
  transform: scale(0.97);
  transition:
    filter 0.6s var(--ease-out),
    transform 0.6s var(--ease-out),
    box-shadow 0.6s var(--ease-out);
}
.partner-card.is-active {
  filter: saturate(1);
  transform: scale(1);
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.32);
}
/* No hover-brightens — only the centred card is fully exposed.
   Hover keeps the dimmed state and just hints the link cursor. */

/* During a silent infinite-scroll wrap (.is-wrapping on grid for ~1 frame),
   kill transitions so the atomic is-active class transfer between identical
   cards in adjacent sets is invisible — no overlay fade flash. */
.partner-grid.is-wrapping .partner-card,
.partner-grid.is-wrapping .partner-card::after,
.partner-grid.is-wrapping .partner-card__photo img {
  transition: none !important;
}

@media (min-width: 640px) {
  .partner-card {
    flex: 0 0 clamp(28rem, 60vw, 38rem);
    grid-template-columns: 1fr 1fr;       /* TWO EQUAL SQUARES */
    grid-template-rows: 1fr;
    aspect-ratio: 2 / 1;                  /* image-square + text-square */
  }
}
@media (min-width: 960px) {
  .partner-card {
    flex: 0 0 clamp(32rem, 50vw, 48rem);
  }
}

/* Photo column — navy haze overlay when off-centre */
.partner-card__photo {
  position: relative;
  overflow: hidden;
  background: var(--cream-dark);
  aspect-ratio: 4 / 3;   /* mobile crop */
}
@media (min-width: 640px) {
  .partner-card__photo {
    aspect-ratio: auto;
    height: 100%;
  }
}
.partner-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1s var(--ease-out);
}
.partner-card.is-active .partner-card__photo img {
  transform: scale(1.03);
}
/* Whole-card navy haze on inactive cards.
   Covers photo + text panel so off-centre cards are only barely
   recognisable as cards. Fades to 0 when .is-active. */
.partner-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(26, 46, 74, 0.82) 0%,
    rgba(15, 29, 48, 0.88) 100%
  );
  pointer-events: none;
  transition: opacity 0.6s var(--ease-out);
  opacity: 1;
  border-radius: inherit;
  z-index: 2;
}
.partner-card.is-active::after {
  opacity: 0;
}

/* Text column */
.partner-card__text {
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.6em;
}
@media (min-width: 640px) {
  .partner-card__text {
    padding: var(--space-lg) var(--space-xl);
  }
}

.partner-card__served {
  margin: 0;
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-dark);
}

/* Specificity bump: `.section--dark h4` (0,1,1) globally forces white;
   `.partner-card .partner-card__name` (0,2,0) wins because the partner
   cards are white-on-dark and the title must stay navy. */
.partner-card .partner-card__name {
  margin: 0;
  color: var(--navy);
  font-size: clamp(1.8rem, 1.2rem + 1.6vw, 2.6rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.partner-card__focus {
  margin: 0;
  font-size: var(--font-sm);
  color: var(--text-secondary);
  line-height: 1.5;
}

.partner-card__cta {
  margin-top: 0.4em;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--green);
}
.partner-card.is-active .partner-card__cta {
  color: var(--gold-dark);
}

/* Scroll hint — soft fade on both edges */
.partner-carousel-wrap {
  position: relative;
  overflow: hidden;
}

/* Carousel arrows — hug the centred card with a small gap.
   Card half-width = half of clamp(32rem, 50vw, 48rem) = clamp(16rem, 25vw, 24rem).
   Plus ~1.25rem gap between card edge and arrow centre. */
.carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  border: 2px solid var(--gold);
  background: var(--navy-dark);
  color: var(--gold);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    transform var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    opacity 0.7s var(--ease-out);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  padding: 0;
}
/* Sit each arrow's centre on the EDGE of the adjacent (dimmed) card —
   half on the card, half in the gap. Card half-width = clamp(16rem, 25vw, 24rem).
   Gap between cards = var(--space-lg). Distance from viewport centre to
   the inner edge of a side card = half_card_width + gap. */
.carousel-arrow--prev {
  left: calc(50% - clamp(16rem, 25vw, 24rem) - var(--space-lg));
  transform: translate(-50%, -50%);
}
.carousel-arrow--next {
  left: calc(50% + clamp(16rem, 25vw, 24rem) + var(--space-lg));
  transform: translate(-50%, -50%);
}

.carousel-arrow:hover {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--navy-dark);
  transform: translate(-50%, -50%) scale(1.08);
}

.carousel-arrow:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 4px;
}

.carousel-arrow:active {
  transform: translate(-50%, -50%) scale(0.95);
}

/* At carousel boundaries, the arrow gently fades out — there's no
   card on that side, so the navigation cue should be absent. */
.carousel-arrow[disabled] {
  opacity: 0;
  pointer-events: none;
  cursor: default;
}

@media (max-width: 640px) {
  .carousel-arrow { display: none; }
}

/* Edge gradient fades removed — cards run off-page naturally */



/* --- Board Members --------------------------------------- */
/* Board grid: airy, composed, photographs lead.
   Max-width keeps the 8-person grid from sprawling on wide screens.
   Photos are circular (warm for people-shots), borders are subtle, hover
   lifts gently with a gold ring + soft cast shadow. */
.board-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-xl) var(--space-lg);
  max-width: 64rem;
  margin-inline: auto;
}
@media (min-width: 640px) {
  .board-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 960px) {
  /* Two-row composition for the 9-member board: centred flex-wrap lays
     out 5 over 4 with the short row automatically centred — a deliberate
     stagger instead of a grid stranding an orphan on its own row. */
  .board-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-xl) var(--space-lg);
  }
  .board-grid .board-member {
    width: clamp(8rem, 6.5rem + 3vw, 10.5rem);
  }
}
/* On the 2-col mobile grid an odd headcount also strands a member —
   let the last odd item span the full width so it centres. */
@media (max-width: 639.98px) {
  .board-member:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }
}

.board-member {
  text-align: center;
}
.board-member__photo {
  width: clamp(9rem, 7rem + 5vw, 13rem);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  margin-inline: auto;
  margin-bottom: var(--space-md);
  /* Crisp 1px white edge — defines the photo without overpowering it. */
  border: 1px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 0 0 transparent;
  transition:
    border-color 0.35s var(--ease-out),
    box-shadow 0.45s var(--ease-out),
    transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.board-member__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--white);
  /* Editorial colour grade — matches the hero slideshow recipe so every
     photograph on the site sits in the same tonal range. */
  filter: contrast(1.05) saturate(0.88) brightness(0.99);
}
.board-member:hover .board-member__photo {
  border-color: var(--gold);
  box-shadow:
    0 0 0 6px rgba(232, 184, 75, 0.12),         /* gold halo ring */
    0 14px 30px -14px rgba(0, 0, 0, 0.25);       /* soft lift shadow */
  transform: translateY(-3px);
}

.board-member__name {
  font-size: var(--font-base);
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--navy);
  line-height: 1.3;
}

.section--dark .board-member .board-member__name {
  color: var(--white);
}

.section--dark .board-member__photo {
  border-color: rgba(255, 255, 255, 0.15);
}

.section--dark .board-member:hover .board-member__photo {
  border-color: var(--gold);
}


/* --- Donation Tiers -------------------------------------- */
.donate-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-lg);
}

@media (min-width: 640px) {
  .donate-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 960px) {
  .donate-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.donate-card {
  background: var(--white);
  border-radius: var(--radius-xl);
  padding: var(--space-xl) var(--space-lg);
  text-align: center;
  border: 1px solid var(--sand);
  display: flex;
  flex-direction: column;
  transition: transform var(--duration) var(--ease-out), box-shadow var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
}

.donate-card:hover {
  border-color: var(--gold);
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
}

.donate-card__amount {
  font-size: var(--font-3xl);
  font-weight: 800;
  color: var(--green);
  margin-bottom: var(--space-sm);
}

.donate-card__desc {
  font-size: var(--font-base);
  color: var(--text-secondary);
  line-height: 1.6;
  flex: 1;
  margin-bottom: var(--space-lg);
}

.donate-card .btn {
  align-self: center;
}

/* --- Check / Mail Section (donate page) ------------------ */
.check-section__subtitle {
  margin-top: var(--space-md);
  color: var(--text-secondary);
}

.check-section__address {
  font-style: normal;
  margin-top: var(--space-lg);
  font-size: var(--font-lg);
  font-weight: 600;
  color: var(--navy);
  line-height: 1.8;
}


/* --- Impact Stories (editorial cards) --------------------- */
/* Each story is a contained card with a photo column. The card sits
   in a .story-stack column that creates the gap between stories.
   On desktop the photo alternates L/R for visual rhythm. */
.story-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);
  margin-top: var(--space-xl);
}

.story-editorial {
  background: var(--white);
  border-radius: var(--radius-xl);
  overflow: hidden;
  box-shadow: var(--shadow-md);
  display: grid;
  grid-template-columns: 1fr;          /* mobile: stacked */
  border: 1px solid var(--sand);
  transition: box-shadow var(--duration) var(--ease-out), transform var(--duration) var(--ease-out);
}
.story-editorial:hover {
  box-shadow: var(--shadow-xl);
  /* No transform on hover — the photo shouldn't shift/zoom when the cursor
     merely passes over while scrolling. Shadow-only is the quiet cue. */
}

@media (min-width: 768px) {
  .story-editorial {
    grid-template-columns: 2fr 3fr;     /* photo left, content right */
    min-height: 26rem;
  }
  /* Alternate L/R for visual rhythm */
  .story-editorial:nth-child(even) {
    grid-template-columns: 3fr 2fr;
  }
  .story-editorial:nth-child(even) .story-editorial__photo {
    order: 2;
  }
}

.story-editorial__photo {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--cream-dark);
}
@media (min-width: 768px) {
  .story-editorial__photo {
    aspect-ratio: auto;
    height: 100%;
  }
}
.story-editorial__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* Editorial colour grade — matches the hero slideshow + board grid so
     every photo on the site lands in the same tonal range. */
  filter: contrast(1.05) saturate(0.92) brightness(0.98);
  transition: transform 1.2s var(--ease-out);
}

/* Per-story object-position so the subject lands in frame after the
   "cover" crop. Without these, tall/wide source photos can clip the
   person out of the visible area. */
#thembi .story-editorial__photo img       { object-position: 55% 35%; }
#msizi .story-editorial__photo img        { object-position: 50% 35%; }
#audery .story-editorial__photo img       { object-position: 50% 30%; }
#qiniso .story-editorial__photo img       { object-position: 65% 40%; }
#nontutuzelo .story-editorial__photo img  { object-position: 50% 40%; }
#nosipho .story-editorial__photo img      { object-position: 50% 40%; }

/* Story cards stay white plates even inside .section--dark — keep their
   internal text colours readable (the .section--dark cascade was making
   the navy h3 turn white, hiding the name). */
.section--dark .story-editorial__name        { color: var(--navy); }
.section--dark .story-editorial__body,
.section--dark .story-editorial__body p      { color: var(--text-primary); }
.section--dark .story-editorial__pathway h4  { color: var(--green); }
.section--dark .story-editorial__pathway p   { color: var(--text-primary); }
.section--dark .story-editorial__org         { color: var(--gold-dark); }

.story-editorial__inner {
  padding: var(--space-xl);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-sm);
}
@media (min-width: 768px) {
  .story-editorial__inner {
    padding: var(--space-xl) var(--space-2xl);
  }
}

.story-editorial__org {
  margin: 0;
  font-size: var(--font-xs);
  font-weight: 700;
  color: var(--gold-dark);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.story-editorial__org a {
  color: inherit;
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration-fast) var(--ease-out);
}
.story-editorial__org a:hover {
  border-bottom-color: var(--gold-dark);
}

.story-editorial__name {
  margin: 0;
  font-size: var(--font-2xl);
  color: var(--navy);
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.story-editorial__body {
  font-size: var(--font-base);
  line-height: 1.75;
  color: var(--text-primary);
}
.story-editorial__body p {
  margin: 0;
}

.story-editorial__pathway {
  margin-top: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  background: var(--cream);
  border-radius: var(--radius-lg);
  border-left: 3px solid var(--green);
}
.story-editorial__pathway h4 {
  margin: 0 0 var(--space-xs) 0;
  color: var(--green);
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.story-editorial__pathway p {
  margin: 0;
  font-size: var(--font-sm);
  color: var(--text-secondary);
  line-height: 1.65;
}


/* --- Footer ---------------------------------------------- */
.footer {
  background: var(--navy-dark);
  color: rgba(250, 248, 244, 0.7);
  padding: var(--space-2xl) 0 var(--space-xl);
}

.footer__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-xl);
}

@media (min-width: 768px) {
  .footer__inner {
    grid-template-columns: 2fr 1fr 1fr;
  }
}

.footer__brand p {
  margin-top: var(--space-md);
  max-width: 28rem;
  line-height: 1.7;
}

.footer h5 {
  color: var(--white);
  font-size: var(--font-sm);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: var(--space-md);
}

.footer a {
  color: rgba(250, 248, 244, 0.7);
  display: block;
  padding: var(--space-xs) 0;
  font-size: var(--font-sm);
}
.footer a:hover {
  color: var(--gold);
}

.footer__bottom {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-md);
  font-size: var(--font-xs);
}

.footer__logo {
  height: 2.5rem;
}

.footer__address {
  margin-top: var(--space-sm);
  font-size: var(--font-sm);
}

.footer__social {
  display: flex;
  gap: var(--space-md);
  margin-top: var(--space-md);
}

.footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem;
  min-width: 44px;
  min-height: 44px;
  margin: -0.6rem;             /* keep visual gap unchanged */
}


/* Subscribe stage lighting — two soft pools of navy-light positioned
   where the donate column (left) and newsletter column (right) sit on
   desktop. The pools overlap softly in the middle of the section, so it
   reads as ambient "stage light" rather than two distinct spotlights.
   On mobile (single column), the two pools converge to a centred glow.
   Lower intensity than Focus's single spotlight so the navy band feels
   varied, not repetitive. */
#subscribe.section--dark {
  background-image:
    radial-gradient(ellipse 55% 65% at 28% 50%, rgba(42, 68, 104, 0.50) 0%, transparent 65%),
    radial-gradient(ellipse 55% 65% at 72% 50%, rgba(42, 68, 104, 0.50) 0%, transparent 65%);
  background-color: var(--navy-dark);
}

/* --- Subscribe section: 2-col split inside one 100svh stage ---
   Desktop: donate-led copy on the left, newsletter form on the right,
   thin vertical hairline between. Mobile: stacks vertically with a
   horizontal hairline. Sizes are deliberately tight so the whole block
   sits inside 100svh on typical viewports. */
.subscribe-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-xl);
  align-items: center;
  max-width: 60rem;
  margin-inline: auto;
}
@media (min-width: 768px) {
  .subscribe-split {
    grid-template-columns: 1fr auto 1fr;
    gap: clamp(2rem, 4vw, 4rem);
  }
}

.subscribe-side {
  text-align: center;
}
@media (min-width: 768px) {
  .subscribe-side                        { text-align: left;  padding-right: var(--space-md); }
  .subscribe-side--newsletter            { text-align: left;  padding-right: 0; padding-left: var(--space-md); }
}

/* Compact H2 + body inside the split — overrides the .section--full huge
   editorial sizes so both columns fit the deck without overflow. */
.subscribe-split__title {
  font-size: clamp(1.5rem, 1.2rem + 0.8vw, 2rem);
  letter-spacing: -0.015em;
  line-height: 1.15;
  margin-bottom: var(--space-sm);
}
.section--full .subscribe-split__title {
  font-size: clamp(1.5rem, 1.2rem + 0.8vw, 2rem);   /* beat the full-stage h2 size */
}
.subscribe-split__body {
  font-size: var(--font-sm);
  line-height: 1.6;
  margin-bottom: var(--space-md);
  color: rgba(250, 248, 244, 0.85);
}

/* Divider: horizontal hairline between blocks on mobile, vertical between
   columns on desktop. */
.subscribe-divider {
  height: 1px;
  width: clamp(3rem, 12vw, 5rem);
  background: rgba(250, 248, 244, 0.18);
  margin-inline: auto;
  justify-self: center;
}
@media (min-width: 768px) {
  .subscribe-divider {
    height: auto;
    width: 1px;
    align-self: stretch;
    margin-block: var(--space-md);
  }
}

/* --- Newsletter Form ------------------------------------- */
.newsletter-form {
  display: flex;
  flex-direction: column;                   /* mobile: stack input over button */
  gap: var(--space-sm);
  max-width: 28rem;
  margin-inline: auto;
}
.newsletter-form input {
  width: 100%;
  padding: 0.85em 1.25em;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.06);
  color: var(--white);
  font-family: var(--font-family);
  font-size: var(--font-sm);
  outline: none;
  min-width: 0;
  transition: border-color 0.3s var(--ease-out), background 0.3s var(--ease-out);
}
.newsletter-form input::placeholder {
  color: rgba(255, 255, 255, 0.45);
}
.newsletter-form input:focus {
  border-color: rgba(232, 184, 75, 0.6);
  background: rgba(255, 255, 255, 0.09);
}
.newsletter-form .btn {
  width: 100%;
  padding: 0.7em 1.4em;
  font-size: var(--font-sm);
}

/* From tablet up — input + button sit on one line in a pill chassis. */
@media (min-width: 480px) {
  .newsletter-form {
    flex-direction: row;
    gap: var(--space-xs);
    padding: 0.35rem;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: var(--radius-full);
    transition: border-color 0.3s var(--ease-out), background 0.3s var(--ease-out);
  }
  .newsletter-form:focus-within {
    border-color: rgba(232, 184, 75, 0.6);
    background: rgba(255, 255, 255, 0.09);
  }
  .newsletter-form input {
    flex: 1;
    width: auto;
    padding: 0.65em 1.1em;
    border: none;
    background: transparent;
  }
  .newsletter-form input:focus {
    border: none;
    background: transparent;
  }
  .newsletter-form .btn {
    width: auto;
    flex-shrink: 0;
    padding: 0.55em 1.4em;
  }
}

.newsletter-success {
  margin-top: var(--space-md);
  font-size: var(--font-sm);
  color: var(--gold);
  letter-spacing: 0.02em;
}


/* --- Page Hero (sub-pages) ------------------------------- */
.page-hero {
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2xl) 0;
  padding-top: 5rem;
  text-align: center;
  background: linear-gradient(
    160deg,
    var(--navy-dark) 0%,
    var(--navy) 40%,
    var(--navy-light) 100%
  );
  position: relative;
  overflow: hidden;
}
/* When the page-hero has a photo background, kill the navy gradient so
   the fixed slideshow (z-index:-1) shows through. Without this, the
   gradient opaquely covers the slideshow and the photos vanish. */
.page-hero--has-photo {
  background: transparent;
}
/* Fallback navy on the body for pages that include a photo-backed
   page-hero — prevents a flash of cream body bg before the slideshow
   image decodes. */
body:has(.page-hero--has-photo) {
  background-color: var(--navy-dark);
}

/* Blurred editorial photo behind the orb gradient — adds depth and a
   real-world sense of place to the hero without competing with the type.
   Heavy blur + navy veil keeps the photo as "atmosphere" not "subject"
   so the gradient + drifting orbs still own the colour story. */
.page-hero__bg {
  /* Fixed slideshow — content scrolls over the photo, photo stays put.
     inset:-5% gives the blur edges room without exposing the page bg. */
  position: fixed;
  inset: -5%;
  z-index: -1;
  overflow: hidden;
}
/* Slides inside the page-hero rotate as a soft-focus gallery — almost
   crisp enough to read the subjects, with just enough softness that the
   overlay type sits cleanly. Higher specificity than the .hero__slide
   homepage rule so the blur isn't overridden. */
.page-hero .hero__slideshow .hero__slide {
  object-position: center 40%;
  /* Very soft focus only — photo is clearly legible, just not crisp. */
  filter: blur(2px) brightness(0.92) saturate(0.95);
  transform: scale(1.02);
}
.page-hero__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Cinematic vignette — picture stays legible in the centre; corners
     darken hard to draw the eye inward. Pure radial, no all-over tint. */
  background:
    radial-gradient(ellipse 70% 65% at 50% 45%, transparent 35%, rgba(6, 14, 28, 0.85) 100%);
  pointer-events: none;
}
/* Shallow depth-of-field blur, layered behind the dark vignette above.
   Same recipe as .hero__bg::after — radial mask makes the blur fade
   away in the centre so the subject reads sharp and the edges go soft
   like a wide-aperture lens. */
.page-hero__bg::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  -webkit-mask-image: radial-gradient(ellipse 65% 75% at 50% 45%, transparent 25%, black 85%);
          mask-image: radial-gradient(ellipse 65% 75% at 50% 45%, transparent 25%, black 85%);
}

/* When the page-hero has a photo backdrop, the outlined-green eyebrow
   pill gets lost against the busy imagery. Switch to a solid white pill
   with green text — same colour palette inverted, much more legible. */
.page-hero--has-photo .eyebrow {
  background: var(--white);
  color: var(--green);
  border-color: var(--white);
}

/* Lead copy gets the same frosted-green plate as the homepage hero
   subtitle — keeps the type readable over a busy photo background and
   ties the two heroes together visually. */
.page-hero--has-photo .lead {
  background: rgba(61, 122, 62, 0.92);
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  border-radius: var(--radius-lg);
  color: var(--white);
  padding: 0.85rem 1.5rem;
  max-width: 50rem;
  margin-left: auto;
  margin-right: auto;
  font-size: clamp(0.9rem, 0.82rem + 0.3vw, 1.05rem);
  line-height: 1.55;
}
.page-hero > .container {
  position: relative;
  z-index: 2;
}
.page-hero > .hero__scroll-hint {
  /* keep position:absolute from .page-hero .hero__scroll-hint — only need
     z-index here so it stays above the .page-hero__bg layer */
  z-index: 2;
}

/* Animated gradient orbs — slow-moving depth */
.page-hero::before,
.page-hero::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  filter: blur(80px);
  z-index: 1;                                /* above the .page-hero__bg photo, below .container content */
}

.page-hero::before {
  width: 50vw;
  height: 50vw;
  max-width: 40rem;
  max-height: 40rem;
  top: -10%;
  right: -10%;
  background: radial-gradient(circle, rgba(61, 122, 62, 0.2) 0%, transparent 70%);
  animation: orb-drift-1 20s ease-in-out infinite;
}

.page-hero::after {
  width: 40vw;
  height: 40vw;
  max-width: 30rem;
  max-height: 30rem;
  bottom: -5%;
  left: -5%;
  background: radial-gradient(circle, rgba(232, 184, 75, 0.12) 0%, transparent 70%);
  animation: orb-drift-2 25s ease-in-out infinite;
}

@keyframes orb-drift-1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(-5vw, 8svh) scale(1.1); }
  66%      { transform: translate(3vw, -5svh) scale(0.95); }
}

@keyframes orb-drift-2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  40%      { transform: translate(6vw, -6svh) scale(1.15); }
  70%      { transform: translate(-4vw, 4svh) scale(0.9); }
}

.page-hero h1 {
  color: var(--white);
  margin-bottom: var(--space-sm);
  position: relative;
}

/* On the photo-backed page hero, lift the title off the busy imagery:
   the home-hero stack — a hard hairline shadow for clean white edges,
   plus a wide diffuse shadow for stage-light depth. */
.page-hero--has-photo h1 {
  text-shadow: var(--shadow-text);
}

/* Gold rule under the heading */
.page-hero h1::after {
  content: '';
  display: block;
  width: 4rem;
  height: 3px;
  background: var(--gold);
  margin: var(--space-md) auto 0;
  border-radius: 2px;
}

.page-hero .lead {
  max-width: 38rem;
  margin-inline: auto;
  margin-top: var(--space-lg);
  color: rgba(250, 248, 244, 0.85);
  position: relative;
}

.page-hero .hero__scroll-hint {
  position: absolute;
  bottom: var(--space-lg);
  left: 50%;
  transform: translateX(-50%);
  margin-top: 0;
}


/* Soft gradient transition between contrasting sections — only fires
   when the adjacent sections differ in tone (dark → light or vice versa). */
.section--dark + .section:not(.section--dark),
.section--dark + .section--cream {
  border-top: 1px solid var(--sand);
}

.section:not(.section--dark) + .section--dark {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* Hero-to-content gradient bleed */
.page-hero + .section,
.page-hero + .section--cream {
  position: relative;
  border-top: none;
}

.page-hero + .section::before,
.page-hero + .section--cream::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 8rem;
  background: linear-gradient(180deg, var(--navy-light), transparent);
  opacity: 0.06;
  pointer-events: none;
}


/* --- CTA section helpers --------------------------------- */
.text-center { text-align: center; }

.lead--centered {
  max-width: 36rem;
  margin-inline: auto;
}

.cta-lead {
  margin-top: var(--space-md);
  margin-bottom: var(--space-xl);
}

.newsletter-intro {
  font-size: var(--font-sm);
  color: rgba(250, 248, 244, 0.65);
  margin-bottom: var(--space-md);
  letter-spacing: 0.005em;
}

.btn--spaced-top {
  margin-top: var(--space-md);
}


/* --- Scroll Reveal --------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

.reveal-delay-1 { transition-delay: 0.1s; }
.reveal-delay-2 { transition-delay: 0.2s; }
.reveal-delay-3 { transition-delay: 0.3s; }
.reveal-delay-4 { transition-delay: 0.4s; }

/* --- Bento photo emerge ---------------------------------- */
/* Slow, graceful staggered arrival. Tiles start hidden + a hair zoomed (only
   when JS is present, so it's fail-safe — JS off shows them) and TRANSITION
   in one after another. A transition (not a keyframe with backwards-fill)
   avoids the snap-to-invisible flash. initCurtain() reveals a gallery's tiles
   as a group when it scrolls in; the per-tile transition-delay then plays the
   cascade in order — a deliberate, calm procession, not a fast twinkle. The
   scale settle is on the TILE (not the img), so it never conflicts with the
   img hover zoom. */
.js .bento-gallery__item {
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 1.3s cubic-bezier(0.4, 0, 0.2, 1),
              transform 1.5s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: opacity, transform;
}
.js .bento-gallery__item.is-emerging {
  opacity: 1;
  transform: scale(1);
}
.js .bento-gallery__item:nth-child(2).is-emerging  { transition-delay: 0.16s; }
.js .bento-gallery__item:nth-child(3).is-emerging  { transition-delay: 0.32s; }
.js .bento-gallery__item:nth-child(4).is-emerging  { transition-delay: 0.48s; }
.js .bento-gallery__item:nth-child(5).is-emerging  { transition-delay: 0.64s; }
.js .bento-gallery__item:nth-child(6).is-emerging  { transition-delay: 0.80s; }
.js .bento-gallery__item:nth-child(7).is-emerging  { transition-delay: 0.96s; }
.js .bento-gallery__item:nth-child(8).is-emerging  { transition-delay: 1.12s; }
.js .bento-gallery__item:nth-child(9).is-emerging  { transition-delay: 1.28s; }
@media (prefers-reduced-motion: reduce) {
  .js .bento-gallery__item { opacity: 1; transform: none; transition: none; }
}


/* --- Counter Animation ----------------------------------- */
.counter {
  display: inline-block;
}


/* --- Mandela Quote --------------------------------------- */
.quote-section {
  text-align: center;
  padding: var(--space-2xl) var(--space-md);
}

.quote-section blockquote {
  border-left: none;
  background: none;
  padding: 0;
  max-width: 44rem;
  margin-inline: auto;
  font-size: var(--font-xl);
  color: var(--white);
}

.quote-section blockquote::before {
  content: '\201C';
  display: block;
  font-size: 4rem;
  line-height: 1;
  color: var(--gold);
  margin-bottom: var(--space-sm);
}


/* --- Skip link ------------------------------------------- */
.skip-link {
  position: absolute;
  top: -100px;
  left: 1rem;
  z-index: 1000;
  padding: 0.75em 1.5em;
  background: var(--navy-dark);
  color: var(--white);
  border-radius: var(--radius-md);
  font-weight: 600;
  text-decoration: none;
  transition: top 0.2s var(--ease-out);
}
.skip-link:focus {
  top: 1rem;
  color: var(--white);
}


/* --- Link with arrow ------------------------------------- */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 600;
  color: var(--green);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
}
.link-arrow:hover {
  color: var(--green-light);
  border-bottom-color: var(--green-light);
}
.link-arrow span {
  transition: transform var(--duration) var(--ease-out);
}
.link-arrow:hover span {
  transform: translateX(4px);
}
.link-arrow--light {
  color: var(--gold-light);
}
.link-arrow--light:hover {
  color: var(--gold);
  border-bottom-color: var(--gold);
}


/* ===========================================================
   PROJECT PAGE — partner-specific layout
   =========================================================== */

/* --- Project Hero — 2-column split: photo left, content right.
   Mobile stacks (photo on top, content below). The content column sits
   on navy (matches the nav). Same systems-first treatment as the
   partner cards on the home grid. */
.project-hero {
  display: grid;
  grid-template-columns: 1fr;        /* mobile: stacked */
  min-height: 100svh;
  background: var(--navy-dark);
  color: var(--white);
  overflow: hidden;
  /* On mobile the nav floats over the hero photo (the logo + hamburger
     already carry drop-shadows for legibility on busy backdrops), so no
     padding-top is needed — the photo butts up against the top edge. */
}

@media (min-width: 768px) {
  .project-hero {
    grid-template-columns: 1fr 1fr;   /* equal columns */
  }
}

.project-hero__photo {
  position: relative;
  aspect-ratio: 4 / 3;                /* mobile crop */
  overflow: hidden;
  background: var(--cream-dark);
}

@media (min-width: 768px) {
  .project-hero__photo {
    aspect-ratio: auto;
    height: 100%;
  }
}

.project-hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}

/* Scroll-linked push-in on the partner-page hero photo (see
   initProjectHeroParallax in main.js) — the image zooms as you scroll down
   past it, the same scroll-driven treatment as the Our Story portrait, which
   suits a single still far better than a time-based loop. transform-origin
   set to the crop focus so it pushes toward the subject. */
.project-hero__photo img {
  transform-origin: center 30%;
}

.project-hero__content {
  padding: var(--space-xl) var(--space-lg);
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-width: 36rem;
  margin: 0 auto;
}

@media (min-width: 768px) {
  .project-hero__content {
    /* Top-aligned, not centred. With justify-content:center the PARTNER
       kicker landed at different heights across project pages because a
       4-meta-item stack (Kgololo) is taller than a 3-meta stack and
       centring pushed the top of the stack upward. Anchoring to the top
       with a fixed-fluid padding-top puts the kicker on the SAME line
       across every partner page. Padding-bottom stays generous so action
       buttons never crowd the section edge. */
    justify-content: flex-start;
    padding-top: clamp(4rem, 12svh, 7rem);
    padding-bottom: clamp(2rem, 5svh, 4rem);
    padding-inline: var(--space-xl);
    margin: 0 auto 0 0;
  }
}

.project-hero__title {
  font-size: clamp(3rem, 2.2rem + 3.5vw, 5rem);
  color: var(--white);
  letter-spacing: -0.035em;
  line-height: 1;
  margin-bottom: var(--space-md);
}

/* Small uppercase kicker above the partner name — gold, with proper
   tracking — so the H1 reads "PARTNER / Thanda" instead of repeating
   "Partners / Thanda" in a breadcrumb above. One title, two registers. */
.project-hero__title-kicker {
  display: block;
  font-size: clamp(0.85rem, 0.75rem + 0.3vw, 1.05rem);
  font-weight: 700;
  color: var(--gold);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin-bottom: var(--space-sm);
  line-height: 1.2;
}

.project-hero__tagline {
  font-size: var(--font-lg);
  font-weight: 400;
  line-height: 1.5;
  color: rgba(250, 248, 244, 0.92);
  max-width: 36rem;
  margin-bottom: clamp(1rem, 2.5svh, 2rem);
}

.project-hero__meta {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-sm) var(--space-xl);
  padding: clamp(0.75rem, 1.5svh, 1.25rem) 0;
  margin-bottom: clamp(1rem, 2.5svh, 2rem);
  border-top: 1px solid rgba(232, 184, 75, 0.35);
  border-bottom: 1px solid rgba(232, 184, 75, 0.15);
  font-size: var(--font-sm);
  max-width: 36rem;
}

@media (min-width: 640px) {
  .project-hero__meta {
    grid-template-columns: 1fr 1fr;
  }
}

.project-meta__label {
  display: block;
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-light);
  margin-bottom: 0.2em;
}

.project-hero__actions {
  display: flex;
  gap: var(--space-md);
  flex-wrap: wrap;
}

/* Old scroll-hint marker no longer rendered in the split layout */


/* --- At-a-glance stat ribbon ----------------------------- */
.project-glance .stats {
  gap: var(--space-lg);
}


/* --- Project intro ---------------------------------------
   Lives inside the standard `.container` (72rem) so its outer edges
   align with Programs and Story sections. The inner content is capped
   at 60rem for editorial line-length so the long body paragraphs still
   read cleanly. */
.project-intro {
  max-width: 60rem;
  margin-inline: auto;
}
.project-intro h2 {
  margin-bottom: var(--space-md);
}
.project-intro .lead {
  color: var(--text-primary);
  margin-bottom: var(--space-lg);
}
.prose p {
  margin-bottom: 1em;
  font-size: var(--font-base);
  line-height: 1.75;
}


/* --- Bento gallery ---------------------------------------
   Editorial photo cluster — varied tile sizes inside a 12-col × 8-row
   grid, all rounded, with generous breathing room around the cluster.
   The cluster sits inside a 100svh section but only occupies ~80% of
   that height so it feels "placed" rather than edge-to-edge.

   Layouts are named (a, b, c…) on each partner page so each story can
   carry its own composition — the size system is consistent, but no
   two partners' clusters look alike. */
.section--bento-gallery {
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Edge padding matches the tile gap (0.5rem) so the bento reads as
     near-full-width with a tiny symmetric gutter — the cluster sits
     "nested" in the viewport without competing for width with the
     narrower body sections elsewhere on the page. */
  padding: var(--space-lg) 0.5rem;
  background: var(--cream);
}
.bento-gallery {
  width: 100%;
  /* Cap at 120rem for ultra-wide displays so tiles don't get absurd;
     below that, the section's 0.5rem edges dictate the width. */
  max-width: 120rem;
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: repeat(8, minmax(0, 1fr));
  gap: 0.5rem;
  height: 80svh;
  max-height: 720px;
}
.bento-gallery__item {
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--sand);
  position: relative;
}
.bento-gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 1.4s var(--ease-out);
}
.bento-gallery__item:hover img {
  transform: scale(1.05);
}

/* Layout A — 7 tiles, asymmetric weight to the centre. (Thanda) */
.bento-gallery--a {
  grid-template-areas:
    "a a a a b b b b b c c c"
    "a a a a b b b b b c c c"
    "a a a a b b b b b c c c"
    "a a a a d d d d e e e e"
    "f f f f d d d d e e e e"
    "f f f f d d d d e e e e"
    "f f f f g g g g e e e e"
    "f f f f g g g g e e e e";
}
.bento-gallery--a > :nth-child(1) { grid-area: a; }
.bento-gallery--a > :nth-child(2) { grid-area: b; }
.bento-gallery--a > :nth-child(3) { grid-area: c; }
.bento-gallery--a > :nth-child(4) { grid-area: d; }
.bento-gallery--a > :nth-child(5) { grid-area: e; }
.bento-gallery--a > :nth-child(6) { grid-area: f; }
.bento-gallery--a > :nth-child(7) { grid-area: g; }

/* Layout B — 8 tiles, balanced grid with one tall left column. (BRAVE) */
.bento-gallery--b {
  grid-template-areas:
    "a a a a b b b b c c c c"
    "a a a a b b b b c c c c"
    "a a a a d d d d c c c c"
    "e e e e d d d d f f f f"
    "e e e e d d d d f f f f"
    "e e e e g g g g h h h h"
    "e e e e g g g g h h h h"
    "e e e e g g g g h h h h";
}
.bento-gallery--b > :nth-child(1) { grid-area: a; }
.bento-gallery--b > :nth-child(2) { grid-area: b; }
.bento-gallery--b > :nth-child(3) { grid-area: c; }
.bento-gallery--b > :nth-child(4) { grid-area: d; }
.bento-gallery--b > :nth-child(5) { grid-area: e; }
.bento-gallery--b > :nth-child(6) { grid-area: f; }
.bento-gallery--b > :nth-child(7) { grid-area: g; }
.bento-gallery--b > :nth-child(8) { grid-area: h; }

/* Layout C — 7 tiles, dominant centre anchor; bottom-centre tile widened
   (the old slender sliver merged in). (Siyakwazi) */
.bento-gallery--c {
  grid-template-areas:
    "a a a a b b b b b c c c"
    "a a a a b b b b b c c c"
    "d d d d b b b b b c c c"
    "d d d d b b b b b e e e"
    "d d d d f f f f f e e e"
    "g g g g f f f f f e e e"
    "g g g g f f f f f e e e"
    "g g g g f f f f f e e e";
}
.bento-gallery--c > :nth-child(1) { grid-area: a; }
.bento-gallery--c > :nth-child(2) { grid-area: b; }
.bento-gallery--c > :nth-child(3) { grid-area: c; }
.bento-gallery--c > :nth-child(4) { grid-area: d; }
.bento-gallery--c > :nth-child(5) { grid-area: e; }
.bento-gallery--c > :nth-child(6) { grid-area: f; }
.bento-gallery--c > :nth-child(7) { grid-area: g; }

/* Layout D — 8 tiles, dense editorial grid; left column extended into a
   single tall tile (replaces the old bottom-left duplicate). (True North) */
.bento-gallery--d {
  grid-template-areas:
    "a a a b b b b c c d d d"
    "a a a b b b b c c d d d"
    "a a a b b b b c c d d d"
    "e e e b b b b c c f f f"
    "e e e g g g g c c f f f"
    "e e e g g g g h h f f f"
    "e e e g g g g h h f f f"
    "e e e g g g g h h f f f";
}
.bento-gallery--d > :nth-child(1) { grid-area: a; }
.bento-gallery--d > :nth-child(2) { grid-area: b; }
.bento-gallery--d > :nth-child(3) { grid-area: c; }
.bento-gallery--d > :nth-child(4) { grid-area: d; }
.bento-gallery--d > :nth-child(5) { grid-area: e; }
.bento-gallery--d > :nth-child(6) { grid-area: f; }
.bento-gallery--d > :nth-child(7) { grid-area: g; }
.bento-gallery--d > :nth-child(8) { grid-area: h; }

/* Layout E — 6 tiles, triptych top + wider trio below (no slender slivers). (Kgololo) */
.bento-gallery--e {
  grid-template-areas:
    "a a a a b b b b c c c c"
    "a a a a b b b b c c c c"
    "a a a a b b b b c c c c"
    "d d d e e e e e e f f f"
    "d d d e e e e e e f f f"
    "d d d e e e e e e f f f"
    "d d d e e e e e e f f f"
    "d d d e e e e e e f f f";
}
.bento-gallery--e > :nth-child(1) { grid-area: a; }
.bento-gallery--e > :nth-child(2) { grid-area: b; }
.bento-gallery--e > :nth-child(3) { grid-area: c; }
.bento-gallery--e > :nth-child(4) { grid-area: d; }
.bento-gallery--e > :nth-child(5) { grid-area: e; }
.bento-gallery--e > :nth-child(6) { grid-area: f; }

/* Mobile: collapse to a fluid 2-col stack with `dense` so larger tiles
   pack neatly. Designer-chosen "feature" tiles get the double cell. */
/* --- Bento gallery — mobile -----------------------------------------
   The desktop named-area placements (.bento-gallery--a > :nth-child(N)
   { grid-area: a }) have higher specificity than a generic mobile reset,
   so we override them at matching specificity here. Every per-layout
   tile is released from its named area, then a single mobile rhythm is
   applied: 2-column grid with three feature tiles (full-width hero at
   1, tall portrait at 4, full-width divider at 6) to break the
   monotony. `grid-auto-flow: dense` packs the remaining half-tiles
   neatly into the gaps. Inline padding on the section keeps the cluster
   inside the viewport — no tile bleeds to the edges. */
@media (max-width: 700px) {
  .section--bento-gallery {
    min-height: auto;
    padding: var(--space-lg) clamp(0.75rem, 4vw, 1.5rem);
  }
  .bento-gallery {
    height: auto;
    max-height: none;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: none;
    grid-auto-rows: clamp(150px, 42vw, 240px);
    grid-auto-flow: dense;
    grid-template-areas: none;
    gap: 0.5rem;
  }

  /* Reset all per-layout placements at matching specificity (each
     :nth-child below mirrors the desktop selectors so this rule wins
     via cascade order, not via !important). */
  .bento-gallery--a > :nth-child(n),
  .bento-gallery--b > :nth-child(n),
  .bento-gallery--c > :nth-child(n),
  .bento-gallery--d > :nth-child(n),
  .bento-gallery--e > :nth-child(n) {
    grid-area: auto;
    grid-column: span 1;
    grid-row: span 1;
  }

  /* Feature tiles — break the 2-col rhythm into something editorial. */
  .bento-gallery--a > :nth-child(1),
  .bento-gallery--b > :nth-child(1),
  .bento-gallery--c > :nth-child(1),
  .bento-gallery--d > :nth-child(1),
  .bento-gallery--e > :nth-child(1) {
    grid-column: span 2;                 /* wide hero at top */
  }
  .bento-gallery--a > :nth-child(4),
  .bento-gallery--b > :nth-child(4),
  .bento-gallery--c > :nth-child(4),
  .bento-gallery--d > :nth-child(4),
  .bento-gallery--e > :nth-child(4) {
    grid-row: span 2;                    /* tall portrait mid-gallery */
  }
  .bento-gallery--a > :nth-child(6),
  .bento-gallery--b > :nth-child(6),
  .bento-gallery--c > :nth-child(6),
  .bento-gallery--d > :nth-child(6),
  .bento-gallery--e > :nth-child(6) {
    grid-column: span 2;                 /* wide divider lower down */
  }
}


/* --- Program grid (numbered cards) ----------------------- */
.program-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}
@media (min-width: 640px) {
  .program-grid {
    grid-template-columns: 1fr 1fr;
  }
}
@media (min-width: 960px) {
  .program-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

.program-card {
  background: var(--white);
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  border: 1px solid var(--sand);
  border-top: 5px solid var(--green);
  transition: transform var(--duration) var(--ease-out), box-shadow var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
  position: relative;
}
.program-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-top-color: var(--gold);
}
.program-card__num {
  font-size: var(--font-xs);
  font-weight: 800;
  letter-spacing: 0.16em;
  color: var(--gold-dark);
  text-transform: uppercase;
  margin-bottom: var(--space-sm);
}
.program-card h3 {
  font-size: var(--font-lg);
  margin-bottom: var(--space-sm);
}
.program-card p {
  font-size: var(--font-sm);
  line-height: 1.7;
  color: var(--text-secondary);
}

.program-card--summary {
  background: var(--navy);
  color: var(--white);
  border: none;
}
.program-card--summary h3 {
  color: var(--white);
}
.program-card--summary p {
  color: rgba(250, 248, 244, 0.85);
}
.program-card--summary .program-card__num {
  color: var(--gold-light);
}


/* --- Featured story (single, on project page) -----------
   Project pages use this variant — a flat block without a photo column.
   Override the impact-stories grid layout back to a simple padded card. */
.story-editorial--featured {
  display: block;
  padding: var(--space-xl);
  border-left: 4px solid var(--gold);
  min-height: 0;
  /* Match `.partnership-card`'s width so the two editorial cards on a
     project page (this one + Even Ground's role below) sit on the same
     centred column. Removes the section-to-section width jump. */
  max-width: 60rem;
  margin-inline: auto;
}
.story-editorial--featured:hover {
  transform: none;
}
.story-editorial--featured .story-editorial__body {
  font-size: var(--font-base);
  color: var(--text-primary);
  margin-bottom: var(--space-md);
}
.story-editorial--featured .story-editorial__more {
  margin-top: var(--space-lg);
}


/* --- Partnership card ------------------------------------
   Navy "brand stamp" card — the closing block on every project page is
   the one section that speaks AS Even Ground rather than ABOUT a
   partner. Flipping it to navy with white type creates a deliberate
   juxtaposition against the cream/white sections surrounding it and
   reinforces navy as Even Ground's core brand colour. */
.partnership-card {
  background: var(--navy-dark);
  color: var(--white);
  border-radius: var(--radius-xl);
  padding: var(--space-xl);
  border: 1px solid rgba(255, 255, 255, 0.06);
  box-shadow: 0 24px 60px -24px rgba(15, 29, 48, 0.45);
  max-width: 60rem;
  margin-inline: auto;
  position: relative;
}
.partnership-card p {
  color: rgba(255, 255, 255, 0.88);
  font-size: var(--font-base);
  line-height: 1.75;
  margin-bottom: var(--space-lg);
}
.partnership-card__list {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-sm);
  padding-top: var(--space-md);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
@media (min-width: 640px) {
  .partnership-card__list {
    grid-template-columns: 1fr 1fr;
  }
}
.partnership-card__list li {
  font-size: var(--font-sm);
  color: rgba(255, 255, 255, 0.78);
  padding-left: 1.5em;
  position: relative;
  line-height: 1.6;
}
.partnership-card__list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.5em;
  height: 0.5em;
  background: var(--gold);
  border-radius: 50%;
}
.partnership-card__list strong {
  color: var(--white);
  font-weight: 700;
}


/* --- Project-specific donate band ------------------------ */
.project-donate {
  margin-bottom: var(--space-lg);
}
.project-donate__more {
  text-align: center;
  margin-top: var(--space-lg);
}


/* --- Adjacent partners (prev/next style) ----------------- */
.adjacent-partners {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
}
@media (min-width: 640px) {
  .adjacent-partners {
    grid-template-columns: repeat(3, 1fr);
  }
}
.adjacent-card {
  display: block;
  padding: var(--space-lg);
  background: var(--white);
  border: 1px solid var(--sand);
  border-radius: var(--radius-lg);
  text-decoration: none;
  transition: transform var(--duration) var(--ease-out), box-shadow var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
}
.adjacent-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--gold);
}
.adjacent-card__label {
  font-size: var(--font-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--gold-dark);
  margin-bottom: var(--space-xs);
}
.adjacent-card h3 {
  font-size: var(--font-xl);
  color: var(--navy);
  margin-bottom: var(--space-md);
}
.adjacent-card__cta {
  font-size: var(--font-sm);
  font-weight: 600;
  color: var(--green);
}
.adjacent-card:hover .adjacent-card__cta {
  color: var(--green-light);
}


/* --- Newsletter form centered variant -------------------- */
.newsletter-form--centered {
  margin-top: var(--space-lg);
}


/* ===========================================================
   Page-level overrides (donate / late-stage tweaks)
   =========================================================== */

/* Section padding modifier — first content section under a hero where
   the hero already has bottom space. Replaces an inline style. */
.section--flush-top {
  padding-top: 0;
}

/* Tablet — donate CTA stays visible when full nav collapses */
@media (min-width: 640px) and (max-width: 1199.98px) {
  .nav__donate {
    display: inline-flex;
  }
}

/* Newsletter form stacks under 480px */
@media (max-width: 480px) {
  .newsletter-form {
    flex-direction: column;
  }
  .newsletter-form input,
  .newsletter-form button {
    width: 100%;
  }
}

/* Trust strip on donate page */
.trust-strip {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
  padding: var(--space-lg);
  background: var(--white);
  border: 1px solid var(--sand);
  border-radius: var(--radius-xl);
  margin-bottom: var(--space-xl);
  text-align: center;
}
@media (min-width: 640px) {
  .trust-strip {
    grid-template-columns: repeat(3, 1fr);
  }
}
.trust-strip__item strong {
  display: block;
  font-size: var(--font-lg);
  font-weight: 800;
  color: var(--navy);
  margin-bottom: 0.2em;
}
.trust-strip__item span {
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-secondary);
}


/* Aria-current page state for nav links (also covers the Partners
   dropdown link which sits next to the chevron-only trigger). */
.nav__links a[aria-current="page"],
.nav__dropdown-link[aria-current="page"] {
  color: var(--gold);
}
.nav__links a[aria-current="page"]::after {
  width: 100%;
}


/* --- Accessible focus ------------------------------------ */
:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}

/* --- Reduced motion -------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal {
    opacity: 1;
    transform: none;
  }
}


/* --- Print ----------------------------------------------- */
@media print {
  .nav, .nav__mobile, .nav__hamburger,
  .hero__scroll-hint,
  .btn, .newsletter-form,
  .carousel-arrow, .carousel-dots, .carousel-hint { display: none; }
  .hero, .page-hero, .project-hero { min-height: auto; padding: 2rem 0; height: auto; }
  .hero__bg, .project-hero__photo { display: none; }
  .section { padding: 1rem 0; }
  body { color: var(--ink); background: var(--white); }
  .reveal { opacity: 1; transform: none; }
  .partner-card { filter: none; transform: none; opacity: 1; }
  .partner-card::after { display: none; }
}
