/* ==========================================================================
   The Project Hope — site stylesheet
   Single file, no build step. Edit here; every page picks it up.

   Contents
     1. Tokens          design system variables
     2. Reset & base    element defaults, typography
     3. Accessibility   skip link, focus, reduced motion
     4. Layout          wrappers, sections, grids
     5. Header & nav
     6. Buttons & links
     7. Components      cards, credentials, forms, quotes
     8. Page sections   hero, banner, vision, gallery, contact
     9. Footer
    10. Utilities

   Rules that are not negotiable (see .claude/skills/hope-brand-system):
     - Never put text on --coral, --sage or --gold. Fills only.
     - Every colour pairing is contrast-verified. Recompute before adding one.
     - Headings max out at font-weight 700; Times has no heavier cut.
   ========================================================================== */


/* --- Tinos, self-hosted ---------------------------------------------------
   Times New Roman is the client's decision and is present on Windows, macOS
   and iOS. Tinos is the metric-compatible substitute for Android and Linux,
   which is most of this audience, so it cannot be dropped.

   It is served from this origin rather than from Google. The third-party
   route cost two DNS lookups, two TLS handshakes and a render-blocking
   stylesheet before a single word could be painted. Only latin and latin-ext
   are shipped: the site is in English, and the Greek, Cyrillic and Vietnamese
   subsets Google serves would never be reached.

   Tinos is designed by Steve Matteson and licensed under the SIL Open Font
   License 1.1. The licence ships beside the files, at assets/fonts/OFL.txt.
   -------------------------------------------------------------------------- */
@font-face{
  font-family:'Tinos';
  font-style:italic;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/tinos-400-italic-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Tinos';
  font-style:italic;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/tinos-400-italic-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Tinos';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/tinos-400-normal-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Tinos';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/tinos-400-normal-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Tinos';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('../fonts/tinos-700-normal-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Tinos';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('../fonts/tinos-700-normal-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* 1. TOKENS ================================================================
   Quiet-luxury palette, from design/HANDOFF.md. Every ratio below was
   computed, not estimated.

   THREE VALUES DEVIATE FROM THE HANDOFF, because the handoff's own contrast
   rule and its token roles disagreed with each other:

   - Eyebrows. The handoff gives #6E8A73 for "eyebrow labels, sage text on
     light". Eyebrows are 12-13px bold, which is not large text, so they need
     4.5:1 — #6E8A73 reaches only 3.57:1 on ivory. --sage-deep is therefore
     #3E5A44 (7.19:1), which is what the handoff's own rule 4 prescribes for
     sage that must read as text. #6E8A73 is kept as --sage-mid, fills only.

   - Gold on deep teal. The handoff states 8.3:1; the real figure for
     #C8A96B on #174F59 is 4.06:1, which fails for small text. --gold-on-teal
     is #D3BA88 (4.85:1) for eyebrow-sized type on teal grounds.

   - Link hover. #A8873F is 3.19:1 on ivory, below 4.5 for body-size links.
     --gold-link-hover is #7E6229 (5.40:1 ivory, 5.08:1 sunk).
   ========================================================================== */
:root{
  /* Ground */
  --cream:#FAF8F3;             /* Warm Ivory — page background */
  --sunk:#F4F1EA;              /* Stone Sunk — alternate sections */
  --white:#FFFFFF;

  /* Ink */
  --charcoal:#252A29;          /* 13.72:1 on ivory */
  --muted:#5C6260;             /* Steel — 5.87:1 on ivory */

  /* Identity */
  --teal:#174F59;              /* 8.61:1 on ivory */
  --teal-deep:#0F3B43;         /* 11.46:1 on ivory; 12.16:1 with white */
  --teal-wash:#EAF0F0;

  /* Growth */
  --sage:#91A995;              /* fill only — 2.38:1, never text */
  --sage-mid:#6E8A73;          /* fill / large decorative only — 3.57:1 */
  --sage-deep:#3E5A44;         /* 7.19:1 on ivory — the text-safe sage */
  --sage-wash:#EFF2EE;

  /* Action */
  --coral:#C97868;             /* Dusty Terracotta — fill only, 3.11:1 */
  --coral-deep:#A9503C;        /* 5.07:1 ivory · 4.77:1 sunk · 5.39:1 w/ white */
  --coral-wash:#F7EAE6;

  /* Certification — reserved for verifiable credentials */
  --gold:#C8A96B;              /* Champagne — fill only, 2.12:1 */
  --gold-deep:#8A6D2F;         /* 4.59:1 on ivory — gold as text */
  --gold-on-teal:#D3BA88;      /* 4.85:1 on --teal — small text on teal */
  --gold-link-hover:#7E6229;   /* 5.40:1 on ivory */
  --gold-accent:#755A24;       /* Training's accent. --gold-deep is 4.59:1 on
                                  ivory but only 4.15:1 on coral-wash and
                                  4.23:1 on teal-wash, and the eyebrow it
                                  colours is 13px -- normal text, 4.5:1. This
                                  clears 5.51:1 on the worst ground used. */

  --line:#E9E6DE;              /* Soft Stone — borders, hairlines */
  --stone-muted:#CFCABE;       /* breadcrumbs on dark — 5.59:1 on teal */
  --error:#A8452F;

  /* Times New Roman first; Tinos is metric-identical and covers Android,
     which has no Times New Roman at all. */
  --font:"Times New Roman",Tinos,"Liberation Serif",Times,serif;

  --s3:.75rem; --s4:1rem; --s5:1.5rem; --s6:2rem;
  --s7:2.25rem; --s8:3rem; --s9:4rem;

  --r-sm:8px; --r-md:14px; --r-lg:22px; --r-pill:999px;

  --e1:0 1px 2px rgba(23,79,89,.06),0 2px 8px rgba(23,79,89,.05);
  --e2:0 4px 12px rgba(23,79,89,.08),0 12px 28px rgba(23,79,89,.07);

  /* The handoff specifies min(100% - 40px, 1140px), and its artboards are
     1200px wide — so in the design a 1140px container fills the frame almost
     edge to edge. On a real 1600-1920px display the same number leaves very
     wide empty margins, which is not what the design looks like. Widened so
     the proportions match the intent rather than the literal value.
     Line length is unaffected: measure is capped separately on .lede and
     body copy, so text never runs longer than it should. */
  /* The accent a page signs itself with. Therapy, the portal and the home
     page keep the teal the whole site is built on; the three pages that
     answer different questions get their own, so a reader who has been
     round the site once can tell which room they are standing in before
     they have read the heading. Each is a text-safe -deep value, so the
     accent is legal anywhere the palette is, not only as a fill. */
  --accent:var(--teal);

  --wrap:1320px;
  --head-h:97px;
  --head-h-wide:149px;
}

/* 2. RESET & BASE ========================================================== */
*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;
  background:var(--cream);
  color:var(--charcoal);
  font-family:var(--font);
  /* Times has a small x-height, so the base starts a step above 1rem */
  font-size:clamp(1.0625rem,1rem + .3vw,1.1875rem);
  line-height:1.58;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{font-family:var(--font); font-weight:700; margin:0; text-wrap:pretty}
/* Balancing is measurably expensive — ~540ms of Style & Layout on the long
   home page — and it only earns its cost on large display type where a
   single orphaned word is visible. Restricted to h1/h2 for that reason. */
h1,h2{text-wrap:balance}
h1{font-size:clamp(2.4rem,1.5rem + 3.8vw,3.7rem); line-height:1.05}
h2{font-size:clamp(1.95rem,1.3rem + 2.5vw,2.9rem); line-height:1.12; color:var(--teal)}
h3{font-size:clamp(1.2rem,1.08rem + .55vw,1.45rem); line-height:1.25}
h4{font-size:1.05rem; line-height:1.4}
p{margin:0; max-width:65ch}
img{max-width:100%; display:block}
ul,ol{margin:0}
code{font-family:ui-monospace,Consolas,monospace; font-size:.9em; background:var(--sunk); padding:.1em .35em; border-radius:4px}

/* 3. ACCESSIBILITY ========================================================= */
.skip{
  position:absolute; left:-9999px; top:0; z-index:100;
  background:var(--teal); color:#fff; padding:.75rem 1.25rem;
  border-radius:0 0 var(--r-sm) 0; font-weight:700; text-decoration:none;
}
.skip:focus{left:0}
:focus-visible{outline:3px solid var(--teal); outline-offset:2px; border-radius:2px}
/* Sticky header must never cover the element you just jumped to (WCAG 2.4.11) */
[id]{scroll-margin-top:calc(var(--head-h) + 1rem)}
@media(min-width:1181px){[id]{scroll-margin-top:calc(var(--head-h-wide) + 1rem)}}
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

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

/* 4. LAYOUT ================================================================ */
.wrap{width:min(100% - 2.5rem,var(--wrap)); margin-inline:auto}
/* Sections carried 96px top and bottom at desktop width, which on the home
   page alone was 1388px of padding -- 19% of the page. Halved-and-a-bit to
   57.6px. Nothing is removed; the page simply stops holding its content at
   arm's length. */
.section{padding-block:clamp(2.25rem,4.2vw,3.6rem)}
.section--sunk{background:var(--sunk)}
.section--wash{background:var(--teal-wash)}
.section--sage{background:var(--sage-wash)}

[data-accent="gold"]{--accent:var(--gold-accent)}  /* Training  — 5.51:1 worst */
[data-accent="sage"]{--accent:var(--sage-deep)}   /* School    — 7.19:1 ivory */
[data-accent="clay"]{--accent:var(--coral-deep)}  /* Why it matters — 5.07:1 */

/* The reach section is frozen by instruction, and the accent system would
   otherwise have recoloured its eyebrow from sage to teal. Pinned back, so
   that section renders pixel-for-pixel as it did before this pass. */
.reach .eyebrow{color:var(--sage-deep)}
.eyebrow{
  font-size:.8125rem; font-weight:700; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent); margin:0 0 var(--s3);
}
.lede{font-size:clamp(1.06rem,1.02rem + .35vw,1.3rem); color:var(--muted); line-height:1.5;
  max-width:64ch}

.grid{display:grid; gap:var(--s5); grid-template-columns:repeat(auto-fit,minmax(270px,1fr)); margin-top:var(--s7)}
.grid--tight{gap:var(--s4); grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}

/* --- how many columns, given how many cards ------------------------------
   auto-fit fills the row with as many tracks as fit, which at desktop width
   is four, five or six. Nine cards then land as six and three; six land as
   five and one, one card marooned beside four empty columns. That is what
   made these sections look broken rather than airy.

   So the column count is chosen from the number of cards instead, picking a
   divisor where one exists and a near-divisor otherwise. :has(> :nth-child(N):
   last-child) is "exactly N children" -- the Nth child is also the last.
   Below 900px the auto-fit rule above still governs, which is what should
   happen: on a phone these stack whatever the count. */
@media (min-width:900px){
  .grid:has(> :nth-child(2):last-child),
  .grid:has(> :nth-child(4):last-child)   {grid-template-columns:repeat(2,minmax(0,1fr))}
  .grid:has(> :nth-child(3):last-child),
  .grid:has(> :nth-child(5):last-child),
  .grid:has(> :nth-child(6):last-child),
  .grid:has(> :nth-child(9):last-child)   {grid-template-columns:repeat(3,minmax(0,1fr))}
  .grid:has(> :nth-child(7):last-child),
  .grid:has(> :nth-child(8):last-child)   {grid-template-columns:repeat(4,minmax(0,1fr))}

  /* The tight variant carries smaller cards, so it takes one more column
     wherever the count allows it. */
  .grid--tight:has(> :nth-child(4):last-child)   {grid-template-columns:repeat(4,minmax(0,1fr))}
  .grid--tight:has(> :nth-child(8):last-child)   {grid-template-columns:repeat(4,minmax(0,1fr))}
  .grid--tight:has(> :nth-child(9):last-child)   {grid-template-columns:repeat(3,minmax(0,1fr))}

  .steps:has(> :nth-child(6):last-child)  {grid-template-columns:repeat(3,minmax(0,1fr))}
  .steps:has(> :nth-child(4):last-child)  {grid-template-columns:repeat(2,minmax(0,1fr))}
  .steps:has(> :nth-child(5):last-child)  {grid-template-columns:repeat(3,minmax(0,1fr))}
  .steps:has(> :nth-child(7):last-child)  {grid-template-columns:repeat(4,minmax(0,1fr))}

  .doors:has(> :nth-child(2):last-child)  {grid-template-columns:repeat(2,minmax(0,1fr))}
}
.two{display:grid; gap:clamp(2rem,5vw,4rem); grid-template-columns:1fr; align-items:start}
@media(min-width:880px){
  .two{grid-template-columns:1fr 1fr}
  .two--narrow{grid-template-columns:.85fr 1.15fr}
  /* When the narrow column holds a portrait, size the column to the portrait
     rather than the other way round. At .85fr the column came out 535px wide
     around a photograph capped at 320px, leaving 215px of nothing between the
     face and the text that belongs to it. */
  .two--narrow:has(.portrait){grid-template-columns:minmax(0,340px) minmax(0,1fr)}
}

/* 5. HEADER & NAV ========================================================== */
.head{
  position:sticky; top:0; z-index:50;
  background:rgba(249,247,242,.94); backdrop-filter:blur(10px);
  border-bottom:1px solid var(--line);
}
/* Two rows on wide screens: the mark and the call to action sit on the top
   row, and the full navigation runs beneath. Twelve items cannot share a
   single row with the logo without either shrinking the type or hiding
   pages, and the brief is that every page is reachable from the nav. Below
   the breakpoint this collapses back to one row plus the drawer. */
.head__in{
  display:flex; align-items:center; gap:var(--s5);
  min-height:var(--head-h); position:relative;
}
@media(min-width:1181px){
  .head__in{
    display:grid; grid-template-columns:auto 1fr auto;
    grid-template-areas:"logo . cta" "nav nav nav";
    row-gap:.55rem; padding-block:.85rem 0;
  }
  .head__in > .logo{grid-area:logo}
  .head__in > .btn--head{grid-area:cta; justify-self:end}
  /* A hairline between the two rows so the nav reads as its own band rather
     than as text floating under the logo. */
  .head__in > .nav{
    grid-area:nav; border-top:1px solid var(--line);
    padding-top:.15rem; margin-top:.1rem;
  }
}
/* No wordmark beside it: the logo already spells the name, and setting it
   twice made the mark read as an icon in front of a heading rather than as
   the identity of the site. With the text gone the mark takes the room --
   64px on a phone, 76px once the header goes to two rows. The link keeps its
   accessible name from the image's alt text. */
.logo{text-decoration:none; margin-right:auto; display:flex; align-items:center; color:var(--teal)}
.logo img{height:64px; width:auto; flex:none}
@media(min-width:1181px){ .logo img{height:76px} }

.nav{display:flex; gap:.1rem; align-items:center}
@media(min-width:1181px){
  .nav{gap:0; justify-content:space-between; width:100%; padding-bottom:.15rem}
  .nav a{
    font-size:.92rem; padding:.62rem .45rem .55rem; white-space:nowrap;
    letter-spacing:.005em;
  }
  .nav a::after{left:.45rem; right:.45rem; bottom:.18rem}
  /* The active item gets the gold rule, matching the credential accent used
     everywhere else for "this is the verified one". */
  /* --gold is 2.12:1 on the header ground, below the 3:1 a state indicator
     needs. --gold-deep is 4.59:1 and still reads as gold. */
  .nav a[aria-current]::after{background:var(--gold-deep)}
}
.nav a{
  position:relative; font-size:.98rem; color:var(--charcoal);
  text-decoration:none; padding:.55rem .6rem; border-radius:var(--r-sm);
}
.nav a::after{
  content:""; position:absolute; left:.6rem; right:.6rem; bottom:.3rem; height:2px;
  background:var(--teal); transform:scaleX(0); transform-origin:left center;
  transition:transform .2s ease-out;
}
.nav a:hover{color:var(--teal)}
.nav a:hover::after{transform:scaleX(1)}
.nav a[aria-current]{color:var(--teal); font-weight:700}
.nav a[aria-current]::after{transform:scaleX(1)}

.nav-toggle{
  display:none; align-items:center; justify-content:center;
  min-height:48px; min-width:48px; padding:0 .9rem;
  border-radius:var(--r-sm); background:transparent; border:2px solid var(--teal);
  color:var(--teal); font-family:var(--font); font-weight:700; font-size:1rem; cursor:pointer;
}
@media(min-width:1001px){ .nav .btn{display:none} }
/* The drawer used to take over at 1000px. With nine nav items the inline row
   wraps to two lines between about 1000 and 1180px, which looks like a bug,
   so the drawer now takes over earlier. */
@media(max-width:1180px){
  .nav-toggle{display:inline-flex}
  .btn--head{display:none}
  .nav{
    display:none; position:absolute; left:0; right:0; top:100%;
    flex-direction:column; align-items:stretch; gap:0;
    background:var(--cream); border-bottom:1px solid var(--line);
    box-shadow:var(--e2); padding:var(--s3);
    max-height:calc(100dvh - var(--head-h)); overflow-y:auto;
  }
  .nav.is-open{display:flex}
  .nav a{padding:.9rem 1rem; font-size:1.1rem; border-bottom:1px solid var(--line)}
  .nav a::after{display:none}
  .nav a[aria-current]{background:var(--teal-wash)}
  .nav .btn{margin-top:var(--s3); border-bottom:0}
}

.progress{
  position:fixed; inset:0 0 auto 0; height:3px; background:var(--gold-deep);
  transform:scaleX(0); transform-origin:left center; z-index:60;
}

/* 6. BUTTONS & LINKS ======================================================= */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  min-height:48px; padding:.8rem 1.6rem; border-radius:var(--r-pill);
  font-family:var(--font); font-weight:700; font-size:1rem;
  text-decoration:none; border:2px solid transparent; cursor:pointer;
  transition:background-color .2s,color .2s,transform .2s,box-shadow .2s;
}
.btn--primary{background:var(--teal); color:#fff; box-shadow:var(--e1)}
.btn--primary:hover{background:var(--gold); color:var(--teal-deep);
  transform:translateY(-2px); box-shadow:var(--e2)}
.btn--primary:active{transform:translateY(0)}
.btn--ghost{background:transparent; color:var(--teal); border-color:var(--teal)}
.btn--ghost:hover{background:var(--teal-wash)}
.btn--wa{background:var(--sage-deep); color:#fff}
.btn--wa:hover{background:var(--teal); transform:translateY(-2px)}
.btn[disabled],.btn[aria-busy="true"]{opacity:.7; cursor:not-allowed; transform:none}

.prose a{color:var(--teal); text-underline-offset:3px}
.prose a:hover{color:var(--gold-link-hover)}

/* 7. COMPONENTS ============================================================ */
.card{
  background:var(--white); border:1px solid var(--line); border-radius:var(--r-md);
  padding:var(--s6); box-shadow:var(--e1);
  display:flex; flex-direction:column; gap:var(--s3);
  transition:transform .2s,box-shadow .2s,border-color .2s;
}
.card:hover{transform:translateY(-6px); box-shadow:var(--e2); border-color:var(--teal)}
.card__plate{width:52px; height:52px; border-radius:var(--r-md); background:var(--teal-wash); display:grid; place-items:center; color:var(--teal)}
.card--b .card__plate{background:var(--sage-wash); color:var(--sage-deep)}
.card--c .card__plate{background:var(--coral-wash); color:var(--coral-deep)}
.card p{font-size:.98rem; color:var(--muted)}
/* Forward link. Was scoped to .card; the doors and the Why-it-matters index
   use it too, so it is now a standalone component. Without this the links in
   those sections fell back to the browser's default blue. */
.more{font-weight:700; color:var(--teal); text-decoration:none; padding-top:var(--s3);
  display:inline-flex; gap:.4rem; align-items:center}
.card .more{margin-top:auto}
.door--sage .more{color:var(--sage-deep)}
.door--gold .more{color:var(--gold-deep)}
.more:hover,.more:focus-visible{color:var(--gold-link-hover)}
.more::after{content:"\2192"; transition:transform .2s}
.more:hover::after,.more:focus-visible::after{transform:translateX(3px)}

.mini{background:var(--white); border:1px solid var(--line); border-radius:var(--r-md); padding:var(--s5)}
.mini h3{font-size:1.05rem; color:var(--teal); margin-bottom:.3rem}
.mini p{font-size:.95rem; color:var(--muted)}

.path{
  background:var(--white); border:1px solid var(--line); border-radius:var(--r-md);
  border-left:5px solid var(--teal); padding:var(--s6); box-shadow:var(--e1);
  display:flex; flex-direction:column; gap:var(--s3);
  transition:transform .2s,box-shadow .2s;
}
.path--pro{border-left-color:var(--sage-deep)}
.path:hover{transform:translateY(-4px); box-shadow:var(--e2)}
.path__who{font-size:.8rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:var(--teal)}
.path--pro .path__who{color:var(--sage-deep)}
.path p{color:var(--muted); font-size:1rem}
.path .btn{align-self:flex-start; margin-top:var(--s3)}

/* Credential block — gold is reserved for verifiable certification */
.cred{
  background:var(--white); border:1px solid var(--line); border-top:4px solid var(--gold);
  border-radius:var(--r-md); padding:clamp(1.5rem,4vw,2.5rem); box-shadow:var(--e1);
  display:grid; gap:clamp(1.5rem,4vw,2.5rem); grid-template-columns:1fr; align-items:center;
}
@media(min-width:760px){.cred{grid-template-columns:auto 1fr}}
.cred__seal{
  width:120px; height:120px; border-radius:50%; background:#FDF8E8;
  border:2px solid var(--gold); display:grid; place-items:center; text-align:center;
  color:var(--gold-deep); font-weight:700; line-height:1.15; justify-self:start;
}
.cred__seal b{display:block; font-size:1.7rem}
.cred__seal span{font-size:.62rem; letter-spacing:.08em; text-transform:uppercase}
.cred h3{color:var(--teal)}
.cred__meta{list-style:none; margin:1.1rem 0 0; padding:0; display:grid; gap:.45rem; grid-template-columns:1fr; font-size:.95rem}
@media(min-width:520px){.cred__meta{grid-template-columns:1fr 1fr; gap:.5rem 1.5rem}}
.cred__meta li{display:flex; gap:.5rem; flex-wrap:wrap}
.cred__meta dfn{font-style:normal; color:var(--muted); min-width:8.5em}
.cred__meta b{font-variant-numeric:tabular-nums}
.cred__link{display:inline-flex; align-items:center; gap:.45rem; margin-top:1.1rem; color:var(--teal); font-weight:700; text-decoration:underline; text-underline-offset:3px}
.cred__link:hover{color:var(--gold-link-hover)}

.auths{display:grid; gap:var(--s4); grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); margin-top:var(--s6)}
.auth{background:var(--white); border:1px solid var(--line); border-left:4px solid var(--gold); border-radius:var(--r-sm); padding:var(--s5)}
.auth h3{font-size:1.02rem; color:var(--gold-deep); margin-bottom:.2rem}
.auth p{font-size:.93rem; color:var(--muted)}

.ticks{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--s3)}
.ticks li{display:flex; gap:.7rem; align-items:flex-start}
.ticks svg{flex:none; width:22px; height:22px; color:var(--sage-deep); margin-top:.28em}

.steps{display:grid; gap:var(--s5); grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); margin-top:var(--s7)}
.step{background:var(--white); border:1px solid var(--line); border-radius:var(--r-md); padding:var(--s5)}
.step__n{width:40px; height:40px; border-radius:50%; background:var(--teal); color:#fff; display:grid; place-items:center; font-weight:700; margin-bottom:var(--s3)}
.step h3{font-size:1.05rem; color:var(--teal); margin-bottom:.3rem}
.step p{font-size:.95rem; color:var(--muted)}

.quote{background:var(--white); border:1px solid var(--line); border-radius:var(--r-md); padding:var(--s6); display:flex; flex-direction:column; gap:var(--s4)}
.quote blockquote{margin:0; font-size:1.08rem; font-style:italic}
.quote figcaption{font-size:.93rem; color:var(--muted)}

.post{background:var(--white); border:1px solid var(--line); border-radius:var(--r-md); padding:var(--s5); display:flex; flex-direction:column; gap:.5rem}
.post .kind{font-size:.75rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--sage-deep)}
.post h3{font-size:1.08rem; color:var(--teal)}
.post p{font-size:.94rem; color:var(--muted)}

/* Placeholder marker — this site never fabricates facts.
   Styled in 37.8: a dashed terracotta box on every one of them made a
   finished site read as broken, and there are three dozen. */
.note{border-left:4px solid var(--gold); background:#FDF8E8; border-radius:0 var(--r-sm) var(--r-sm) 0; padding:var(--s4) var(--s5); font-size:.95rem; color:#5C4A12; max-width:70ch}
.note strong{color:var(--gold-deep)}

/* 8. PAGE SECTIONS ========================================================= */
/* Hero. Deliberately sparse: eyebrow, headline, one line, two choices,
   and a way down. Everything the page used to stack above the fold now
   sits below it. A first screen with fifteen things on it asks the
   visitor to make a decision before they have read anything. */
.hero{padding-block:clamp(2.5rem,5.6vw,4.4rem) clamp(2rem,4.2vw,3.2rem)}
.hero h1{max-width:15ch}
.hero__lede{margin-top:var(--s4); max-width:46ch}
.hero__acts{display:flex; flex-wrap:wrap; gap:var(--s4);
  margin-top:clamp(1.4rem,3vw,2rem)}

/* Scroll cue. Static — a looping bounce would violate the motion budget,
   and this audience is exactly who that budget protects. It moves only
   on hover, which the visitor initiates. */
.cue{display:inline-flex; align-items:center; gap:.5rem;
  margin-top:clamp(2.5rem,6vw,4rem); font-size:.85rem; font-weight:700;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted);
  text-decoration:none}
.cue svg{width:18px; height:18px; transition:transform .25s cubic-bezier(.2,.7,.3,1)}
.cue:hover,.cue:focus-visible{color:var(--teal-deep)}
.cue:hover svg,.cue:focus-visible svg{transform:translateY(3px)}

/* Credentials band — a thin strip between hero and content, not a block
   competing inside the hero itself. */
.band{background:var(--white); border-block:1px solid var(--line);
  padding-block:clamp(1rem,2.5vw,1.4rem)}
.band .trust{margin-top:0; padding-top:0; border-top:0}

.fork{display:grid; gap:var(--s5); grid-template-columns:1fr; margin-top:var(--s7)}
@media(min-width:820px){.fork{grid-template-columns:1fr 1fr}}

.trust{display:flex; flex-wrap:wrap; gap:var(--s3) var(--s6); margin:0; padding:0; list-style:none; justify-content:space-between}
.trust li{display:flex; align-items:center; gap:.55rem; font-weight:700; font-size:.95rem; color:var(--teal)}
.trust svg{flex:none; width:20px; height:20px; color:var(--gold-deep)}

/* Page banner for inner pages */
.banner{background:var(--teal-wash); border-bottom:1px solid var(--line); padding-block:clamp(2rem,4vw,3.05rem)}
.banner h1{font-size:clamp(2rem,1.3rem + 2.8vw,3rem); color:var(--teal)}
.banner p{margin-top:var(--s4)}
.crumbs{font-size:.9rem; color:var(--muted); margin-bottom:var(--s4)}
.crumbs a{color:var(--teal)}

.photo{
  aspect-ratio:4/3; border-radius:var(--r-md); border:2px dashed var(--teal);
  background:var(--teal-wash); display:grid; place-items:center; text-align:center;
  padding:var(--s5); color:var(--teal);
}
.photo--portrait{aspect-ratio:3/4}
.photo span{font-weight:700; max-width:28ch}

.vision{background:var(--teal); color:#fff; border-radius:var(--r-lg); padding:clamp(1.75rem,5vw,3.5rem)}
.vision h2{color:#fff}
.vision p{color:#DCEAEC}
.vision .eyebrow{color:#BFD9C6}
.vision .btn--primary{background:#fff; color:var(--teal)}
.vision .btn--primary:hover{background:var(--coral-deep); color:#fff}
.vision .btn--ghost{color:#fff; border-color:rgba(255,255,255,.6)}
.vision .btn--ghost:hover{background:rgba(255,255,255,.12)}
.vision .tbd{background:rgba(0,0,0,.30); border-color:#F5C4B7; color:#FFD9CF}
.vision__acts{display:flex; flex-wrap:wrap; gap:var(--s4); margin-top:var(--s6)}

/* What the centre provides free — cards inside the teal vision panel.
   Contrast on the composited background (10% white over --teal, #356F7A):
   #fff 5.67:1, #EAF3F4 5.03:1. Both pass AA. Do not lighten the panel
   further without recomputing — every gain in panel lightness is a loss
   of contrast for the text on it. */
.gives{display:grid; gap:var(--s4); margin-top:var(--s6);
  grid-template-columns:repeat(auto-fit,minmax(215px,1fr))}
.give{background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.22);
  border-radius:var(--r-md); padding:var(--s5)}
.give__ic{width:40px; height:40px; border-radius:var(--r-sm); display:grid;
  place-items:center; background:rgba(255,255,255,.14); color:#fff; margin-bottom:var(--s4)}
.give h3{color:#fff; font-size:1.05rem}
.vision .give p{color:#EAF3F4; font-size:.94rem; margin-top:.35rem}

/* Evidence figures — big number, then what it means. Numbers use --teal
   (7.4:1 on --white); never --sage/--coral/--gold, which are fills only. */
.stats{display:grid; gap:var(--s4); margin-top:var(--s7);
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.stat{background:var(--white); border:1px solid var(--line); border-left:4px solid var(--teal);
  border-radius:var(--r-md); padding:var(--s5)}
.stat b{display:block; font-size:clamp(2rem,5vw,2.9rem); line-height:1.05; color:var(--teal);
  font-weight:700; letter-spacing:0}
.stat span{display:block; margin-top:var(--s3); font-size:.95rem; color:var(--charcoal)}
.stat cite{display:block; margin-top:var(--s3); font-size:.82rem; color:var(--muted); font-style:normal}

/* Source list. Small, but present — an unsourced statistic on a donations
   page is worth less than no statistic at all. */
.cites{margin-top:var(--s6); padding-top:var(--s5); border-top:1px solid var(--line);
  font-size:.85rem; color:var(--muted); line-height:1.65}
.cites li{margin-top:var(--s3)}
.cites a{color:var(--teal-deep)}

/* The handoff's 5-cell asymmetric gallery: a tall feature cell on the left
   spanning both rows, then a 2x2 of smaller frames. Collapses to two
   columns, then one, on narrow screens. */
.gal{display:grid; gap:var(--s4); margin-top:var(--s7); grid-template-columns:1fr}
@media(min-width:600px){.gal{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:900px){
  .gal{grid-template-columns:minmax(0,2fr) minmax(0,1fr) minmax(0,1fr);
       grid-auto-rows:168px}
  .gal > *:first-child{grid-row:span 2}
}
.gal div{aspect-ratio:1; border-radius:var(--r-md); border:2px dashed var(--sage-deep); background:var(--sage-wash); display:grid; place-items:center; text-align:center; padding:var(--s4); color:var(--sage-deep); font-weight:700; font-size:.92rem}

.contact{display:grid; gap:clamp(2rem,5vw,3.5rem); grid-template-columns:1fr}
@media(min-width:880px){.contact{grid-template-columns:.9fr 1.1fr}}
.channels{display:flex; flex-direction:column; gap:var(--s4)}
.chan{background:var(--white); border:1px solid var(--line); border-radius:var(--r-md); padding:var(--s5); display:flex; gap:var(--s4); align-items:flex-start}
/* A flex or grid child defaults to min-width:auto, so it never shrinks below
   its longest unbreakable word. The email address is one 26-character token,
   which pushed the contact panel 23px past a 320px viewport -- still a real
   screen width on older Android, which is much of this audience. */
.chan,.chan > *{min-width:0}
.chan a,.chan p{overflow-wrap:anywhere}
.enquiry,.enquiry .field,.enquiry .field > *{min-width:0}

.chan__ic{width:44px; height:44px; flex:none; border-radius:var(--r-sm); background:var(--sage-wash); color:var(--sage-deep); display:grid; place-items:center}
.chan h3{font-size:1.02rem; color:var(--teal)}
.chan p{font-size:.95rem; color:var(--muted); margin-top:.15rem}
.chan a{color:var(--teal); font-weight:700}

/* Forms — visible labels always; placeholders are not labels */
form.enquiry{background:var(--white); border:1px solid var(--line); border-radius:var(--r-md); padding:var(--s6)}
.field{display:flex; flex-direction:column; gap:.4rem; margin-bottom:var(--s4)}
label{font-weight:700; font-size:.98rem}
label .opt{font-weight:400; color:var(--muted)}
input,textarea,select{
  font-family:inherit; font-size:1rem; min-height:48px; padding:.7rem .9rem;
  background:var(--sunk); border:1.5px solid #D8D3C8; border-radius:var(--r-sm);
  color:var(--charcoal); width:100%;
}
textarea{min-height:120px; resize:vertical}
input:focus,textarea:focus,select:focus{outline:none; border-color:var(--teal); box-shadow:0 0 0 3px rgba(31,95,107,.18)}
input[aria-invalid="true"],textarea[aria-invalid="true"]{border-color:var(--error); background:var(--coral-wash)}
.hint{font-size:.9rem; color:var(--muted)}
/* Errors are text, never colour alone, and never a shake animation */
.err{font-size:.9rem; color:var(--error); font-weight:700}
.err:empty{display:none}
.form-status{margin-top:var(--s4); padding:var(--s4); border-radius:var(--r-sm); font-weight:700}
.form-status:empty{display:none; padding:0}
.form-status--ok{background:var(--sage-wash); color:var(--sage-deep); border:1px solid var(--sage-deep)}
.form-status--bad{background:var(--coral-wash); color:var(--error); border:1px solid var(--error)}
form.enquiry .btn{width:100%; margin-top:var(--s3)}
/* Honeypot — hidden from people, visible to naive bots */
.hp{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}

/* 9. FOOTER ================================================================ */
.foot{background:var(--teal); color:#fff; padding-block:var(--s8) var(--s6); margin-top:var(--s9)}
.foot a{color:#CFE6EA}
.foot__grid{display:grid; gap:var(--s6); grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.foot h3{font-size:.98rem; margin-bottom:var(--s3); color:#fff}
.foot ul{list-style:none; padding:0; display:flex; flex-direction:column; gap:.5rem; font-size:.95rem}
.foot p{font-size:.95rem; color:#CFE6EA}
.foot__bar{margin-top:var(--s7); padding-top:var(--s5); border-top:1px solid rgba(255,255,255,.2); font-size:.9rem; color:#CFE6EA; display:flex; flex-wrap:wrap; gap:var(--s4); justify-content:space-between}

/* 10. UTILITIES ============================================================ */
.mt1{margin-top:.85rem} .mt2{margin-top:1.5rem} .mt3{margin-top:2.15rem}
/* Centring a block is not enough on its own: p has max-width:65ch, so a
   centred paragraph is a narrow box pinned to the left edge and anything
   inside it — a button, especially — centres within that box rather than on
   the page. Auto-margin every direct child so .center actually centres. */
.center{text-align:center}
.center > *{margin-inline:auto}
.stack > * + *{margin-top:var(--s4)}

/* Reveal: visible at rest. JS opts elements into starting hidden, so if the
   script never runs nothing is ever invisible. */
[data-reveal]{opacity:1}
.js [data-reveal]{opacity:0; transform:translateY(14px);
  transition:opacity .5s ease-out, transform .5s ease-out; transition-delay:0s}
/* Members of a group come in one after another. The delay applies only on the
   way in -- on the way out the base rule above wins, so a section leaving the
   viewport does not unravel one card at a time. */
.js [data-reveal].in{transition-delay:calc(var(--i, 0) * 55ms)}
.js [data-reveal].in{opacity:1; transform:none}

/* 11. HELPER CLASSES ======================================================= */
/* These replace inline styles so the pages pass html-validate and so a
   Content-Security-Policy without 'unsafe-inline' for style would still work. */
.mx-auto{margin-inline:auto}
.mb2{margin-bottom:1.15rem}
.t-teal{color:var(--teal)}
.h-sub{font-size:1.45rem}
.h-form{font-size:1.5rem}
.fs-sm{font-size:.95rem}
.map{aspect-ratio:16/7}
.foot__bar--bare{margin-top:0; border-top:0; padding-top:0}

/* 12. VIEW TRANSITIONS ===================================================== */
/* Cross-document page transitions, native and framework-free. Chromium and
   Safari 18.2+ honour this; everything else simply navigates normally, so it
   is pure progressive enhancement.

   Deliberately a CROSS-FADE ONLY — no slide, no scale. Movement between pages
   is the part that causes vestibular problems; a change in opacity does not.
   Kept short (220ms) so it never feels like waiting. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root){
  animation-duration:.22s;
  animation-timing-function:ease;
}

/* The header is visually identical across pages, so hold it still rather than
   cross-fading it with the rest — otherwise it appears to flicker. */
.head{ view-transition-name:site-header; }

@media (prefers-reduced-motion: reduce){
  @view-transition { navigation: none; }
}

/* 13. REGISTRATION FORMS =================================================== */
fieldset{
  border:1px solid var(--line); border-radius:var(--r-sm);
  padding:var(--s5); margin:0 0 var(--s5);
}
legend{
  font-weight:700; font-size:.98rem; padding:0 .5rem; color:var(--teal);
}
.choices{display:grid; gap:.6rem; grid-template-columns:1fr}
@media(min-width:520px){.choices{grid-template-columns:1fr 1fr}}
.choice{
  display:flex; align-items:flex-start; gap:.6rem;
  padding:.7rem .8rem; border:1.5px solid #D8D3C8; border-radius:var(--r-sm);
  background:var(--sunk); cursor:pointer; min-height:48px;
  transition:border-color .15s, background-color .15s;
}
.choice:hover{border-color:var(--teal)}
.choice input{
  width:20px; height:20px; min-height:0; flex:none; margin-top:.15rem;
  accent-color:var(--teal); padding:0;
}
.choice span{font-size:.97rem; line-height:1.4}
.choice:has(input:checked){border-color:var(--teal); background:var(--teal-wash)}
.choice:has(input:focus-visible){outline:3px solid var(--teal); outline-offset:2px}

.consent{
  display:flex; align-items:flex-start; gap:.7rem;
  padding:var(--s4); border:1.5px solid var(--line); border-radius:var(--r-sm);
  background:var(--sunk); margin-bottom:var(--s4);
}
.consent input{width:20px; height:20px; min-height:0; flex:none; margin-top:.2rem; accent-color:var(--teal); padding:0}
.consent label{font-weight:400; font-size:.95rem; line-height:1.5}

/* Two registration tracks on one page, kept visually distinct so a parent and
   a prospective trainee never feel they are reading each other's form. */
.track{
  background:var(--white); border:1px solid var(--line);
  border-top:5px solid var(--teal); border-radius:var(--r-md);
  padding:clamp(1.5rem,4vw,2.5rem); box-shadow:var(--e1);
}
.track--pro{border-top-color:var(--sage-deep)}
.track > h2{font-size:clamp(1.5rem,1.2rem + 1vw,1.9rem)}
.track .enquiry{background:transparent; border:0; padding:0; margin-top:var(--s5)}
.track-nav{display:flex; flex-wrap:wrap; gap:var(--s4); margin-top:var(--s6)}

/* 14. MOTION CRAFT ========================================================= */
/* Added depth without breaking the budget: every effect below is user- or
   scroll-initiated, moves <=14px, runs once, and animates only transform,
   opacity or background-size. Nothing loops. Nothing moves on its own. */

/* --- headline word reveal ------------------------------------------------
   Words rise and fade in sequence. This is where the typographic personality
   lives, and it costs nothing in layout because the words are inline-block
   and never reflow. JS sets the per-word delay; the cap is 8 words so the
   line always finishes inside ~350ms. */
.js [data-split] .w{
  display:inline-block;
  opacity:0;
  transform:translateY(14px);
  transition:opacity .42s cubic-bezier(.2,.7,.3,1), transform .42s cubic-bezier(.2,.7,.3,1);
  will-change:transform,opacity;
}
.js [data-split].in .w{opacity:1; transform:none; will-change:auto}

/* --- button fill sweep ---------------------------------------------------
   The hover colour wipes across instead of switching flatly. Done with
   background-size so there is no extra element and no stacking-context risk;
   the end state is identical to before, so contrast is unchanged. */
.btn--primary{
  background-image:linear-gradient(var(--gold),var(--gold));
  background-repeat:no-repeat;
  background-size:0% 100%;
  transition:background-size .3s cubic-bezier(.2,.7,.3,1), transform .2s, box-shadow .2s, color .2s;
}
.btn--primary:hover,.btn--primary:focus-visible{background-size:100% 100%}
.btn--ghost{
  background-image:linear-gradient(var(--teal-wash),var(--teal-wash));
  background-repeat:no-repeat;
  background-size:0% 100%;
  transition:background-size .3s cubic-bezier(.2,.7,.3,1), transform .2s, box-shadow .2s;
}
.btn--ghost:hover,.btn--ghost:focus-visible{background-size:100% 100%}

/* --- card interior response ---------------------------------------------- */
.card__plate{transition:transform .25s cubic-bezier(.2,.7,.3,1), background-color .25s}
.card:hover .card__plate{transform:translateY(-3px)}
.card:hover .card__plate{background:var(--teal); color:#fff}
.card--b:hover .card__plate{background:var(--sage-deep); color:#fff}
.card--c:hover .card__plate{background:var(--coral-deep); color:#fff}

/* --- header entrance ----------------------------------------------------- */
@keyframes hope-head-in{from{opacity:0; transform:translateY(-6px)} to{opacity:1; transform:none}}
.js .head__in > *{animation:hope-head-in .45s cubic-bezier(.2,.7,.3,1) both}
.js .head__in > *:nth-child(2){animation-delay:.06s}
.js .head__in > *:nth-child(3){animation-delay:.12s}

/* --- trust strip --------------------------------------------------------- */
.trust li{transition:transform .2s cubic-bezier(.2,.7,.3,1)}
.trust li:hover{transform:translateY(-2px)}

/* --- in-page links ------------------------------------------------------- */
.prose a,.chan a,.cred__link{
  background-image:linear-gradient(currentColor,currentColor);
  background-repeat:no-repeat;
  background-position:0 100%;
  background-size:0% 1.5px;
  transition:background-size .25s cubic-bezier(.2,.7,.3,1), color .2s;
  text-decoration:none;
}
.prose a:hover,.chan a:hover,.cred__link:hover{background-size:100% 1.5px}

/* Everything above is switched off wholesale by the reduced-motion block in
   section 3, which zeroes all animation and transition durations. */
@media (prefers-reduced-motion: reduce){
  .js [data-split] .w{opacity:1 !important; transform:none !important}
}

/* 15. WORLD REACH MAP =======================================================
   Rebuilt from design/HopeReachMap.dc.html. Geometry and layer flags come
   from tools/genreach.py; only behaviour lives in main.js.

   The rules the design fought for, kept:
     - The country interior is the only marker. No dots, no pins, no labels,
       no arcs. Emphasis is fill, never outline.
     - Strokes carry no data: one uniform hairline everywhere, cartographic.
     - Fills are set by script, not by CSS class, so the three state
       variables stay the single source of truth.
   ========================================================================== */
.reach{background:var(--cream)}

/* Contained, as the design draws it: a bordered, rounded frame sitting
   inside the page container rather than bleeding to the window edges. */
.reach__frame{
  position:relative; width:100%; margin-block:var(--s6);
  background:var(--cream);
  border:1px solid var(--line); border-radius:var(--r-lg);
  overflow:hidden;
}
.reach__svg{display:block; width:100%; height:auto; aspect-ratio:1000 / 406}

/* One hairline for every country, data-free by design. */
/* No fill here on purpose. The resting colour is a presentation attribute
   written by tools/genreach.py, so the map is correctly coloured with
   scripting off; main.js then drives state through style.fill, which beats
   both. A fill declaration in this rule would silently outrank the script. */
.reach__svg path[data-n]{stroke:#D6D1C4; stroke-width:.4}
.js .reach__svg path[data-n]{transition:fill .3s ease-out}
.reach__svg path[data-nav]{cursor:pointer}

/* Focus ring for keyboard navigation. The prototype had none — the handoff
   lists that as a gap to fix. Drawn as a stroke so it follows the country
   outline instead of boxing it. */
.reach__svg path[data-nav]:focus{outline:none}
.reach__svg path[data-nav]:focus-visible{
  outline:none; stroke:var(--teal-deep); stroke-width:2.4; paint-order:stroke;
}
.reach__hi{pointer-events:none}

.reach__legend{
  position:absolute; left:2.2%; bottom:5%; margin:0; padding:0; list-style:none;
  display:flex; flex-direction:column; gap:7px;
}
.reach__legend-head{
  font-size:9.5px; font-weight:700; letter-spacing:.16em;
  text-transform:uppercase; color:var(--muted);
}
.reach__legend li:not(.reach__legend-head){
  display:flex; align-items:center; gap:8px;
  font-size:12.5px; line-height:1.2; color:var(--charcoal);
}
/* Swatches are the exact resting map fills, so the key reads 1:1 against
   the map. Change one here and you must change REACH_LAYERS in main.js. */
.reach__swatch{
  width:17px; height:9px; border-radius:2px; flex:none;
  border:1px solid rgba(0,0,0,.06);
}
.reach__swatch--ip{background:#35646B}
.reach__swatch--tr{background:#A6B6A5}
.reach__swatch--th{background:#CF9789}
.reach__swatch--ib{background:#D9CDAE}
.reach__swatch--base{background:#DCD8CF}
.reach__key-note{color:var(--muted); font-size:11.5px}

.reach__panel{
  position:absolute; left:0; top:0; width:242px; visibility:hidden; opacity:0;
  background:var(--white); border:1px solid var(--line); border-radius:12px;
  box-shadow:var(--e2); overflow:hidden; pointer-events:none;
  transition:opacity .22s ease, transform .26s ease-out;
}
.reach__rule{height:2px; background:var(--gold)}
.reach__panel-in{padding:12px 15px 13px}
.reach__name{margin:0; font-size:16.5px; font-weight:700; line-height:1.2; color:var(--teal)}
.reach__panel-body{display:flex; flex-direction:column; gap:8px; margin-top:9px}
.reach__group-head{
  margin:0 0 4px; font-size:9.5px; font-weight:700; letter-spacing:.15em;
  text-transform:uppercase; color:var(--muted);
}
.reach__group-list{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:3px}
.reach__group-list li{display:flex; gap:7px; align-items:flex-start; font-size:12.5px; line-height:1.35}
.reach__dot{width:4px; height:4px; border-radius:50%; flex:none; margin-top:.5em; background:var(--dot)}

/* Legend filters are a cartographic key, not pills. */
.reach__filters{
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--s5);
  margin-top:var(--s5); padding-top:14px; border-top:1px solid var(--line);
}
.reach__filter{
  border:0; border-bottom:1.5px solid transparent; padding:4px 0;
  background:transparent; font-family:var(--font); font-size:15px;
  color:var(--muted); cursor:pointer; min-height:44px;
}
.reach__filter:hover{color:var(--teal)}
.reach__filter[aria-pressed="true"]{color:var(--teal); border-bottom-color:var(--teal); font-weight:700}
.reach__hint{margin-left:auto; font-size:13px; color:var(--muted)}

.reach__note{margin:14px 0 0; font-size:14px; line-height:1.6; color:var(--charcoal); max-width:96ch}

/* Country lists — the keyboard/screen-reader equivalent of the map, and the
   answer to the handoff's "map is mouse-only" gap. Closed by default: the
   browser skips layout for closed details content, and 97 chips at once is
   unreadable. */
.reach__more{margin-top:var(--s5)}
.reach__more summary{
  cursor:pointer; font-weight:700; color:var(--teal); padding:.45rem 0; font-size:.95rem;
}
.reach__more summary:hover{color:var(--teal-deep)}
.reach__chips{display:flex; flex-wrap:wrap; gap:.4rem; list-style:none; margin:var(--s3) 0 0; padding:0}
.reach__chip{
  cursor:pointer; font-family:var(--font); font-size:.85rem; font-weight:700;
  color:var(--teal); background:var(--white); border:1px solid var(--line);
  border-radius:var(--r-pill); padding:.3rem .7rem; min-height:32px;
}
.reach__chip:hover,.reach__chip:focus-visible{background:var(--teal-wash); border-color:var(--teal)}
.reach__chip[aria-current="true"]{background:var(--teal); color:var(--white); border-color:var(--teal)}

@media (prefers-reduced-motion: reduce){
  .js .reach__svg path[data-n]{transition:none}
  .reach__panel{transition:none}
}

@media (max-width:640px){
  .reach__legend{position:static; margin:var(--s4) 0 0; padding:0 var(--s4) var(--s4)}
  .reach__panel{display:none}
  .reach__hint{margin-left:0; flex-basis:100%}
}

/* 16. CHILDREN BAND ========================================================
   The silhouette artwork that opens the hero. Kept small and pale on
   purpose — it introduces the page, it does not shout at it.

   Twelve overlapping layers all paint the same image and each is clipped to
   one child's vertical strip, so together they reassemble the artwork
   exactly. clip-path also clips hit-testing, which is what gives a per-child
   hover without slicing the file into twelve images or tracing it to paths.

   aria-hidden: it is decoration. Everything it conveys is said in the
   headline underneath it. */
/* Two columns on desktop: words left, artwork right, both centred against
   each other. On narrow screens the art drops below the copy — it is
   decoration, so it should never push the headline off the first screen. */
.hero__grid{display:grid; gap:clamp(1.75rem,4vw,3.25rem);
  grid-template-columns:1fr; align-items:center}
@media(min-width:940px){
  .hero__grid{grid-template-columns:minmax(0,1fr) minmax(0,.95fr)}
}
.kids{
  position:relative; width:100%; max-width:540px; aspect-ratio:793 / 143;
  margin:0; justify-self:center;
}
.kid{
  position:absolute; inset:0;
  background:url("../img/children.png") center/100% 100% no-repeat;
  transition:filter .28s ease, transform .28s cubic-bezier(.2,.7,.3,1);
}
@supports (background-image:image-set(url("../img/children.webp") type("image/webp"))){
  .kid{background-image:image-set(url("../img/children.webp") type("image/webp"),
                                  url("../img/children.png") type("image/png"))}
}
/* A lift of 2px and a soft sage halo. Small enough to read as response
   rather than movement. */
.kid:hover{
  filter:drop-shadow(0 0 7px rgba(71,114,79,.55)) saturate(1.25) brightness(.94);
  transform:translateY(-2px);
}

/* One strip per child. Each extends 0.35% past its right boundary so
   sub-pixel rounding cannot leave a hairline seam between neighbours; the
   overlap is invisible because every layer paints the same image in the
   same place. The last strip is not extended - there is nothing to its
   right to cover. */
.kid:nth-child(1){clip-path:inset(0 90.697% 0 0.000%)}
.kid:nth-child(2){clip-path:inset(0 84.518% 0 8.953%)}
.kid:nth-child(3){clip-path:inset(0 76.699% 0 15.132%)}
.kid:nth-child(4){clip-path:inset(0 69.133% 0 22.951%)}
.kid:nth-child(5){clip-path:inset(0 59.297% 0 30.517%)}
.kid:nth-child(6){clip-path:inset(0 49.209% 0 40.353%)}
.kid:nth-child(7){clip-path:inset(0 42.777% 0 50.441%)}
.kid:nth-child(8){clip-path:inset(0 30.671% 0 56.873%)}
.kid:nth-child(9){clip-path:inset(0 17.431% 0 68.979%)}
.kid:nth-child(10){clip-path:inset(0 10.621% 0 82.219%)}
.kid:nth-child(11){clip-path:inset(0 5.829% 0 89.029%)}
.kid:nth-child(12){clip-path:inset(0 0.000% 0 93.821%)}
@media (prefers-reduced-motion: reduce){
  .kid{transition:none}
  .kid:hover{transform:none}
}

/* 17. SECTION ENTRANCE =====================================================
   Every section below the fold arrives with a short fade and a 22px rise as
   it is scrolled to. Transform and opacity only — both composited, so this
   costs no layout, which matters on a page this long.

   [data-sec] is set by the script, so with JS off nothing is ever hidden.
   The hero and the credentials band are excluded: they are already on screen
   when the page loads, and animating them would just delay first paint. */
.js [data-sec]{
  /* 14px, not the 22px this used to travel: the motion budget is a written
     accessibility constraint, not a preference, and the rest of the file
     already claims to honour it. */
  opacity:0; transform:translateY(14px);
  transition:opacity .55s cubic-bezier(.2,.7,.3,1),
             transform .55s cubic-bezier(.2,.7,.3,1);
}
.js [data-sec].in{opacity:1; transform:none}

@media (prefers-reduced-motion: reduce){
  .js [data-sec]{opacity:1 !important; transform:none !important; transition:none}
}

/* 18. WHY IT MATTERS ========================================================
   The two-card index at the top of the page, and the deep banner it sits
   under. Both are specific to this page; nothing else uses them. */
.banner--deep{background:var(--teal); border-bottom:0}
.banner--deep h1{color:var(--white)}
.banner--deep .lede{color:#CBE0E4}
.banner--deep .crumbs{color:var(--stone-muted)}
.banner--deep .crumbs a{color:var(--gold-on-teal)}

.grid--two{grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}

.idx{
  background:var(--white); border:1px solid var(--line);
  border-top:3px solid var(--teal); border-radius:var(--r-md);
  padding:clamp(1.5rem,3vw,2rem);
}
.idx--gold{border-top-color:var(--gold)}
.idx__n{
  font-size:.8125rem; font-weight:700; letter-spacing:.16em;
  color:var(--sage-deep); margin:0 0 var(--s3);
}
.idx--gold .idx__n{color:var(--gold-deep)}
.idx p{color:var(--muted); margin-top:var(--s3)}
.idx .more{margin-top:var(--s4)}

/* Volunteer terms — a definition list read as label/value rows. */
.terms{display:grid; gap:0; margin:0}
.terms > div{
  display:grid; gap:var(--s3); padding:var(--s4) 0;
  border-bottom:1px solid var(--line); grid-template-columns:1fr;
}
@media(min-width:640px){.terms > div{grid-template-columns:minmax(0,.4fr) minmax(0,1fr); align-items:baseline}}
.terms dt{font-weight:700; color:var(--teal); margin:0}
.terms dd{margin:0; color:var(--charcoal)}
.lbl{font-weight:700; margin:0 0 var(--s3)}

/* Pointer band — a teal strip with a gold hairline that sends the reader to
   the argument rather than restating it. Used on School and Therapy. */
.pointer{background:var(--teal); border-block:1px solid var(--gold)}
.pointer h2{color:var(--white)}
.pointer .lede{color:#CBE0E4}
.pointer .eyebrow{color:var(--gold-on-teal)}
.btn--gold{background:var(--gold); color:var(--teal-deep); border-color:var(--gold)}
.btn--gold:hover,.btn--gold:focus-visible{background:var(--white); border-color:var(--white); color:var(--teal-deep)}

/* 19. HOME — DOORS, TILES, PILLS, PORTRAIT =================================
   The three-door row, the vision stat tiles and the volunteer pills, from
   the handoff's Home screen. */
.doors{display:grid; gap:var(--s5); grid-template-columns:1fr; margin-top:var(--s7)}
@media(min-width:820px){.doors{grid-template-columns:repeat(3,minmax(0,1fr))}}
.door{
  background:var(--white); border:1px solid var(--line); border-radius:16px;
  overflow:hidden; display:flex; flex-direction:column;
  transition:transform .25s cubic-bezier(.2,.7,.3,1), box-shadow .25s ease, border-color .25s ease;
}
.door:hover{transform:translateY(-4px); box-shadow:var(--e2); border-color:var(--teal)}
.door--sage:hover{border-color:var(--sage-deep)}
.door--gold:hover{border-color:var(--gold-deep)}
/* 16:10 frame. A marked placeholder until real photographs arrive — the
   handoff's 31 images are Unsplash comps and the project rule is no stock
   photography of children. */
.door__img{
  aspect-ratio:16/10; display:grid; place-items:center; text-align:center;
  padding:var(--s4); background:var(--teal-wash); color:var(--teal);
  border-bottom:2px dashed var(--teal); font-size:.86rem; font-weight:700;
}
.door--sage .door__img{background:var(--sage-wash); color:var(--sage-deep); border-bottom-color:var(--sage-deep)}
.door--gold .door__img{background:#FAF6EE; color:var(--gold-deep); border-bottom-color:var(--gold-deep)}  /* 4.52:1 — #F6F0E2 gave only 4.29 */
.door__body{padding:26px; display:flex; flex-direction:column; gap:var(--s3); flex:1}
.door__who{
  font-size:.78rem; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--teal); margin:0;
}
.door--sage .door__who{color:var(--sage-deep)}
.door--gold .door__who{color:var(--gold-deep)}
.door h3{font-size:1.25rem}
.door p{color:var(--muted); font-size:.98rem; flex:1}
.door .more{margin-top:auto}

/* Vision stat tiles — white, 3px top rule alternating teal and gold. */
/* 2x2, as the handoff draws it — auto-fit gave a 3+1 row at this width. */
.tiles{
  display:grid; gap:var(--s4); list-style:none; margin:0; padding:0;
  grid-template-columns:1fr;
}
@media(min-width:520px){.tiles{grid-template-columns:repeat(2,minmax(0,1fr))}}
.tile{
  background:var(--white); border:1px solid var(--line);
  border-top:3px solid var(--teal); border-radius:var(--r-md); padding:var(--s5);
}
.tile--gold{border-top-color:var(--gold)}
.tile b{display:block; font-size:clamp(1.7rem,4vw,2.3rem); line-height:1.05; color:var(--teal); font-weight:700}
.tile--gold b{color:var(--gold-deep)}
.tile span{display:block; margin-top:var(--s3); font-size:.92rem; color:var(--charcoal)}

/* Volunteer route pills — labels, not links. */
.pills{display:flex; flex-wrap:wrap; gap:.5rem; list-style:none; margin:0; padding:0}
.pills li{
  border:1px solid var(--line); border-radius:var(--r-pill);
  padding:.4rem .9rem; font-size:.9rem; font-weight:700; color:var(--teal);
  background:var(--white);
}

/* Founder portrait — the one genuinely real photograph on the site. */
.portrait{display:block; max-width:320px; width:100%}
.portrait img{
  display:block; width:100%; height:auto; border-radius:18px;
  border:1px solid var(--line);
}

/* 20. PHOTO FRAMES =========================================================
   Images sit in a fixed-ratio frame so the page never reflows as they load;
   every one carries width/height or an aspect-ratio, and CLS stays at 0.

   .frame--comp marks a placeholder. These are the handoff's Unsplash comps,
   downloaded so the site can be seen as designed — they are NOT photographs
   of this centre, and the project rule is no stock photography of children.
   The badge is deliberately visible: remove the class, not the marker, when
   real photography replaces them. See assets/img/comps/CREDITS.md. */
.frame{position:relative; overflow:hidden; border-radius:18px; background:var(--sunk)}
.frame[data-ratio="16/10"]{aspect-ratio:16/10}
.frame img,.door__img img,.photo img,.gal img{
  width:100%; height:100%; object-fit:cover; display:block;
}
.frame--comp{position:relative}
.frame--comp::after{
  content:"placeholder"; position:absolute; left:8px; bottom:8px;
  font-size:10px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  background:rgba(15,59,67,.88); color:#fff; padding:3px 7px; border-radius:4px;
  pointer-events:none;
}
/* The frames these replace were dashed placeholder boxes; with a photograph
   in them the dashes and the centred label are no longer wanted. */
/* flex:none matters: .door is a column flex container, and without it the
   image frame can be stretched past its aspect ratio when the grid equalises
   card heights — which made one door's photo twice the height of its
   neighbours'. */
.door__img.frame--comp,.photo.frame--comp{
  border:0; border-bottom:0; padding:0; display:block; background:var(--sunk);
  overflow:hidden; flex:none;
}
.door__img.frame--comp{aspect-ratio:16/10}
.photo.frame--comp{aspect-ratio:4/3; border-radius:18px; overflow:hidden}
.gal .frame--comp{aspect-ratio:auto; height:100%; min-height:168px; border:0; padding:0; border-radius:var(--r-md); overflow:hidden}

/* 21. MOTION, SECOND PASS ==================================================
   Richer interaction without leaving the budget: everything here is user- or
   scroll-initiated, moves 14px or less, and animates only transform, opacity,
   background-size or fill. Nothing loops, pins, parallaxes or autoplays.

   GSAP is in package.json but is deliberately not shipped. It is 72KB, and
   the things it is good at — timeline scrubbing, pinning, parallax — are the
   things this audience's motion budget rules out. Every effect below is a
   CSS transition the browser composites on its own thread. */

/* Photographs settle rather than snap: a 1.5% scale is well under 14px at
   any frame size on this page, and it only ever runs on hover. */
.frame--comp img,.door__img img,.gal .frame--comp img{
  transition:transform .5s cubic-bezier(.2,.7,.3,1);
}
.door:hover .door__img img,
.gal .frame--comp:hover img,
.photo.frame--comp:hover img{transform:scale(1.015)}

/* Eyebrow rule draws in with the section it labels. */
.eyebrow{position:relative; padding-bottom:.45rem}
.eyebrow::after{
  content:""; position:absolute; left:0; bottom:0; height:2px; width:34px;
  background:currentColor; opacity:.45;
  transform:scaleX(0); transform-origin:left center;
  transition:transform .5s cubic-bezier(.2,.7,.3,1) .1s;
}
.js [data-sec].in .eyebrow::after,
.js [data-reveal].in .eyebrow::after,
.eyebrow:first-child::after{transform:scaleX(1)}

/* Stat tiles and doors lift on hover, like the cards already do. */
.tile{transition:transform .25s cubic-bezier(.2,.7,.3,1), box-shadow .25s ease}
.tile:hover{transform:translateY(-3px); box-shadow:var(--e2)}
.pills li{transition:transform .2s cubic-bezier(.2,.7,.3,1), border-color .2s ease}
.pills li:hover{transform:translateY(-2px); border-color:var(--teal)}

/* Credential card: the seal turns up a fraction after the card. */
.cred{transition:transform .3s cubic-bezier(.2,.7,.3,1), box-shadow .3s ease}
.cred:hover{transform:translateY(-2px); box-shadow:var(--e2)}

/* The trust strip used to start at opacity 0 and wait for .band.in. Nothing
   ever set it: main.js skips .band when it marks sections, on the grounds
   that the strip is above the fold and animating it only delays first paint.
   So the four items never appeared and the strip rendered as an empty white
   band between two hairlines. It is above the fold -- it is simply there. */

/* The header gains a hairline shadow once the page has moved. */
.head{transition:box-shadow .25s ease}
.head.is-stuck{box-shadow:0 1px 0 var(--line),0 6px 18px rgba(23,79,89,.06)}

/* Ghost buttons fill from the left like the primary ones do. */
.btn--ghost{
  background-image:linear-gradient(var(--teal-wash),var(--teal-wash));
  background-repeat:no-repeat; background-size:0% 100%;
  transition:background-size .3s cubic-bezier(.2,.7,.3,1),
             transform .2s cubic-bezier(.2,.7,.3,1), border-color .2s ease;
}
.btn--ghost:hover,.btn--ghost:focus-visible{background-size:100% 100%; transform:translateY(-2px)}

@media (prefers-reduced-motion: reduce){
  .frame--comp img,.door__img img,.gal .frame--comp img,
  .tile,.pills li,.cred,.head,.btn--ghost{transition:none}
  .door:hover .door__img img,.gal .frame--comp:hover img,
  .photo.frame--comp:hover img{transform:none}
  .eyebrow::after{transform:scaleX(1); transition:none}
}

/* 22. CARD, BANNER AND TRIO MEDIA ==========================================
   Media slots the design already draws: a photograph on each service and
   pathway card, a banner image on Volunteer, and the three-up row in "Lend a
   hand". No new sections — these fill frames the layout already had. */
/* .card pads with --s6, so the bleed must be --s6 too — with --s5 the
   photograph stopped short of the card's right edge. */
.card__img{
  margin:calc(var(--s6) * -1) calc(var(--s6) * -1) var(--s4);
  aspect-ratio:16/10; overflow:hidden; border-radius:var(--r-md) var(--r-md) 0 0;
  background:var(--sunk); flex:none;
}
.card__img img{width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.card:hover .card__img img{transform:scale(1.03)}

.banner__media{
  /* A cinematic strip rather than a slab. At 21:9 across a 1320px wrap this
     photograph stood 566px tall and pushed the page's first real sentence
     below the fold. The ratio is kept for narrow screens, where it is only
     167px; the cap does the work at desktop. Cropping is object-fit's job,
     so nothing is scaled or distorted. */
  margin:var(--s4) 0; aspect-ratio:21/9; max-height:clamp(220px,32vh,340px);
  overflow:hidden; border-radius:18px; background:var(--sunk);
}
.banner__media img{width:100%; height:100%; object-fit:cover; display:block}

.trio{display:grid; gap:var(--s4); grid-template-columns:1fr}
@media(min-width:760px){.trio{grid-template-columns:repeat(3,minmax(0,1fr))}}
.trio .frame{aspect-ratio:16/9}

@media (prefers-reduced-motion: reduce){
  .card__img img{transition:none}
  .card:hover .card__img img{transform:none}
}

/* The founder portrait is used exactly once, on About, which is the
   leadership page. Home keeps the summary and the credential card, laid out
   as a single column so the space the portrait used to occupy closes up
   rather than being left empty. */
.founder-brief{display:grid; gap:var(--s5)}
.founder-brief .prose{max-width:76ch}
.founder-brief .cred{max-width:640px}

/* 23. FOUNDER STORY ========================================================
   Editorial column. Narrower measure than the rest of the site because this
   is the longest continuous read on it — roughly 62 characters a line, which
   is where sustained prose stays comfortable. */
/* Centred, not left-pinned: at 1320px a left-aligned 68ch column leaves the
   whole right half of the section empty. Long-form prose is the one place a
   centred measure is the editorial convention rather than a compromise. */
.story{max-width:68ch; margin-inline:auto}
.story p{max-width:none}

/* Pull quote. Gold rule on the left, generous space around it; the quote is
   the one place the page slows down. */
.pull{
  margin:clamp(2.25rem,5vw,3.25rem) 0; padding:0 0 0 clamp(1.25rem,3vw,2rem);
  border-left:3px solid var(--gold);
}
.pull p{
  margin:0; font-size:clamp(1.25rem,1.05rem + .9vw,1.7rem); line-height:1.4;
  color:var(--teal); font-style:italic; max-width:34ch;
}
.pull cite{
  display:block; margin-top:var(--s4); font-style:normal; font-size:.86rem;
  font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted);
}

/* 24. TOUCH TARGETS ========================================================
   WCAG 2.2 SC 2.5.8 asks for a 24x24 CSS-pixel minimum on pointer targets.
   axe does not test this rule by default, so these three were passing the
   automated audit while failing the criterion — found by measuring every
   interactive element at 390px.

   Inline links inside running prose are exempt under the criterion, so body
   copy is deliberately left alone. */

/* Consent and choice checkboxes were 20x20. */
.consent input[type="checkbox"],
.choice input[type="checkbox"]{width:24px; height:24px}

/* Footer bar links sat at 16px tall. Padding lifts the hit area without
   moving anything visually. */
.foot__bar a{display:inline-block; padding-block:4px}

/* The scroll cue was 22px tall. */
.cue{min-height:24px; align-items:center}

/* 25. REACH HEAD, FIGURES AND COVERAGE COLUMNS =============================
   The layout around the map, from the design. The map component itself is
   untouched — this is only what sits above and below it. */
.reach__head{display:grid; gap:clamp(1.5rem,4vw,3rem); grid-template-columns:1fr}
@media(min-width:900px){
  .reach__head{grid-template-columns:minmax(0,1.35fr) minmax(0,1fr); align-items:start}
}
.reach__figures{
  display:grid; gap:var(--s5); list-style:none; margin:0; padding:0;
  grid-template-columns:repeat(3,minmax(0,1fr));
}
@media(max-width:520px){.reach__figures{grid-template-columns:1fr}}
.reach__figures b{
  display:block; font-size:clamp(2rem,1.4rem + 2.4vw,3rem); line-height:1;
  color:var(--teal); font-weight:700;
}
.reach__figures span{
  display:block; margin-top:var(--s3); font-size:.86rem; line-height:1.35;
  color:var(--muted);
}

.reach__cols{
  display:grid; gap:var(--s5) var(--s6); margin-top:var(--s6);
  padding-top:var(--s5); border-top:1px solid var(--line);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,215px),1fr));
}
.reach__col h3{font-size:1rem; color:var(--teal)}
.reach__sub{margin:.25rem 0 0; font-size:.82rem; color:var(--muted); line-height:1.4}
.reach__names{list-style:none; margin:var(--s4) 0 0; padding:0;
  display:flex; flex-direction:column; gap:.3rem; font-size:.92rem}
.reach__names li{color:var(--charcoal)}
/* Country names stay clickable — they pin the country on the map — but read
   as text rather than as buttons, which is how the design prints them. */
.reach__name{
  background:none; border:0; padding:2px 0; margin:0; font:inherit;
  color:var(--charcoal); cursor:pointer; text-align:left; min-height:24px;
  border-bottom:1px solid transparent;
}
.reach__name:hover,.reach__name:focus-visible{color:var(--teal); border-bottom-color:var(--teal)}
.reach__name[aria-current="true"]{color:var(--teal); font-weight:700; border-bottom-color:var(--teal)}
.reach__plus{color:var(--muted); font-size:.82rem}

/* 26. FOOTER, SECOND PASS ==================================================
   Was four plain lists with browser-default underlines. Now a brand column
   with the mark and the tagline, three link columns, and a quieter legal
   bar. Underlines are drawn on hover rather than sitting there by default. */
.foot__grid{
  display:grid; gap:clamp(2rem,4vw,3.5rem);
  grid-template-columns:1fr;
}
@media(min-width:700px){.foot__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:1000px){
  .foot__grid{grid-template-columns:minmax(0,1.5fr) repeat(3,minmax(0,1fr))}
}
.foot__logo{
  display:inline-flex; align-items:center; gap:.7rem; text-decoration:none;
  color:#fff; font-weight:700; font-size:1.12rem; margin-bottom:var(--s4);
}
.foot__logo img{width:60px; height:auto}
.foot__brand p{max-width:44ch}
.foot__tag{
  margin-top:var(--s4); font-style:italic; color:var(--gold-on-teal);
  font-size:1rem;
}
.foot__addr{margin-top:var(--s4); font-size:.9rem}

/* Underline on hover, not at rest. */
.foot a{
  color:#CFE6EA; text-decoration:none;
  background-image:linear-gradient(currentColor,currentColor);
  background-repeat:no-repeat; background-position:0 100%;
  background-size:0 1px;
  transition:background-size .25s cubic-bezier(.2,.7,.3,1), color .2s ease;
}
.foot a:hover,.foot a:focus-visible{color:#fff; background-size:100% 1px}
.foot__logo:hover{background-size:0 1px}

.foot__legal{display:flex; flex-wrap:wrap; gap:var(--s5)}

@media (prefers-reduced-motion: reduce){
  .foot a{transition:none}
}

/* 27. FAQ ==================================================================
   Native <details>, so it works without JavaScript and a browser's find-in-
   page can still reach closed answers. */
.faq{border-top:1px solid var(--line)}
.faq__item{border-bottom:1px solid var(--line)}
.faq__item summary{
  cursor:pointer; list-style:none; padding:var(--s5) 2.5rem var(--s5) 0;
  font-size:1.06rem; font-weight:700; color:var(--teal); position:relative;
  min-height:48px;
}
.faq__item summary::-webkit-details-marker{display:none}
.faq__item summary::after{
  content:""; position:absolute; right:.5rem; top:50%;
  width:11px; height:11px; margin-top:-7px;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(45deg); transition:transform .25s cubic-bezier(.2,.7,.3,1);
}
.faq__item[open] summary::after{transform:rotate(-135deg); margin-top:-3px}
.faq__item summary:hover,.faq__item summary:focus-visible{color:var(--teal-deep)}
.faq__item p{padding:0 0 var(--s4); color:var(--charcoal); max-width:70ch}
@media (prefers-reduced-motion: reduce){
  .faq__item summary::after{transition:none}
}

/* 28. FIRST STEPS GUIDE ====================================================
   A routing form, not a screener. Nothing is scored and nothing is stored. */
.choices--stack{grid-template-columns:1fr}
.steps-form legend{
  font-weight:700; color:var(--teal); font-size:1.05rem; padding:0;
  margin-bottom:var(--s4);
}
.steps-form fieldset{border:0; padding:0; margin:0}

.result{
  background:var(--white); border:1px solid var(--line);
  border-top:3px solid var(--teal); border-radius:var(--r-md);
  padding:clamp(1.5rem,3.5vw,2.5rem);
}
.result:focus{outline:3px solid var(--teal); outline-offset:3px}
.result h2{font-size:clamp(1.4rem,1.2rem + 1vw,1.9rem)}
.result__list{display:grid; gap:var(--s5); margin-top:var(--s5)}
.result__item{
  padding:var(--s5); border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--sunk);
}
.result__item h3{font-size:1.08rem; color:var(--teal)}
.result__item p{margin-top:var(--s3); color:var(--charcoal)}

/* Map embed. A fixed ratio so the third-party frame cannot shift the page as
   it loads, and lazy so it is not fetched until scrolled to. */
.mapwrap{
  /* The Google embed -- not the reach map, which is frozen. At 16/9 across the
     wrap it stood 742px tall, most of the section it sits in, to show a place
     marker. Capped; the embed reflows to whatever box it is given. */
  position:relative; aspect-ratio:16/9; max-height:clamp(260px,44vh,440px);
  overflow:hidden;
  border:1px solid var(--line); border-radius:18px; background:var(--sunk);
}
@media(max-width:640px){.mapwrap{aspect-ratio:4/3}}
.mapwrap iframe{position:absolute; inset:0; width:100%; height:100%; border:0}

/* 29. PORTAL ===============================================================
   A hub, not an account area. The three routes are the same three the site
   already has; this page gathers them, says what each one needs, and adds a
   short form for people who would rather talk. */
.portal__h{
  font-size:.78rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted); margin-top:var(--s4);
}
.ticks--tight{margin-top:var(--s3); gap:.4rem}
.ticks--tight li{font-size:.92rem}
.ticks--tight svg{width:15px; height:15px}
.portal__no{
  margin-top:var(--s4); font-size:.9rem; color:var(--muted);
  padding-top:var(--s3); border-top:1px solid var(--line);
}
.portal__no strong{color:var(--charcoal)}

/* 31. HERO GROWTH MOTIF ====================================================
   Replaces the silhouette band. Four strands — therapy, education, family,
   training — rise from one root and meet in a single canopy, which is the
   argument the whole site makes, drawn rather than stated.

   Built in SVG rather than sourced: it is on-palette, weighs nothing, stays
   sharp at any size, and needs no photograph of a child. */
.growth{margin:0; width:100%; max-width:520px; justify-self:center}
.growth__svg{display:block; width:100%; height:auto; overflow:visible}

.growth__ground{stroke:var(--line); stroke-width:2; fill:none; stroke-linecap:round}
.growth__stem{stroke:var(--sage-deep); stroke-width:3; fill:none; stroke-linecap:round}

.growth__arc{
  fill:none; stroke-width:2.5; stroke-linecap:round;
  opacity:.55; transition:opacity .3s ease, stroke-width .3s ease;
}
.growth__arc[data-arc="therapy"]{stroke:var(--teal)}
.growth__arc[data-arc="education"]{stroke:var(--sage-deep)}
.growth__arc[data-arc="family"]{stroke:var(--coral-deep)}
.growth__arc[data-arc="training"]{stroke:var(--gold-deep)}

.growth__leaf{
  opacity:.5; transition:opacity .3s ease, transform .3s cubic-bezier(.2,.7,.3,1);
  transform-box:fill-box; transform-origin:center;
}
.growth__leaf[data-arc="therapy"]{fill:var(--teal)}
.growth__leaf[data-arc="education"]{fill:var(--sage)}
.growth__leaf[data-arc="family"]{fill:var(--coral)}
.growth__leaf[data-arc="training"]{fill:var(--gold)}
.growth__core{fill:var(--cream); stroke:var(--teal); stroke-width:2.5; opacity:.9}

/* Focus or hover a strand and the rest step back. Opacity only — nothing
   moves more than a hair, and nothing loops. */
.growth.is-on .growth__arc,
.growth.is-on .growth__leaf{opacity:.14}
.growth.is-on .growth__arc.on{opacity:1; stroke-width:3.5}
.growth.is-on .growth__leaf.on{opacity:.85; transform:scale(1.06)}

.growth__cap{margin-top:var(--s5)}
.growth__key{
  display:flex; flex-wrap:wrap; gap:.35rem var(--s4);
  list-style:none; margin:0; padding:0; justify-content:center;
}
.growth__key button{
  display:inline-flex; align-items:center; gap:.45rem; min-height:32px;
  background:none; border:0; padding:.25rem .1rem; cursor:pointer;
  font-family:var(--font); font-size:.9rem; color:var(--muted);
  border-bottom:1.5px solid transparent;
}
.growth__key button:hover,.growth__key button:focus-visible{color:var(--teal); border-bottom-color:var(--teal)}
.growth__sw{width:11px; height:11px; border-radius:50%; flex:none}
.growth__sw--therapy{background:var(--teal)}
.growth__sw--education{background:var(--sage-mid)}
.growth__sw--family{background:var(--coral)}
.growth__sw--training{background:var(--gold)}
.growth__note{
  margin-top:var(--s3); text-align:center; font-size:.86rem; color:var(--muted);
  min-height:2.6em;
}

@media (prefers-reduced-motion: reduce){
  .growth__arc,.growth__leaf{transition:none}
  .growth.is-on .growth__leaf.on{transform:none}
}

/* 32. PORTAL PANEL =========================================================
   The signed-in area. Deliberately plain: this is somewhere a parent reads
   their child's plan, not somewhere to show off. */
.panel{
  background:var(--white); border:1px solid var(--line);
  border-top:3px solid var(--teal); border-radius:var(--r-md);
  padding:clamp(1.5rem,4vw,2.5rem);
}
.panel__head{display:flex; flex-wrap:wrap; gap:var(--s4); align-items:start; justify-content:space-between}
.signin{max-width:34rem}

.pblock{margin-top:var(--s6); padding-top:var(--s5); border-top:1px solid var(--line)}
.pblock:first-child{margin-top:0; padding-top:0; border-top:0}
.pblock h3{font-size:1.15rem; color:var(--teal)}
.pblock__blurb{margin-top:var(--s3); color:var(--muted); font-size:.94rem}
.pblock__empty{margin-top:var(--s4); color:var(--muted); font-style:italic}

.prow{
  margin-top:var(--s4); padding:var(--s4); border:1px solid var(--line);
  border-radius:var(--r-sm); background:var(--sunk);
}
.prow strong{display:block; color:var(--charcoal)}
.prow p{margin-top:.35rem; font-size:.94rem; color:var(--charcoal)}
.prow__meta{color:var(--muted); font-size:.86rem}
.prow__task{
  margin-top:var(--s3); padding-top:var(--s3);
  border-top:1px dashed var(--line); font-size:.92rem;
}
.prow__tag{
  display:inline-block; margin-bottom:.4rem; font-size:.7rem; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; color:var(--teal);
  background:var(--teal-wash); border-radius:var(--r-pill); padding:.2rem .6rem;
}
.prow__tag--funded{color:var(--sage-deep); background:var(--sage-wash)}
.prow__tag--pending{color:var(--gold-deep); background:#FAF6EE}
.prow__tag--cancelled,.prow__tag--missed{color:var(--coral-deep); background:var(--coral-wash)}

.pbar{margin-top:var(--s4); height:8px; border-radius:99px; background:var(--line); overflow:hidden}
.pbar__fill{height:100%; background:var(--teal); border-radius:99px}

/* 33. THERAPY SELECTOR =====================================================
   Four cards act as tabs; one panel below reveals the detail. This replaces
   an accordion inside each card, which pushed the page around and made the
   four therapies impossible to compare.

   The panel reveals the way the Start here result does — same gesture, so
   the site behaves consistently. */
.svc-cards{
  display:grid; gap:var(--s4); grid-template-columns:1fr;
}
@media(min-width:640px){.svc-cards{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:1000px){.svc-cards{grid-template-columns:repeat(4,minmax(0,1fr))}}

.svc-card{
  display:flex; flex-direction:column; text-align:left; padding:0; cursor:pointer;
  background:var(--white); border:1px solid var(--line); border-radius:14px;
  overflow:hidden; font-family:var(--font); color:inherit;
  transition:transform .28s cubic-bezier(.2,.7,.3,1),
             box-shadow .28s ease, border-color .28s ease;
}
.svc-card:hover{transform:translateY(-4px); box-shadow:var(--e2)}
.svc-card__img{display:block; aspect-ratio:16/10; overflow:hidden; background:var(--sunk)}
.svc-card__img img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .55s cubic-bezier(.2,.7,.3,1);
}
.svc-card:hover .svc-card__img img{transform:scale(1.04)}
.svc-card__body{display:flex; flex-direction:column; gap:.4rem; padding:var(--s5); flex:1}
.svc-card__title{font-size:1.08rem; font-weight:700; color:var(--teal)}
.svc-card__helps{font-size:.88rem; color:var(--muted); line-height:1.45; flex:1}
.svc-card__more{
  font-size:.86rem; font-weight:700; color:var(--teal); margin-top:var(--s3);
  display:inline-flex; align-items:center; gap:.35rem;
}
.svc-card__more::after{content:"\2192"; transition:transform .25s ease}
.svc-card:hover .svc-card__more::after{transform:translateX(3px)}

/* Selected card: a teal edge and a filled indicator, so the link between the
   card and the panel below is unmistakable. */
.svc-card[aria-selected="true"]{
  border-color:var(--teal); box-shadow:var(--e2);
  outline:2px solid var(--teal); outline-offset:-2px;
}
.svc-card[aria-selected="true"] .svc-card__more{color:var(--teal-deep)}
.svc-card[aria-selected="true"] .svc-card__more::after{transform:rotate(90deg)}
.svc-card--sage[aria-selected="true"]{border-color:var(--sage-deep); outline-color:var(--sage-deep)}
.svc-card--gold[aria-selected="true"]{border-color:var(--gold-deep); outline-color:var(--gold-deep)}

.svc-detail{
  margin-top:var(--s5); padding:clamp(1.5rem,4vw,2.5rem);
  background:var(--sunk); border:1px solid var(--line);
  border-top:3px solid var(--teal); border-radius:var(--r-md);
}
.svc-detail:focus-visible{outline:3px solid var(--teal); outline-offset:3px}
.svc-detail h3{font-size:clamp(1.3rem,1.1rem + .9vw,1.75rem); color:var(--teal)}
.svc-detail__grid{display:grid; gap:var(--s5); margin-top:var(--s5); grid-template-columns:1fr}
@media(min-width:800px){.svc-detail__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.svc-detail__block h4{
  font-size:.76rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--sage-deep);
}
.svc-detail__block p{margin-top:.45rem; font-size:.96rem; color:var(--charcoal)}
.svc-detail__cta{margin-top:var(--s6)}

/* The reveal itself. Blocks arrive in sequence rather than all at once, which
   is what makes it read as a considered answer instead of a page jump. */
.js .svc-detail.is-swapping{opacity:0; transform:translateY(8px)}
.js .svc-detail{
  opacity:1; transform:none;
  transition:opacity .3s ease, transform .3s cubic-bezier(.2,.7,.3,1);
}
/* Panels are hidden at load, so a visible one is always one the visitor
   opened. Without scripting they are all visible and this start state must
   not apply. */
.js .svc-detail__block{opacity:0; transform:translateY(10px)}
.js .svc-detail.is-in .svc-detail__block{
  opacity:1; transform:none;
  transition:opacity .45s ease-out, transform .45s cubic-bezier(.2,.7,.3,1);
}
.js .svc-detail.is-in .svc-detail__block:nth-child(2){transition-delay:.07s}
.js .svc-detail.is-in .svc-detail__block:nth-child(3){transition-delay:.14s}
.js .svc-detail.is-in .svc-detail__block:nth-child(4){transition-delay:.21s}

@media (prefers-reduced-motion: reduce){
  .svc-card,.svc-card__img img,.svc-detail,.svc-detail__block{transition:none}
  .svc-card:hover{transform:none}
  .svc-card:hover .svc-card__img img{transform:none}
  .js .svc-detail__block{opacity:1; transform:none}
}

/* Links on the deep teal banner. Without this they inherit --teal, which is
   the banner's own background: 1:1, and axe caught it. */
.banner--deep a{color:var(--gold-on-teal); text-decoration-color:rgba(211,186,136,.5)}
.banner--deep a:hover,.banner--deep a:focus-visible{color:#fff; text-decoration-color:#fff}

/* 34. HERO PHOTOGRAPH ======================================================
   The design's own hero image, in the hero. Framed rather than floated: a
   soft-stone mat, a generous radius, and a gold hairline that ties it to the
   credential accent used elsewhere.

   width and height are on the img and the frame has a fixed ratio, so this
   cannot shift the page as it loads — it is the largest element above the
   fold and therefore the LCP candidate. */
.hero__art{margin:0; width:100%; max-width:560px; justify-self:center}
.hero__frame{
  position:relative; aspect-ratio:4/3; overflow:hidden;
  border-radius:20px; background:var(--sunk);
  box-shadow:var(--e2);
}
.hero__frame::after{
  content:""; position:absolute; inset:0; border-radius:20px; pointer-events:none;
  border:1px solid rgba(23,79,89,.12);
  box-shadow:inset 0 0 0 4px var(--cream), inset 0 0 0 5px rgba(200,169,107,.55);
}
.hero__frame img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform 1.1s cubic-bezier(.2,.7,.3,1);
}
.hero__art:hover .hero__frame img{transform:scale(1.03)}
.hero__cap{
  margin-top:var(--s4); font-size:.82rem; color:var(--muted);
  display:flex; align-items:center; gap:.5rem; flex-wrap:wrap;
}
.hero__cap-tag{
  font-size:.66rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
  background:var(--teal-deep); color:#fff; border-radius:4px; padding:.2rem .45rem;
}

/* Arrival: the frame settles rather than snapping in. Runs once, on load. */
@media (prefers-reduced-motion: no-preference){
  .js .hero__art{animation:heroSettle .8s cubic-bezier(.2,.7,.3,1) both .12s}
}
@keyframes heroSettle{
  from{opacity:0; transform:translateY(12px) scale(.985)}
  to{opacity:1; transform:none}
}

/* 35. MAP ARRIVAL ==========================================================
   Countries settle into place the first time the map is scrolled to. This is
   presentation only: no fill, no layer flag, no interaction and no data is
   touched. The script sets --dx/--dy per country and the transition does the
   rest.

   The motion budget says 14px, and it exists because this audience includes
   autistic children. A hundred countries flying across the screen would
   break it, so the drift is small, it runs once, and reduced-motion skips it
   entirely. What reads as "coming together" here is the stagger, not the
   distance. */
@media (prefers-reduced-motion: no-preference){
  .js .reach__svg[data-arrive] path[data-n]{
    opacity:0;
    transform:translate(var(--dx,0), var(--dy,0));
    transition:opacity .55s ease-out, transform .7s cubic-bezier(.2,.7,.3,1);
    transition-delay:var(--d,0ms);
  }
  .js .reach__svg[data-arrive].is-in path[data-n]{
    opacity:1; transform:none;
  }
}

/* 36. HERO REASSURANCE LINE ================================================
   The line under the two buttons had no styling at all — an earlier
   conditional append never ran — so it sat hard against them at full body
   size and read as part of the button row. */
.hero__note{
  margin-top:var(--s5);
  font-size:.95rem; line-height:1.6; color:var(--muted);
  max-width:46ch;
  padding-top:var(--s4);
  border-top:1px solid var(--line);
}

/* ==========================================================================
   37. MOTION & CRAFT LAYER
   A deliberate pass over the whole site: the hero arrives as a sequence,
   photographs uncover rather than fade, rules draw, numbers count, and every
   interactive surface answers back.

   Everything here is transform / opacity / clip-path / background-size, all
   composited, all disabled under prefers-reduced-motion. No rule in this
   block touches the reach map.
   ========================================================================== */

/* ---- 37.1 hero entrance -------------------------------------------------
   Six beats, roughly 90ms apart: eyebrow, headline, lede, actions, note,
   cue. Short enough to be finished before a reader has settled on the
   headline, ordered enough to read as intent rather than as a slow load. */
@media (prefers-reduced-motion: no-preference){
  .js .hero__copy > *:not(h1){opacity:0; animation:heroIn .62s cubic-bezier(.2,.75,.3,1) forwards}
  .js .hero__copy > .eyebrow    {animation-delay:.05s}

  /* The headline rises but never fades: it is the largest contentful paint
     on this page, and anything that starts it at opacity 0 postpones the
     metric by the length of the animation. A transform costs nothing --
     the text is painted where the browser can see it, and moves after. */
  .js .hero__copy > h1{animation:heroRise .62s cubic-bezier(.2,.75,.3,1) both}
  .js .banner h1      {animation:heroRise .62s cubic-bezier(.2,.75,.3,1) both}
  .js .hero__copy > .hero__lede {animation-delay:.24s}
  .js .hero__copy > .hero__acts {animation-delay:.33s}
  .js .hero__copy > .hero__note {animation-delay:.42s}
  .js .hero__copy > .cue        {animation-delay:.50s}
  .js .hero__frame{animation:uncover .95s cubic-bezier(.2,.75,.3,1) both .18s}
}
@keyframes heroIn{
  from{opacity:0; transform:translateY(14px)}
  to{opacity:1; transform:none}
}
@keyframes heroRise{
  from{transform:translateY(14px)}
  to{transform:none}
}
@keyframes uncover{
  from{clip-path:inset(0 0 100% 0)}
  to{clip-path:inset(0 0 0 0)}
}

/* ---- 37.2 photographs uncover on scroll ---------------------------------
   A wipe reads as deliberate where a fade reads as a slow connection. The
   image starts a touch scaled so it settles into the frame. */
.js [data-uncover]{clip-path:inset(0 0 100% 0)}
.js [data-uncover] img{transform:scale(1.05)}
@media (prefers-reduced-motion: no-preference){
  .js [data-uncover]{transition:clip-path .95s cubic-bezier(.2,.75,.3,1)}
  .js [data-uncover] img{transition:transform 1.2s cubic-bezier(.2,.75,.3,1)}
}
.js [data-uncover].is-in{clip-path:inset(0 0 0 0)}
.js [data-uncover].is-in img{transform:none}

/* ---- 37.3 (removed) ----------------------------------------------------
   This drew a second rule above every section h2. But .eyebrow::after already
   draws one under the eyebrow directly above it, so any section with both got
   two dashes eleven pixels apart, and any section without an eyebrow got a
   stray dash floating over the heading. One rule per section heading is the
   design; this was a duplicate of it. */

/* ---- 37.4 numbers ------------------------------------------------------
   Tabular figures so a counting number does not jitter its own width. */
.stat b,.tile b{font-variant-numeric:tabular-nums}
/* .reach__figures is deliberately not in that list. The reach section is
   frozen by instruction: nothing in this stylesheet changes how it renders. */

/* ---- 37.5 cards answer back ---------------------------------------------
   A colour bar wipes across the top on hover: one element, one transform,
   and a static grid starts feeling responsive without anything moving far
   enough to disturb the reading.

   Gated on a real pointer. A touch device cannot hover, so on a phone these
   rules only ever cost style recalculation for a bar nobody can trigger --
   61ms of it, measured. Worse, a tapped :hover state sticks until the next
   tap elsewhere. Both problems disappear by not shipping it to touch. */
@media (hover: hover) and (pointer: fine){
  .card,.mini,.idx{position:relative}
  .card::before,.mini::before,.idx::before{
    content:""; position:absolute; left:0; right:0; top:0; height:3px;
    background:var(--accent); transform:scaleX(0); transform-origin:left center;
    transition:transform .45s cubic-bezier(.2,.75,.3,1);
    border-radius:var(--r-md) var(--r-md) 0 0;
  }
  .card--b::before{background:var(--sage-deep)}
  .card--c::before{background:var(--gold-deep)}
  .idx--gold::before{background:var(--gold-deep)}
  .card:hover::before,.mini:hover::before,.idx:hover::before{transform:scaleX(1)}

  .mini{transition:transform .28s cubic-bezier(.2,.75,.3,1), box-shadow .28s ease, border-color .28s ease}
  .mini:hover{transform:translateY(-3px); box-shadow:var(--e2); border-color:var(--teal)}
  .idx{transition:transform .28s cubic-bezier(.2,.75,.3,1), box-shadow .28s ease}
  .idx:hover{transform:translateY(-3px); box-shadow:var(--e2)}
}

/* ---- 37.6 buttons -------------------------------------------------------
   A real press. One pixel is enough to feel and too little to notice. */
.btn{transition:background-size .3s cubic-bezier(.2,.75,.3,1),
                transform .18s cubic-bezier(.2,.75,.3,1),
                box-shadow .25s ease, color .2s ease, border-color .2s ease}
.btn:active{transform:translateY(1px) scale(.995)}
.btn--primary{box-shadow:0 1px 2px rgba(23,79,89,.10)}
@media (hover: hover) and (pointer: fine){
  .btn--primary:hover{box-shadow:0 6px 18px rgba(23,79,89,.18)}
}

/* ---- 37.7 form fields ---------------------------------------------------
   The focused field takes a teal ring, so a parent working through a long
   form always knows where they are. */
.field input,.field select,.field textarea{
  transition:border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}
.field input:focus,.field select:focus,.field textarea:focus{
  border-color:var(--teal); background:var(--white);
  box-shadow:0 0 0 3px rgba(23,79,89,.14);
}
@media (hover: hover) and (pointer: fine){
  .choice{transition:border-color .2s ease, background-color .2s ease, transform .2s cubic-bezier(.2,.75,.3,1)}
  .choice:hover{border-color:var(--teal); transform:translateY(-1px)}
}

/* ---- 37.8 placeholders, redesigned --------------------------------------
   These were bright dashed boxes, and 36 of them made a finished site look
   unfinished. They are still unmistakably placeholders, because that rule
   stands, but they now read as an editorial note in the margin rather than
   as something broken. */
.tbd{
  display:inline; border:0; border-radius:0; padding:0;
  color:var(--muted); font-style:italic; font-weight:400; font-size:1em;
  line-height:inherit;
  /* A marker line low in the line box. Painted with background-size in em
     rather than a colour-stop percentage: an inline box is only as tall as
     the font, so a stop at 62% lands across the middle of the letters and
     reads as a strikethrough. */
  background-image:linear-gradient(rgba(200,169,107,.45),rgba(200,169,107,.45));
  background-repeat:no-repeat;
  background-size:100% .28em;
  background-position:0 1.02em;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
}
.tbd::before{
  /* A non-breaking space: a trailing ordinary space in a content string is
     collapsed away at the inline boundary, and the label runs into the text. */
  content:"to add\2014\00A0"; font-style:normal; font-weight:700;
  font-size:.78em; letter-spacing:.06em; text-transform:uppercase;
  color:var(--gold-deep); background:none;
}
.vision .tbd,.banner--deep .tbd,.pointer .tbd{
  background-image:linear-gradient(rgba(211,186,136,.4),rgba(211,186,136,.4));
  color:#E6EEF0;
}
.vision .tbd::before,.banner--deep .tbd::before,.pointer .tbd::before{color:var(--gold-on-teal)}

/* ---- 37.8b handing the reveal over to GSAP ------------------------------
   .gs is set by the script on every element GSAP drives. GSAP writes opacity
   and transform inline, frame by frame; a CSS transition on the same
   properties would be a second engine fighting it for the same pixels. The
   class only ever exists when the library actually loaded, so the CSS path
   below is untouched when it did not. */
.gs{transition:none !important}

/* ---- 37.9 links ---------------------------------------------------------
   The underline retracts on hover instead of appearing. It reads as the link
   responding rather than as a state being switched on. Pointer devices only:
   a phone paints the gradient and never animates it. Underlines themselves
   are not conditional -- these rules only replace one underline with another
   that can move, so gating them takes nothing away from a touch reader. */
@media (hover: hover) and (pointer: fine){
  .prose a,.story a,.faq__item p a{
    background-image:linear-gradient(currentColor,currentColor);
    background-repeat:no-repeat; background-position:0 100%;
    background-size:100% 1px; text-decoration:none;
    transition:background-size .3s cubic-bezier(.2,.75,.3,1), color .2s ease;
  }
  .prose a:hover,.story a:hover,.faq__item p a:hover{
    background-size:0 1px; color:var(--gold-link-hover);
  }
}

/* ---- 37.10 moving between pages ----------------------------------------
   A cross-document view transition: the outgoing page fades to the incoming
   one instead of the browser blanking to white between them. It is CSS only,
   which matters here -- the Content-Security-Policy is script-src 'self',
   so there is no inline script to hook navigation with, and none is needed.

   Opacity only, no movement, and it is user-initiated by definition, so it
   sits inside the motion budget. Browsers without the feature ignore the
   at-rule and navigate exactly as they do now. */
@view-transition{ navigation:auto }
::view-transition-old(root),
::view-transition-new(root){ animation-duration:.26s; animation-timing-function:cubic-bezier(.2,.75,.3,1) }

@media (prefers-reduced-motion: reduce){
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){ animation:none !important }
  .js .hero__copy > *{opacity:1; animation:none}
  .js .banner h1{animation:none}
  .js .hero__frame{animation:none}
  .js [data-uncover]{clip-path:none; transition:none}
  .js [data-uncover] img{transform:none; transition:none}
    .card::before,.mini::before,.idx::before,.mini,.idx,.btn,.choice,
  .prose a,.story a{transition:none}
}

/* ---- 37.11 story chapters ----------------------------------------------
   The founder story is the longest continuous read on the site. Numbered
   chapters give it a spine: a reader can see how far through they are, and
   can come back to a part rather than re-scanning from the top. The numeral
   is decorative and hidden from screen readers, which get the heading. */
.chap{
  position:relative; margin-top:clamp(2.5rem,5vw,3.5rem);
  padding-top:var(--s5); color:var(--teal);
  border-top:1px solid var(--line);
}
.chap__n{
  display:block; font-size:.78rem; font-weight:700; letter-spacing:.18em;
  color:var(--gold-deep); margin-bottom:.45rem;
}
@media(min-width:900px){
  .chap__n{
    position:absolute; left:-4.5rem; top:var(--s5); margin:0;
    font-size:1.6rem; letter-spacing:0; line-height:1;
    color:var(--line); font-weight:700;
  }
  .story .chap{padding-left:0}
}

/* ---- 37.12 comparison table --------------------------------------------
   Training should read academic where Therapy reads clinical. A real table
   is the right element: it is scannable, it is what a professional comparing
   providers expects, and a screen reader can navigate it by row and column.
   It scrolls inside its own container so it never pushes the page sideways. */
.tablewrap{overflow-x:auto; border:1px solid var(--line); border-radius:var(--r-md); background:var(--white)}
.ctable{border-collapse:collapse; width:100%; min-width:640px; font-size:.95rem}
.ctable th,.ctable td{
  padding:var(--s4) var(--s5); text-align:left; vertical-align:top;
  border-bottom:1px solid var(--line);
}
.ctable thead th{
  background:var(--teal); color:#fff; font-size:1.02rem; vertical-align:bottom;
  border-bottom:0;
}
.ctable thead th span{
  display:block; font-weight:400; font-size:.8rem; margin-top:.2rem; color:#CBE0E4;
}
.ctable thead th:first-child{background:var(--teal-deep)}
.ctable tbody th{
  width:26%; color:var(--teal); font-weight:700; background:var(--sunk);
}
.ctable tbody tr:last-child th,.ctable tbody tr:last-child td{border-bottom:0}
.ctable tbody tr{transition:background-color .2s ease}
.ctable tbody tr:hover td{background:var(--teal-wash)}
.ctable .yes{color:var(--sage-deep)}
