/* GEM Platform — site styles (mobile-first).
   Brand values come from tokens.css. No hard-coded colors here. */

/* ===================================================================
   1. Reset & base
   =================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.0625rem;          /* ~17px, low-fatigue */
  line-height: var(--line);
  color: var(--text);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3, h4 {
  font-family: var(--font-head);
  color: var(--purple);
  line-height: 1.2;
  margin: 0 0 0.5em;
  font-weight: 600;
}
h1 { font-size: clamp(2rem, 5vw, 3rem); }
h2 { font-size: clamp(1.5rem, 3.5vw, 2.1rem); }
h3 { font-size: clamp(1.2rem, 2.5vw, 1.45rem); }

p { margin: 0 0 1em; max-width: var(--maxw); }

a { color: var(--purple-deep); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--purple-bright); }   /* lively hover from the brightened palette (6.5:1 on white) */

/* ===================================================================
   2. Layout helpers
   =================================================================== */
.container {
  width: 100%;
  max-width: 1120px;
  margin-inline: auto;
  padding-inline: 1.25rem;
}

.section { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.section--lavender { background: var(--lavender); }
.section--purple { background: var(--purple); color: var(--white); }
/* Warm, near-white band with a soft gold glow — distinct from the cool lavender. */
.section--warm {
  background: radial-gradient(760px 460px at 82% 118%, rgba(187, 134, 63, 0.12), transparent 60%), var(--white);
}
.section--purple h1, .section--purple h2, .section--purple h3 { color: var(--white); }

/* ===================================================================
   3. Accessibility utilities
   =================================================================== */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* Visible keyboard focus everywhere — purple ring (gold is too light to ring reliably). */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: 1rem; top: -3rem;
  z-index: 1000;
  background: var(--purple);
  color: var(--white);
  padding: 0.6rem 1rem;
  border-radius: var(--radius);
  text-decoration: none;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 1rem; color: var(--white); }

/* ===================================================================
   4. Buttons
   =================================================================== */
.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  padding: 0.85rem 1.4rem;
  border-radius: var(--radius);
  border: 2px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
/* Brighter, hopeful primary actions: --purple-bright rest state (white label,
   6.5:1 = AA at every size), settling into --purple on hover/press. Headings and
   body anchors stay --purple/--purple-deep; only actions get the lively violet. */
.btn--primary { background: var(--purple-bright); color: var(--white); }
.btn--primary:hover { background: var(--purple); color: var(--white); }
.btn--ghost { background: transparent; color: var(--purple-bright); border-color: var(--purple-bright); }
.btn--ghost:hover { background: var(--purple-bright); color: var(--white); }
/* Gold accent action (What We Believe "Read the Founder's Vision" CTA). Gold-on-light can't use the canonical
   #BB863F for the LABEL (fails AA at button size), so the text uses --gold-deep
   (#8A6222, ≈5.4:1 on white) inside a canonical-gold outline; hover fills to solid
   --gold-deep with a white label (≈5.4:1) plus a subtle lift. */
.btn--gold {
  background: transparent;
  color: var(--gold-deep);
  border-color: var(--gold);        /* #BB863F outline — 3.2:1 graphic on white (AA for a border) */
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.btn--gold:hover {
  background: var(--gold-deep);
  color: var(--white);
  border-color: var(--gold-deep);
  transform: translateY(-2px);
}
.btn--gold:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .btn--gold:hover { transform: none; }
}

/* ===================================================================
   5. Site header
   =================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--cream);              /* warm near-solid so content under stays readable */
  border-bottom: 3px solid var(--gold);
  transition: box-shadow 0.2s ease;
}
/* Flat at the top; lifts with a subtle shadow once the page is scrolled
   (.is-scrolled toggled by ui.js). */
.site-header.is-scrolled { box-shadow: 0 4px 16px rgba(46, 33, 80, 0.12); }

/* Offset in-page anchor jumps (e.g. the skip-link #main) so targets
   aren't hidden beneath the sticky header. */
html { scroll-padding-top: 82px; }
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;   /* mobile: logo left, hamburger right */
  padding-block: 1.2rem;            /* taller, calmer bar (mobile) */
}
/* Guaranteed space between the lockup and whatever sits beside it — a real
   margin, not flex gap (Safari <14.1 ignores flex gap). */
.header-inner > .brand { margin-right: 0.75rem; }

/* Brand / logo — full-colour crest icon + white HTML wordmark. --crest-h is the
   single sizing source: the crest matches it and the wordmark scales from it, so
   the two stay in proportion in every header state (heights set per state below).
   The crest keeps its real colours (NO filter, ever); the wordmark is white in
   both header states — the homepage top dark strip and the plum glass both back
   it. Wordmark is HTML text (no text-only logo asset exists). */
.brand {
  --crest-h: clamp(50px, 13vw, 62px);          /* mobile default — bigger, glanceable logo (drives the logo height) */
  display: inline-flex;
  align-items: center;                         /* full lockup vertically centred in the bar */
  min-width: 0;                                /* let the lockup give way before the row overflows */
  text-decoration: none;
  /* No plate/box/fill/border/padding — the transparent PNG sits directly on the
     purple nav bar, original colours exactly as the file. */
}
/* The full original horizontal lockup (crest + GEM + subtitle + gold-"to"
   tagline) as ONE untouched image — no filter, tint, or wrapper. Height is
   --crest-h (frozen on scroll → constant across all frost stages); width auto
   preserves the 1600:715 aspect, never distorted. */
.brand-logo {
  height: var(--crest-h);
  width: auto;
  /* SAFARI COLLISION GUARD: `width: auto` lets each engine resolve the rendered
     width on its own — and the absolutely-stacked white twin resolves it
     independently of the in-flow black one that sizes the .brand box, so Safari
     could paint the visible logo slightly wider than its box, spilling into the
     first nav link. Cap BOTH images to the lockup's exact 1600:715 ratio derived
     from the same --crest-h every engine agrees on — identical width everywhere,
     overlap impossible. object-fit keeps the art undistorted if the cap ever
     binds. Logo size/prominence unchanged (the cap equals its natural width). */
  max-width: calc(var(--crest-h) * 2.238);
  object-fit: contain;
  object-position: left center;
  display: block;
  flex: 0 0 auto;
}
.brand-wordmark { margin-left: 0.2rem; }       /* (legacy, no matching element now) */
.brand-crest {
  height: var(--crest-h);
  width: auto;           /* square crest — height drives it, never stretched */
  display: block;
  flex: 0 0 auto;
  /* gem-crest.png centres the emblem in a square canvas with ~24% transparent
     padding on each side. That right-hand padding is the real gap to the
     wordmark, so pull it back in (scales with --crest-h) to tuck the text right
     up against the emblem — one tight lockup. Crest art is untouched (no filter). */
  margin-right: calc(var(--crest-h) * -0.2);
}
/* Wordmark = the real logo's wordmark + taglines, cropped out of gem-logo-full
   and whitened (dark letterforms -> white, the gold "to"/divider kept gold) so
   the typography matches the printed logo exactly. Sized off --crest-h so it
   stays in proportion with the crest across every header state. It carries its
   own colours (white + gold), so — like the crest — it takes NO filter. */
.brand-wordmark {
  height: calc(var(--crest-h) * 0.94);
  width: auto;                 /* aspect ratio 818:482 — height drives it */
  display: block;
  flex: 0 0 auto;
}
/* Legacy single-image logo class — desktop-only text name (unused; 3-row header
   is retired). Kept as a no-op so any stray reference stays inert. */
.brand-name { display: none; }

/* New masthead pieces (dividers, search) are desktop-only. On mobile the tools
   wrapper is display:contents — invisible to layout — so the EN switcher stays
   inside the hamburger exactly as before. Mobile header is unchanged. */
.header-divider { display: none; }
.header-search { display: none; }
.header-tools { display: contents; }
.lang-switcher__globe { display: none; }   /* shown on both breakpoints below (14px desktop, 24px mobile) */

/* Right-side actions wrapper. Desktop: display:contents makes it invisible to
   layout so .header-tools still lifts into the header grid (util row) exactly as
   before — the desktop header is unchanged. Mobile: a flex cluster (below). */
.header-actions { display: contents; }
.header-actions__divider { display: none; }   /* mobile-only gold hairline (shown in the mobile block) */

/* Hamburger toggle — only appears when JS is active (see .js rule below).
   Without JS the nav is shown in full, so navigation always works. */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  width: 44px; height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.nav-toggle-bar {
  display: block;
  width: 26px; height: 3px;
  margin-inline: auto;
  background: var(--purple);
  border-radius: 2px;
}
.nav-toggle-bar + .nav-toggle-bar { margin-top: 5px; }   /* bar spacing via margin, not flex gap (Safari <14.1) */

/* Primary nav — visible by default so navigation works with JS disabled.
   When JS is active on small screens, it collapses behind the hamburger
   (see the .js rules in the mobile media query below). */
.primary-nav { display: block; }
.site-header .container { position: relative; }

.primary-nav > ul {
  list-style: none;
  margin: 0; padding: 0.5rem 1.25rem 1rem;
  display: flex;
  flex-direction: column;
}
.primary-nav > ul > li + li { margin-top: 0.25rem; }   /* list rhythm via margins, not flex gap (Safari <14.1); desktop row zeroes this */
.primary-nav a {
  display: block;
  padding: 0.7rem 0.4rem;
  text-decoration: none;
  color: var(--purple);
  font-weight: 600;
  border-radius: 8px;
  transition: opacity 0.18s ease;
}
/* Minimal, high-end hover: a gentle label fade only — no underline, bar or box
   (Part A). Keyboard focus uses a currentColor ring so it stays visible on both
   the dark hero (white links) and the light menus (purple links). */
.primary-nav a:hover { opacity: 0.7; }
.primary-nav a:focus-visible,
.nav-menu__toggle:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
  opacity: 1;                         /* focus is never dimmed */
}
.primary-nav a[aria-current="page"] {
  color: var(--purple-deep);          /* active colour kept; the gold underline is removed */
}

/* --- Nav dropdown (e.g. Insights) ---------------------------------------
   Mobile-first: the submenu is an in-flow, collapsible sub-list revealed by
   its toggle (no hover dependence — see the JS-driven .is-open state). The
   >=960px block below turns it into an absolute hover/focus dropdown panel. */
.nav-item--has-menu { position: relative; }
.nav-menu__toggle {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0.7rem 0.4rem;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  color: var(--purple);
  text-align: left;
  cursor: pointer;
  transition: opacity 0.18s ease;
}
.nav-menu__toggle:hover { opacity: 0.7; }
.nav-menu__caret { font-size: 0.7em; margin-left: 0.3rem; transition: transform 0.15s ease; }   /* label↔caret space via margin, not flex gap */
.nav-item--has-menu.is-open > .nav-menu__toggle .nav-menu__caret { transform: rotate(180deg); }

.nav-menu {
  list-style: none;
  margin: 0;
  padding: 0 0 0.25rem 0.5rem;   /* indent the collapsed sub-list */
  display: none;
}
.nav-item--has-menu.is-open > .nav-menu { display: block; }
.primary-nav .nav-menu a { font-weight: 500; }   /* sub-items lighter than top-level */

/* Language switcher (English live; other languages planned until Linguise is on). */
.lang-switcher {
  position: relative;
  display: inline-flex;          /* shrink-wrap to the button so the menu anchors to it,
                                    not to a full-width block (which threw it to the corner) */
  margin: 0 1.25rem 1rem;        /* indent within the open mobile nav (was padding) */
}
.lang-switcher__button {
  display: inline-flex;
  align-items: center;
  background: transparent;
  border: 1.5px solid var(--text-muted);
  color: var(--purple);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.4rem 0.7rem;
  border-radius: 999px;
  cursor: pointer;
}
.lang-switcher__label, .lang-switcher__caret { margin-left: 0.3rem; }   /* globe/EN/caret spacing via margins, not flex gap */
.lang-switcher__caret { font-size: 0.7em; }

/* Dropdown: vertical list anchored to the button. On mobile EN is the last item
   in the open nav (nothing below it, and the panel's overflow would clip a
   downward menu), so it opens UPWARD and left-aligned to the button. On desktop
   EN sits in the header with room below, so it flips to open downward, right-
   aligned (see the desktop override). max-width keeps it on-screen on a phone. */
.lang-switcher__menu {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  top: auto;
  left: 0;
  right: auto;
  width: 190px;
  max-width: calc(100vw - 2.5rem);
  margin: 0;
  padding: 0.35rem;
  list-style: none;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--lavender);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(46, 33, 80, 0.15);
  z-index: 60;
}
.lang-switcher__menu[hidden] { display: none; }
.lang-switcher__menu li { margin: 0; }
.lang-switcher__menu li + li { margin-top: 2px; }   /* row spacing via margins, not flex gap (Safari <14.1) */

.lang-switcher__item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.7rem;
  border: 0;
  border-radius: 8px;
  background: transparent;
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
}
.lang-switcher__name { font-weight: 500; }
.lang-switcher__tag { font-size: 0.72rem; color: var(--text-muted); }

/* Light brand-purple tint on hover (actionable items) and on keyboard focus (all).
   Hover and focus-visible are SEPARATE rules: Safari <15.4 doesn't know
   :focus-visible and drops any rule whose selector list contains it. */
.lang-switcher__item:not(.is-planned):hover { background: var(--lavender); }
.lang-switcher__item:focus-visible { background: var(--lavender); }

/* Current language — clearly marked. */
.lang-switcher__item.is-current { color: var(--purple); font-weight: 600; }
.lang-switcher__item.is-current .lang-switcher__tag { color: var(--purple-deep); font-weight: 600; }

/* Planned languages — muted, honest "coming soon" state, not yet selectable. */
.lang-switcher__item.is-planned { color: var(--text-muted); cursor: not-allowed; }

/* ===================================================================
   6. Site footer
   =================================================================== */
.site-footer {
  /* Lavender-field photo brought back (client request) under a SOFT even purple
     scrim (~0.76) — lighter than the old 0.80 wash and NOT a heavy dark overlay:
     the field texture shows through so the footer reads softer/lighter than the
     flat deep-purple CTA band above it, yet the scrim is tuned so ALL the
     white/lavender footer text clears WCAG AA over the image's brightest areas
     (top sky + warm sunset centre). --purple-deep is the no-image fallback. */
  background-color: var(--purple-deep);
  background-image:
    linear-gradient(rgba(46, 33, 80, 0.76), rgba(46, 33, 80, 0.76)),
    url("../img/backgrounds/bg-4-home-advocacy.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: var(--white);
  padding-bottom: clamp(0.85rem, 2vw, 1.25rem);     /* compact close — excess air removed */
  border-top: 1px solid rgba(187, 134, 63, 0.35);   /* the single gold CTA→footer hairline (kept) */
}
.site-footer .container {
  padding-top: clamp(3rem, 5.5vw, 3.5rem);    /* breathing room below the CTA band: ~48-56px (was 17.6-24px — a ~+32px lift; nudge here). Columns/legal spacing below are untouched. */
}
.site-footer a { color: var(--white); text-decoration: none; }
/* White-wordmark lockup (full-colour crest + WHITE "GEM" + WHITE tagline), designed
   to sit directly on the dark footer field — no plate/box behind it. */
.footer-logo {
  display: block;
  width: clamp(180px, 42vw, 220px);
  height: auto;
  margin-bottom: 0.6rem;                      /* tighter under the logo */
}
.footer-mission { font-family: var(--font-head); font-size: 0.95rem; margin: 0; }   /* unified with the Get in Touch body size (matches .footer-contact__email); serif family kept */
/* Brand promise — a short, premium line between the mission and the Join CTA.
   Typeface matched to the HOMEPAGE hero subtitle (.hero--editorial
   .hero__subtitle): Lora serif, ITALIC, weight 500, normal tracking (the earlier
   0.04em letter-spacing is dropped so the two read as the same treatment).
   Soft champagne (a LIGHT tint of brand gold) keeps it distinct from the
   plain-white mission; #ECD6AE over the footer scrim measures ~8.5:1 = AA.
   Sits inside .footer-brand__main, so it groups with the mission on desktop and
   follows it in the mobile stack (the CTA keeps its own order).
   margin-top 0.3rem (was 0.5rem) pulls it into a tight pair with the tagline. */
.footer-promise {
  font-family: var(--font-head);
  font-style: italic;
  font-size: 0.9rem;
  font-weight: 500;
  color: #ECD6AE;
  margin: 0.3rem 0 0;
}

/* --- 2-column footer (2026-08 redesign): LEFT identity (logo, mission,
   gold-italic promise) · RIGHT contact + action (Get in Touch email ->
   Follow Us -> Join the Movement last). Quick Links + postal address removed.
   Stacks identity above contact/action on mobile; the legal bar is always
   last (it sits outside this grid). --- */
.footer-grid {
  display: grid;
  grid-template-columns: 1fr;                       /* phone: single column, DOM order */
  gap: clamp(1rem, 2.5vw, 1.5rem);                  /* consistent, compact column rhythm */
}
@media (min-width: 760px) {
  .footer-grid {
    /* 2026-08 full-width distribution (client direction - supersedes the 940px
       contained measure): the three columns span the ENTIRE shared container,
       third column flush to the container's right edge, zero right slack.
       Brand carries the wider 1.3fr track (its logo + mission block is the
       largest content); the two link columns are equal 1fr tracks. At a
       1440px viewport: 1080px content = 387.7 / 298.2 / 298.2 + two 48px
       gutters. The legal row below shares this same container, so the left
       AND right edges line up through the whole footer. */
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(2rem, 4vw, 3rem);
    align-items: start;
  }
  .footer-cta { margin-top: 0; }   /* the three column tops align */
}
/* (2026-08 cluster regroup: the former 1rem desktop separation above the CTA
   is retired — the cluster's own tight rhythm applies at every width.) */
/* Mobile/tablet stacking order fix (CSS order, no desktop change): .footer-brand
   dissolves (display:contents) so its two children join the single-column grid as
   separate items — 1 logo+mission (__main), 2 Quick Links, 3-5 Get in Touch (contact ->
   Follow Us -> Join CTA, their DOM order inside .footer-connect), 6 the copyright,
   pushed LAST via order (grid items default to order:0, tree order otherwise). */
@media (max-width: 759.98px) {
  /* Mobile stacking (CSS order only — desktop untouched): both wrappers dissolve so
     the pieces join the single-column grid as orderable items. Tree order gives
     1 logo, mission -> 2 Quick Links -> 3-4 Get in Touch (contact, Follow Us);
     the CTA is pushed to 5 via `order`, and the legal bar (outside the grid) is 6. */
  .footer-brand { display: contents; }
  .footer-brand__main { display: contents; }
  .footer-logo { margin-bottom: 0; }              /* the grid gap now provides the logo->mission rhythm */
  .footer-promise { margin: 0; }                  /* grid gap sets the rhythm; stays with the mission */
  .footer-cta { margin: 0; width: 100%; }   /* 2026-08 three-col: DOM order (brand -> get involved -> contact) is the stack order; no order override */
  .footer-cta__btn { justify-content: flex-start; }   /* quiet link stays LEFT-aligned on phones (full-width pill retired with the demotion) */
}

/* MIDDLE — Quick Links */
.footer-col__title {
  margin: 0 0 0.6rem;
  font-family: var(--font-head);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--white);
}
.footer-nav { list-style: none; margin: 0; padding: 0; }
/* Tightened rhythm: each link KEEPS its full 44px tap box, but consecutive boxes
   overlap by ~6px (negative li margin) so the visible line spacing matches the
   Get in Touch column's compactness instead of stretching the column taller. */
.footer-nav li { margin: 0; }
.footer-nav li + li { margin-top: -0.4rem; }
.footer-nav a { display: inline-flex; align-items: center; min-height: 44px; font-size: 0.95rem; }   /* unified with the Get in Touch body size — one consistent size across the three columns */

/* RIGHT — "Get in Touch": header · contact details · Follow Us + socials · Join button.
   Flex column with an even 1.1rem rhythm; the column title drops its own margin so the
   flex gap alone sets spacing (header style stays identical to the Quick Links column). */
.footer-connect { display: flex; flex-direction: column; align-items: flex-start; gap: 0.55rem; }   /* 2026-08: ONE tight contact cluster (reach us / follow us / join us), not items spread down a tall column */
/* 2026-08: the right column organizes into TWO side-by-side sub-groups on
   desktop/tablet - [Get in Touch + Follow Us] | [GET INVOLVED links] - inside
   the SAME grid column (no third top-level column). Stacks back to the tidy
   left-aligned single column on mobile (the base flex-column above). */
.footer-connect__grp > * + * { margin-top: 0.55rem; }   /* internal rhythm via margins, not a new flex gap */
/* (2026-08 three-col: the former side-by-side sub-group rules are retired -
   GET INVOLVED is its own middle grid column now.) */

.footer-connect .footer-col__title { margin-bottom: 0; }
.footer-follow { display: flex; flex-direction: column; gap: 0.5rem; }        /* "Follow Us" label sits tight above its icons */
.footer-follow__label { margin: 0; font-size: 0.95rem; font-weight: 600; color: var(--white); }
.footer-cta { margin: 0; }   /* 2026-08 sibling headings: the old 0.25rem top nudge was the LAST 4px keeping "Get involved" below "Get in Touch" (it also silently overrode the desktop margin-top:0 alignment rule earlier in the sheet - later same-specificity rule wins) */
/* "Get involved" pair (2026-08): a quiet micro-label above the two sibling
   arrow-links (Join the Movement / Support GEM). Champagne #ECD6AE = the
   footer's documented 8.5:1 on the purple ground - AA even at this size. */
.footer-cta__label {
  /* 2026-08 sibling headings (client direction - supersedes the micro-label
     treatment): matches .footer-col__title ("Get in Touch") EXACTLY - serif
     family, 1.1rem, weight 600, white, sentence case (the HTML was always
     "Get involved"; only the uppercase transform is dropped), normal tracking.
     The old -4px/line-height:1 baseline nudge compensated for the tiny caps
     line box and would now MISALIGN the tops - removed. */
  margin: 0 0 0.35rem;
  font-family: var(--font-head);
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1.2;                /* the h2's line box (21.12px) - the inherited body 1.65 sat the text 4px lower */
  letter-spacing: normal;
  text-transform: none;
  color: var(--white);
}
.footer-cta__item { margin: 0; }
.footer-cta__item + .footer-cta__item { margin-top: -0.6rem; }   /* 2026-08: the two 44px tap boxes hold ~20px text lines - overlapping the boxes ~10px closes the optical gap so Join + Support read as ONE group; both targets stay >=44px (boxes overlap in dead zone only) */   /* 2026-08 cluster: Join sits as the natural LAST line of the block — the old generous desktop separation (1.6rem) is retired with the cluster regroup */
/* DEMOTED (2026-08): the big gold outlined pill is retired — the footer Join is
   now a quiet champagne arrow link ("one more way in"), so it stops competing
   with the header's primary CTA. Tap target stays >=44px via min-height. */
.site-footer .footer-cta__btn {                     /* .site-footer prefix beats the generic `.site-footer a` (0,1,1) on color/decoration */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.2rem 0.1rem;
  border: 0;
  font-weight: 600;
  font-size: 1.15rem;                               /* 2026-08 affordance: 18.4px - the links stay LARGER than their 1.1rem column heading (that hierarchy is deliberate); the .arrowlink-text continuous underline + arrow treatment is unchanged */
  color: #ECD6AE;                                   /* champagne - measured 7.15:1 against the LIGHTEST composited footer pixel = AA */
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.18s ease;
}
.site-footer .footer-cta__btn:hover { color: var(--white); }   /* 10.14:1 worst-case - the arrowlink border follows via currentColor */
/* 2026-08 Support GEM treatment (client-resolved contrast gate, option a):
   targets the SECOND cta item ONLY - "Join the Movement" above keeps its
   champagne 1.15rem styling untouched. 1.17rem = 18.72px crosses the WCAG
   large-bold-text threshold (18.66px), where the canonical gold hover's
   measured 3.68:1 at this footer position is a legitimate AA pass (3.0:1
   bar). Default WHITE (11.71:1 vs the lightest composited pixel behind the
   link) carries full legibility for touch users, where hover never fires.
   Arrow + continuous underline (currentColor) and the white focus ring are
   inherited unchanged. */
.site-footer .footer-cta__item + .footer-cta__item .footer-cta__btn {
  font-size: 1.17rem;
  color: #FFFFFF;
}
.site-footer .footer-cta__item + .footer-cta__item .footer-cta__btn:hover { color: var(--gold); }
/* 2026-08: WHITE focus ring (10.14:1 worst-case on the footer image) - the
   gold ring measured only 3.19:1 against the image's lightest composited
   area, and the --focus token is invisible on dark surfaces site-wide. */
.site-footer .footer-cta__btn:focus-visible { outline: 3px solid #FFFFFF; outline-offset: 3px; border-radius: 6px; }
.footer-social { list-style: none; margin: 0 0 0 -13px; padding: 0; display: flex; gap: 0.4rem; }   /* -13px = the 44px link's inner inset around the 18px glyph, so the first GLYPH stays flush with the "Follow Us" text edge; even 0.4rem spacing */
.footer-social li { margin: 0; }
.footer-social__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;                                      /* ≥44px tap target */
  height: 44px;
  border-radius: 50%;
  color: var(--white);
}
.footer-social__link svg { width: 18px; height: 18px; }   /* 2026-08 refine: quieter glyphs; the 44px tap circle is unchanged */
/* Xiaohongshu placeholder badge — no standard Lucide icon yet (see HTML comment). */
.footer-social__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;                  /* 2026-08: scaled with the 18px glyphs */
  height: 18px;
  padding: 0 0.25rem;
  border: 1px solid currentColor;
  border-radius: 6px;
  font-size: 0.55rem;
  font-weight: 700;
  letter-spacing: 0.05em;
}

/* Copyright now lives inside the left mission column (single-section footer — the
   separate bottom legal bar is gone; a subtle hairline sets it off). */
/* Bottom legal bar: copyright left, small legal links right (they wrap/stack on
   phones). Quiet + compact — the hairline separates it from the columns above;
   the bar carries the border now, not the credit line. */
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0 1.5rem;
  margin-top: 0.7rem;
  padding-top: 0.3rem;
  border-top: 1px solid rgba(187, 134, 63, 0.35);   /* 2026-08: subtle GOLD hairline above the copyright bar (was white 0.14) - understated brand finishing line */
}
/* 2026-08: keep the legal row's text clear of the floating chat/back-to-top
   column. Wherever the container's right edge runs close to the viewport edge
   (the FABs float ~84px wide incl. inset), the row reserves that strip so the
   buttons hover over empty purple, never over copyright/legal text. */
@media (max-width: 1279.98px) {
  .footer-legal { padding-right: 84px; }   /* guard raised from 1240 (2026-08): widths ~1241-1255 still measured the chat FAB over the legal links - the container margin there is thinner than the FAB column */
}
.footer-credit {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--lavender);
  max-width: 64ch;
}
.footer-legal__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}
.footer-legal__links li { display: flex; align-items: center; margin: 0; }
/* 2026-08 wrap fix: the middot now belongs to the PRECEDING item (::after on
   all but the last) instead of the following one (::before) - so when the row
   wraps, the separator stays at the END of its line and a "·" can never
   start a line. The last item carries no trailing separator by selector. */
.footer-legal__links li:not(:last-child)::after {
  content: "\00B7";                           /* subtle middot divider */
  margin: 0 0.5rem;
  color: rgba(255, 255, 255, 0.45);
}
.footer-legal__links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;                           /* tap target, text stays small/quiet */
  font-size: 0.8rem;
  color: var(--lavender);
  white-space: nowrap;                        /* "Privacy Policy" never splits mid-item at any width */
}
/* PHONES: 12px text (the AA/tap floor: >=12px; the 44px-tall hit areas come
   from min-height padding, not text size), tighter middot separators, and a
   whisper of negative tracking. The row WRAPS into two tidy lines: the old
   flex-wrap:nowrap "all on one line" treatment was designed for FOUR links,
   and once Medical Disclaimer became the fifth (2026-08) its ~435px
   min-content row forced every page into horizontal scroll on phones.
   Individual links stay nowrap so none breaks mid-phrase. */
@media (max-width: 479.98px) {
  .footer-legal__links {
    flex-wrap: wrap;
    width: 100%;
    justify-content: flex-start;
  }
  .footer-legal__links a {
    font-size: 0.75rem;                       /* 12px — the stated minimum, NOT shrunk further */
    letter-spacing: -0.01em;
    white-space: nowrap;
  }
  .footer-legal__links li:not(:last-child)::after { margin: 0 0.25rem; }   /* 2026-08: 4.8px -> 4px each side, still clearly separated */
}

/* Contact block (third column, below the socials): email link + placeholder address. */
.footer-contact {
  font-style: normal;                               /* <address> defaults to italic */
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.footer-contact__email { font-size: 0.95rem; }
.footer-contact__addr {
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--lavender);
}

/* Footer link micro-interactions: NO bold, NO underline; hover lifts + shifts to
   gold. prefers-reduced-motion drops the transform (colour shift only). */
.footer-nav a,
.footer-contact__email,
.footer-legal__links a,
.footer-social__link {
  text-decoration: none;
  font-weight: 400;
  transition: color 0.18s ease, transform 0.18s ease;
}
.footer-nav a:hover,
.footer-contact__email:hover,
.footer-legal__links a:hover,
.footer-social__link:hover { color: var(--gold); transform: translateY(-2px); }
.footer-nav a:focus-visible,
.footer-contact__email:focus-visible,
.footer-legal__links a:focus-visible,
.footer-social__link:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 6px; }
@media (prefers-reduced-motion: reduce) {
  .footer-cta__btn,
  .footer-nav a,
  .footer-contact__email,
  .footer-legal__links a,
  .footer-social__link { transition: color 0.18s ease, background-color 0.18s ease; }
  .footer-cta__btn:hover,
  .footer-nav a:hover,
  .footer-contact__email:hover,
  .footer-legal__links a:hover,
  .footer-social__link:hover { transform: none; }
}

/* Compact header: collapse the nav behind the hamburger below 1400px.
   Current value (2026-08): 1400 = measured true fit 1335px + 25px Safari
   text-metrics allowance + 40px safety. Above 1400: the FULL one-line row;
   the nav <ul>'s flex-wrap net still guarantees trailing items WRAP to a
   2nd line (bar grows) rather than crossing the logo if anything ever
   overflows. Scoped to .js (added by ui.js) so the no-JS experience keeps
   the nav visible. MUST match the navHoverMode() breakpoint in ui.js. */
@media (max-width: 1399.98px) {
  .js .nav-toggle { display: inline-flex; }
  .js .primary-nav { display: none; }
  .js .primary-nav.is-open {
    display: block;
    position: absolute;
    left: 0; right: 0;
    top: 100%;
    /* No backdrop-filter here (nor -webkit-): the header is a backdrop root, so a descendant blur samples nothing.
       COOKIE-BANNER MATCH (GEM, Aug 2026): solid #F2EEF8 (--lavender) = the banner's own authored opaque panel
       (its no-blur fallback; the banner's frosted form composites to ~#F5F1F9 over white, <=4 RGB pts lighter).
       Fully opaque by requirement. Supersedes the #EEE4FB header-composite pass. */
    background-color: #F2EEF8;
    background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0) 60%);
    border-bottom: 1px solid rgba(255, 255, 255, 0.22);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.40), 0 14px 30px rgba(20, 14, 40, 0.45);   /* the header's lit top rim + the drawer's existing drop shadow */
    z-index: 50;
    /* Sticky header means the open menu can't rely on page scroll to reveal a
       long list — let the panel itself scroll if it exceeds the viewport.
       vh first as the fallback for browsers without dvh (Safari <15.4).
       Offset = the MEASURED header height (--header-h, set by ui.js) — the old
       hardcoded 82px predated the taller logo header (~88-136px) and let a long
       menu overrun the viewport bottom before its internal scroll engaged. */
    max-height: calc(100vh - var(--header-h, 110px));
    max-height: calc(100dvh - var(--header-h, 110px));
    overflow-y: auto;
  }
}
/* 2026-08: at TABLET/MEDIUM widths the open menu is a COMPACT right-anchored
   panel below the header (content-height, rounded, shadowed) - premium for a
   7-item menu instead of a full-screen-width sheet. TRUE MOBILE (<640px)
   keeps the full-width drawer from the base rule above. Static reveal (no
   animation added - reduced-motion trivially safe); Esc/outside/link close +
   the focus trap live in ui.js. */
@media (min-width: 640px) and (max-width: 1399.98px) {
  .js .primary-nav.is-open {
    left: auto;
    right: clamp(12px, 2vw, 24px);
    width: min(360px, calc(100vw - 24px));
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-top: 0;
    border-radius: 0 0 14px 14px;
  }
}

/* --- Mobile header action cluster: search · globe · | · hamburger ----------
   The .header-tools (search + language switcher) is display:contents, so its
   children flatten into this flex row alongside the gold divider and hamburger.
   Bare icons (no boxes/pills), deep purple, 44x44 tap targets, airy spacing. */
@media (max-width: 1399.98px) {
  .header-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 0 0 auto;              /* icon cluster pinned right; never shrinks below its 44px targets */
  }
  /* Spacing via margins, not flex gap (Safari <14.1 has no flex gap). The
     .header-tools children flatten in via display:contents, so the lobotomised
     owl catches every visible sibling in the row. */
  .header-actions > * + *,
  .header-tools > * + * { margin-left: 0.3rem; }

  /* Bare icon buttons — search + globe. No background box or pill. */
  .header-search,
  .lang-switcher__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px; height: 44px;   /* min 44x44 tap target even though the glyph is smaller */
    min-width: 44px;
    padding: 0;
    margin: 0;
    background: transparent;
    border: 0;                   /* removes the language pill outline on mobile */
    border-radius: 8px;
    color: var(--purple);        /* #3A2A66 deep purple */
    cursor: pointer;
  }
  .header-search__icon,
  .lang-switcher__globe { width: 18px; height: 18px; }   /* small + quiet — secondary utilities,
                                                            matching their understated desktop size;
                                                            the hamburger keeps its full weight as
                                                            the clear primary control */

  /* Globe glyph only — hide the "EN" text and caret on mobile. */
  .lang-switcher__globe { display: inline-block; }
  .lang-switcher__label,
  .lang-switcher__caret { display: none; }
  .lang-switcher { margin: 0; }          /* was indented for the old in-hamburger spot */

  /* Matching gold hairline dividers between every control:
     search · | · globe · | · sign-in · | · hamburger.
     Both .header-divider--tools spans are now legitimate on mobile (the second one
     separates the globe from the sign-in icon, which is shown in the cluster since
     2026-07-09); .header-actions__divider is the sign-in→hamburger hairline. All
     three are identical; the .header-actions flex gap (0.4rem) keeps the row airy. */
  .header-divider--tools,                      /* search · | · globe · | · sign-in */
  .header-actions__divider {                   /* sign-in · | · hamburger */
    display: inline-block;
    flex: 0 0 auto;
    width: 1px;
    height: 18px;                        /* shorter hairline to match the quieter icons */
    background: var(--gold);             /* #BB863F */
  }

  /* Clear, visible keyboard focus for every icon in the cluster. */
  .header-search:focus-visible,
  .lang-switcher__button:focus-visible,
  .nav-toggle:focus-visible {
    outline: 3px solid var(--focus);
    outline-offset: 2px;
    border-radius: 8px;
  }

  /* Language menu now hangs DOWN from the globe in the top bar (it used to open
     upward as the last item in the hamburger), right-aligned to stay on-screen. */
  .lang-switcher__menu {
    top: calc(100% + 0.5rem);
    bottom: auto;
    left: auto;
    right: 0;
  }
  /* Comfortable touch targets for each language row on mobile (>= 44px tall). */
  .lang-switcher__item { min-height: 44px; }

  /* The search panel (.mobile-search) is styled at base level below so it works
     on both mobile and desktop. */
}

/* Narrow phones (<=430px): the four 44px action icons floor the right cluster,
   so scale the whole logo lockup down (crest + wordmark together, proportions
   kept) until it clears them with real space between — no overlap, no scroll at
   375px. Width-based, so it's identical before and after scroll. */
@media (max-width: 430px) {
  .brand { --crest-h: clamp(44px, 11vw, 52px); }   /* small phones: still larger than before, cluster never collides (checked at 360px) */
  .header-inner > .brand { margin-right: 0.75rem; }   /* guaranteed space between the two groups (margin, not flex gap) */
}

/* --- Header search panel: slides down below the header on tap/click ----------
   Works at every width (desktop utility-strip search + mobile header search).
   Reveal is a fade + short downward slide (opacity + transform), with visibility
   flipped so the input and results stay out of the tab/AT order while closed —
   the canonical accessible pattern (and it leaves the results dropdown free to
   extend below the bar, unclipped). Absolute, so opening never shifts the header
   or hero. (Named .mobile-search for historical reasons.) */
.mobile-search {
  position: absolute;
  top: 100%; left: 0; right: 0;
  z-index: 49;                       /* just under the open mobile nav panel (50) */
  visibility: hidden;               /* keeps the input + results out of tab/AT order while closed */
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity 0.25s ease, transform 0.25s ease, visibility 0s linear 0.25s;
}
.mobile-search.is-open {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.25s ease, transform 0.25s ease, visibility 0s;
}
.mobile-search__bar {
  background: var(--cream);
  border-bottom: 3px solid var(--gold);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.12);
}
.mobile-search .container { padding-block: 0.65rem; }
.mobile-search__form {
  display: flex;
  align-items: center;
  max-width: 640px;                 /* comfortable width on desktop; full-width on phones */
  margin-inline: auto;
  background: var(--white);
  border: 1.5px solid rgba(58, 42, 102, 0.25);
  border-radius: 999px;
  padding: 0.15rem 0.4rem 0.15rem 0.9rem;
}
.mobile-search__form:focus-within { border-color: var(--purple); }
.mobile-search__form > * + * { margin-left: 0.5rem; }   /* control spacing via margins, not flex gap (Safari <14.1) */
.mobile-search__icon { flex: 0 0 auto; width: 20px; height: 20px; color: var(--text-muted); }
.mobile-search__input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.55rem 0;
  border: 0;
  background: transparent;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--text);
}
.mobile-search__input:focus { outline: none; }
.mobile-search__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--purple);
  cursor: pointer;
}
.mobile-search__close:hover { background: var(--lavender); }
.mobile-search__close svg { width: 20px; height: 20px; }
.mobile-search__close:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* Live results dropdown — a white card under the input, aligned to the same width. */
.mobile-search__results {
  max-width: 640px;
  margin: 0.5rem auto 0;
  max-height: min(60vh, 22rem);
  overflow-y: auto;
  background: var(--white);
  border: 1px solid var(--lavender);
  border-radius: var(--radius);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.12);
  padding: 0.35rem;
}
.mobile-search__results[hidden] { display: none; }
.mobile-search__result {
  display: block;
  padding: 0.55rem 0.7rem;
  min-height: 44px;                 /* comfortable tap target on mobile */
  border-radius: 8px;
  text-decoration: none;
  color: var(--text);
}
.mobile-search__result:hover,
.mobile-search__result.is-active { background: var(--lavender); }
.mobile-search__result-title {
  display: block;
  font-weight: 600;
  color: var(--purple);
  font-size: 0.95rem;
  line-height: 1.3;
}
.mobile-search__result-desc {
  display: block;
  margin-top: 0.1rem;
  color: var(--text-muted);
  font-size: 0.85rem;
  line-height: 1.35;
  overflow: hidden;                 /* one-line excerpt */
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mobile-search__result mark {
  background: rgba(187, 134, 63, 0.28);   /* soft brand-gold highlight */
  color: inherit;
  font-weight: 700;
  border-radius: 3px;
  padding: 0 1px;
}
.mobile-search__empty { padding: 0.9rem 0.8rem; text-align: center; }
.mobile-search__empty-title { margin: 0; font-weight: 600; color: var(--purple); }
.mobile-search__empty-hint { margin: 0.25rem 0 0; font-size: 0.9rem; color: var(--text-muted); }

@media (prefers-reduced-motion: reduce) {
  .mobile-search { transition: none; }
}

/* --- Sign-in scaffolding (understated auth placeholders) --------------------
   Desktop: a quiet "Sign in" text link lives in the utility strip (shown in the
   desktop query below). (2026-08: the drawer's duplicate "Sign in" item was
   removed - the 44px login icon in the collapsed cluster is the login entry.) */
.header-signin { display: none; }        /* hidden by default; text link on desktop (min-width:960
                                            block), icon link in the mobile cluster (block below) */
.header-signin__icon { display: none; }  /* person glyph is mobile-only; desktop keeps the quiet text */
/* Mobile: "Sign in" joins the top-bar cluster as a small person-icon link, styled
   like the search + globe utilities (18px glyph, 44x44 tap target, aria-label on
   the anchor). This block must sit AFTER the base display:none above to win. */
@media (max-width: 1399.98px) {
  .header-signin {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px; height: 44px;           /* min 44x44 tap target, same as its neighbours */
    min-width: 44px;
    color: var(--purple);
  }
  .header-signin__icon { display: inline-block; width: 18px; height: 18px; }
  .header-signin__label { display: none; }
  .header-signin:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 8px; }
}
/* "Already registered? Sign in" line above a registration form — quiet, secondary. */
.form-signin-prompt {
  margin: 0 0 1.5rem;
  font-size: 0.92rem;
  color: var(--text-muted);
}
.form-signin-prompt a { color: var(--purple); font-weight: 600; text-underline-offset: 3px; }
/* Identifier-first: the email leads, set apart from the rest by a hairline. */
.form-divider {
  border: 0;
  border-top: 1px solid var(--lavender);
  margin: 1.5rem 0;
}

/* ===================================================================
   7. Desktop (>= 1280px): nav inline, no hamburger
   (1280 = the header collapse breakpoint — below it the hamburger shows)
   =================================================================== */
@media (min-width: 1400px) {
  /* (The old 210px scroll-padding for the retired 3-row header is gone — the
     editorial 88px rule later in the sheet is the live value at every width.) */
  .nav-toggle { display: none; }

  /* Desktop logo = the full horizontal lockup, kept EXACTLY as-is (not restyled). */
  .brand-logo--horizontal { height: clamp(68px, 6.5vw, 96px); }
  .brand-name { display: block; }

  /* Three-row header.
     Row 0 (utility strip): ................................. search · | · EN
     Row 1 (masthead): logo | divider | NAME (centred in the freed space)
     Row 2 (nav): the menu, spread evenly across the full container width. */
  .header-inner {
    display: grid;
    grid-template-columns: auto auto 1fr;
    grid-template-areas:
      "util util util"
      "logo vdiv name"
      "nav  nav  nav";
    align-items: center;
    column-gap: 1.5rem;
    row-gap: 0;
    padding-block: 0;
    z-index: 1;                 /* content sits above the full-width utility band (.site-header::before) */
  }
  .brand { grid-area: logo; align-self: center; padding-block: 0.75rem; }

  /* Thin vertical dividers (soft). The brand divider spans the logo's height. */
  .header-divider { display: block; background: rgba(58, 42, 102, 0.2); }
  .header-divider--brand { grid-area: vdiv; align-self: center; width: 1px; height: clamp(22px, 2.2vw, 32px); }
  .header-divider--tools { width: 1px; height: 1.5rem; }

  /* Organisation name — live text: Lora, deep purple, large, generously tracked,
     vertically centred against the logo. No slogan. */
  .brand-name {
    grid-area: name;
    align-self: center;
    margin: 0;
    max-width: none;
    font-family: var(--font-display);   /* Playfair Display */
    font-size: clamp(1.2rem, 2vw, 1.85rem);
    font-weight: 700;                    /* Bold */
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--purple);
    text-align: center;
    white-space: nowrap;
    line-height: 1.15;
  }

  /* Utility strip (Row 0): search · divider · EN, right-aligned and visually
     quieter than the masthead below (smaller, lighter). The full-width band
     behind it is .site-header::before; content stays within the container. */
  .header-tools {
    grid-area: util;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.7rem;
    min-height: 2.3rem;         /* modest strip height */
  }
  .header-search {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem;
    background: transparent;
    border: 0;
    border-radius: 8px;
    color: var(--purple);
    cursor: pointer;
  }
  .header-search:hover { background: var(--lavender); }
  .header-search:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
  .header-search__icon { width: 18px; height: 18px; }          /* smaller in the quiet strip */
  .header-divider--tools { height: 1.15rem; }                  /* shorter divider to match */
  .header-tools .lang-switcher__button { font-size: 0.8rem; font-weight: 500; padding: 0.28rem 0.6rem; }  /* quieter EN */
  .lang-switcher__globe { display: inline-block; width: 14px; height: 14px; }   /* globe before EN */
  /* Quiet "Sign in" text link at the right end of the utility strip. */
  .header-signin {
    display: inline-flex;
    align-items: center;
    color: var(--purple);
    font-size: 0.8rem;
    font-weight: 500;
    text-decoration: none;
    padding: 0.28rem 0.2rem;
    border-radius: 8px;
  }
  .header-signin:hover { text-decoration: underline; text-underline-offset: 3px; }
  .header-signin:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

  /* Row 2 nav: display:contents lifts the ul + tools into the header grid, so the
     ul lands in Row 2 (grid-area nav) and the tools land in Row 1 (grid-area tools).
     Items spread evenly across the full width; a soft rule separates the two rows. */
  .primary-nav { display: contents; }
  .primary-nav > ul {
    grid-area: nav;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.5rem 0 0.45rem;
    border-top: 1px solid rgba(58, 42, 102, 0.12);
  }
  .primary-nav > ul a { padding: 0.5rem 0.6rem; white-space: nowrap; }
  .lang-switcher { margin: 0; }
  /* EN menu opens downward, right-aligned so it never clips the edge. */
  .lang-switcher__menu { top: calc(100% + 0.4rem); bottom: auto; left: auto; right: 0; }

  /* Soft full-width rule beneath the whole header, before the hero (desktop only;
     mobile keeps its original gold border). Replaces the bold gold border here. */
  .site-header { border-bottom: 1px solid rgba(58, 42, 102, 0.14); }
  /* Utility strip band (Row 0), edge to edge. Transparent AND borderless (the old
     hairline under the strip was removed 2026-07-09) so the whole header reads as
     one seamless cream (#FBF9F4) — no visible line between the utility strip and
     the masthead. The nav row's border-top and the header's bottom rule remain. */
  .site-header::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2.3rem;                          /* matches the utility strip height */
    background: transparent;                 /* seamless with the masthead/nav — no tint */
    z-index: 0;
    pointer-events: none;
  }

  /* Insights-style dropdown → absolute panel below the toggle (like the language
     menu). Opens on hover, on keyboard focus, or when explicitly toggled. */
  .nav-menu__toggle { width: auto; padding: 0.5rem 0.6rem; white-space: nowrap; }
  .nav-menu {
    position: absolute;
    top: calc(100% + 0.4rem);
    left: 0;
    min-width: 230px;
    padding: 0.35rem;
    background: var(--white);
    border: 1px solid var(--lavender);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(46, 33, 80, 0.15);
    z-index: 60;
  }
  .nav-item--has-menu:hover > .nav-menu,
  .nav-item--has-menu.is-open > .nav-menu { display: block; }
  /* Invisible bridge over the 0.4rem gap so moving the cursor from the toggle down
     into the panel stays continuous (no dead zone that would drop the hover). */
  .nav-menu::before {
    content: "";
    position: absolute;
    top: -0.4rem; left: 0; right: 0;
    height: 0.4rem;
  }
  .primary-nav .nav-menu li { margin: 0; }
  .primary-nav .nav-menu a {
    display: block;
    padding: 0.55rem 0.7rem;
    border-radius: 8px;
    white-space: nowrap;
    font-weight: 500;
    color: var(--purple);
  }
  .primary-nav .nav-menu a:hover {
    background: var(--lavender);
    color: var(--purple-bright);
  }
  .primary-nav .nav-menu a:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
}

/* ===================================================================
   8. Home page
   =================================================================== */

/* --- Sanctuary hero (background video with still-image fallback) --- */
.hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;                    /* own stacking context for the video/overlay layers */
  display: flex;
  align-items: center;
  min-height: clamp(440px, 62vh, 660px);
  padding-block: clamp(3rem, 8vw, 6rem);
  /* 2026-08: the bright hero-home.webp still-image fallback is RETIRED (the
     dark-first hero rests on its deep-purple layer instead - see
     .hero--editorial) and the image file has been deleted from the repo, so
     the old background-image rule is removed rather than pointing at a
     missing asset. The dark color below is the base fallback. */
  background-color: #2E2150;
}
/* Background video: covers the hero (no distortion). Hidden until ui.js enables it
   (wider viewports, motion allowed, not data-saver). Poster is the still image. */
/* DARK-FIRST underlay (2026-08): brand deep purple from the first paint,
   under the video (same z-plane, earlier in DOM), over the section bg.
   Nothing bright can show before the dark intro is visibly playing. */
.hero__dark {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 0;
  background: #2E2150;
  pointer-events: none;
}
.hero__video {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  display: none;
  opacity: 0;                     /* covered until playback is CONFIRMED (.video-live) */
  pointer-events: none;
  /* Invisible cinematic loop (Step 12): a 2nd stacked video (.hero__video--b) is
     created by ui.js directly above this one (still below the copy + overlay).
     Only B's opacity animates; the duration is set by ui.js via the CSS var. */
  transition: opacity var(--hero-loop-crossfade-ms, 1400ms) ease;
}
.hero.has-video .hero__video { display: block; }
/* Reveal only once the browser CONFIRMS playback ('playing' -> ui.js adds
   .video-live): the dark footage fades in over the identical dark underlay,
   so the intro reads as one continuous dark scene - never a bright pop. */
.hero.video-live .hero__video { opacity: 1; }
/* Homepage editorial hero is dark-first: kill the bright still fallback
   (.hero base bg) - every pre-video / fallback state rests on the dark
   layer instead. Only index.html uses .hero, but scoped to the modifier
   anyway. Also saves the ~like-for-like webp download it replaced. */
.hero--editorial { background-image: none; background-color: #2E2150; }
.hero__video--b { opacity: 0; }   /* the standby/crossfade layer starts hidden */
/* Contrast overlay: soft purple, a bit stronger on the left behind the headline
   and fading to near-clear on the right so the footage reads clearly. White copy
   stays at WCAG AA (helped by the hero text-shadow below). */
.hero::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 1;
  /* 2026-08: the base pseudo is STRUCTURAL ONLY - the text-anchored scrim
     lives on .hero--editorial::after (section 12), which owns the cascade
     at every width. The old gold glow + horizontal purple tint that lived
     here are gone (they read as fog over the footage). */
  background-image: none;
}
.hero > .container { position: relative; z-index: 2; }
.hero--editorial > .container { display: flex; flex-direction: column; width: 100%; }   /* lets hero__intro fill the height for the top/bottom split. width:100% is the fix for the doorway drift: the base .hero is display:flex, so this container was a shrink-to-CONTENT flex item (narrower than 1120 + off-centre). width:100% makes it fill to the SAME max-width:1120 block width as the evidence .container below, so the four doorways line up column-for-column with the four stats. */

/* Scene 1 opening TEXT LAYER (v2 footage, 2026-08): the intro darkness is now
   BAKED INTO the video itself (its first ~5s are the dark portion), so this
   layer carries ONLY the solitude line floating over the video's own darkness —
   its old near-black background screen is retired (restore from history if the
   overlay intro ever returns). The line reveals WORD BY WORD, holds, then fades
   out before the footage brightens. Decorative (aria-hidden); the <h1> is the
   real headline. Shown ONLY with JS + motion allowed — hidden for no-JS,
   reduced-motion, and the autoplay-blocked path (.no-intro). */
.hero__opening {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 5;                          /* above the copy (z2) and scrims (z1) during Scene 1 */
  display: none;                       /* no-JS / reduced-motion: never shown */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.25rem;
  text-align: center;
  pointer-events: none;                /* never blocks the CTA or scroll cue */
  background: transparent;             /* the darkness is the video's own — NO second dark layer */
}
.hero.no-intro .hero__opening { display: none !important; }
.hero.intro-done .hero__opening {
  opacity: 0;
  visibility: hidden;
  /* Scene 1 -> Scene 2: the dark screen + line fade OUT (the video is already playing
     beneath, under the purple wash). Duration = HERO_INTRO_TEXT_FADEOUT_MS via the var. */
  transition: opacity var(--hero-intro-text-fadeout-ms, 1000ms) ease,
              visibility 0s linear var(--hero-intro-text-fadeout-ms, 1000ms);
}
.hero__opening-line {
  margin: 0;
  max-width: 22ch;
  font-family: var(--font-head);       /* Lora — the site's elegant serif */
  font-weight: 600;
  font-size: clamp(2.1rem, 6.2vw, 4.6rem);   /* commanding + cinematic; the min keeps "endometriosis" within the frame at 375px */
  line-height: 1.28;
  letter-spacing: -0.01em;             /* refined tightening at display size */
  color: #F0EDF4;                      /* soft off-white words — ~15:1 on the footage's near-black intro = AA */
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.55);   /* per-glyph safety halo now that the ground is live footage, not a coded solid */
}
/* Word-by-word reveal: each word starts hidden and eases in on a stagger (the
   animation lives in the no-preference block below); the whole line then fades out
   together via .intro-done. */
.hero__opening-word { display: inline-block; opacity: 0; }
.hero__opening-word--accent {
  color: #6B4FA0;                      /* brand purple-bright "No" — the palette purple that clears AA-large (~3.3:1) on the near-black (#3A2A66 would not); the glow lifts its presence */
  text-shadow: 0 0 20px rgba(107, 79, 160, 0.55), 0 0 7px rgba(150, 120, 210, 0.5);
}
/* RETIRED with the v2 footage (2026-08): the code-applied solitude wash is no
   longer driven by ui.js — the scene's darkness and its brightening are baked
   into the video itself. The element + this rule stay (opacity 0 = invisible,
   zero cost) purely for easy rollback; nothing raises it any more. */
.hero__wash {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 1;                          /* over the video, under the copy (z2) */
  pointer-events: none;
  background: #2E2150;                 /* brand deep purple */
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  /* Shown from first paint (html.js is set before render) so there is no poster flash
     before the opening; ui.js then triggers the word-by-word reveal, then fades it out. */
  .js .hero--editorial .hero__opening { display: flex; }
  /* STEP 1 — word-by-word: each word eases up + in, staggered by --hero-intro-word-stagger-ms
     (JS-set), each over --hero-intro-word-fade-ms. Reduced-motion skips all of this. */
  .hero.is-introing .hero__opening-word {
    animation: heroWordIn var(--hero-intro-word-fade-ms, 620ms) cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
  }
  .hero.is-introing .hero__opening-word:nth-child(1) { animation-delay: calc(var(--hero-intro-word-stagger-ms, 320ms) * 0); }
  .hero.is-introing .hero__opening-word:nth-child(2) { animation-delay: calc(var(--hero-intro-word-stagger-ms, 320ms) * 1); }
  .hero.is-introing .hero__opening-word:nth-child(3) { animation-delay: calc(var(--hero-intro-word-stagger-ms, 320ms) * 2); }
  .hero.is-introing .hero__opening-word:nth-child(4) { animation-delay: calc(var(--hero-intro-word-stagger-ms, 320ms) * 3); }
  .hero.is-introing .hero__opening-word:nth-child(5) { animation-delay: calc(var(--hero-intro-word-stagger-ms, 320ms) * 4); }
  .hero.is-introing .hero__opening-word:nth-child(6) { animation-delay: calc(var(--hero-intro-word-stagger-ms, 320ms) * 5); }
}
@keyframes heroWordIn {
  from { opacity: 0; transform: translateY(0.3em); }
  to   { opacity: 1; transform: none; }
}

/* Hero copy sits directly over the video — no panel or scrim behind it. Legibility
   comes from the original .hero::after overlay plus a soft text-shadow on each line. */

/* Hero typographic hierarchy: headline dominates, then subtitle, then description. */
/* 1. Headline — Playfair Display Bold, the largest type on the page; tight leading. */
.hero h1 {
  max-width: 16ch;
  font-family: var(--font-display);   /* Playfair Display */
  font-size: clamp(2.5rem, 6.7vw, 4.5rem);   /* ~40px mobile → ~72px desktop */
  font-weight: 700;
  line-height: 1.0;                   /* tightened so the two lines sit close for impact */
  letter-spacing: -0.01em;
  color: var(--white);
  /* Soft shadow on the glyphs themselves (no panel) — a tight dark edge plus a
     wide diffuse halo so the headline holds up over brighter video frames. */
  text-shadow: 0 1px 3px rgba(24, 16, 44, 0.55), 0 2px 20px rgba(24, 16, 44, 0.45);
}
/* 2. Subtitle — clearly second in size; italic serif, brand gold, over the video. */
.hero__subtitle {
  font-family: var(--font-head);      /* Lora italic */
  font-style: italic;
  font-weight: 600;
  font-size: clamp(1.5rem, 2.7vw, 2rem);     /* 24px mobile → 32px desktop; always ≥24px = large text for AA */
  line-height: 1.2;
  color: var(--gold);                 /* #BB863F */
  max-width: 34ch;
  margin: 0.65rem 0 1rem;
  /* Gold is a mid-tone, so it needs the most help now the panel is gone — a soft,
     layered shadow (never a box) keeps it legible over brighter video frames. */
  text-shadow: 0 1px 2px rgba(24, 16, 44, 0.92), 0 1px 10px rgba(24, 16, 44, 0.72), 0 3px 22px rgba(24, 16, 44, 0.5);
}
/* 3. Description — supporting body, Inter, soft white, smallest of the three. */
.hero__lede {
  font-size: clamp(1rem, 1.6vw, 1.125rem);   /* 16 → 18px */
  color: rgba(255, 255, 255, 0.9);    /* soft white */
  max-width: 44ch;
  margin-bottom: 2rem;
  text-shadow: 0 1px 3px rgba(24, 16, 44, 0.6), 0 2px 14px rgba(24, 16, 44, 0.5);
}

/* Mobile: video plays too (or the still shows). A softer overlay, strongest
   through the middle band where the full-width headline/lede sit and lighter at
   the top and bottom edges so the footage shows through. Text-shadow (below)
   keeps the copy at WCAG AA over brighter frames. */
@media (max-width: 759px) {
  /* Favor the right of the video so the seated woman and the group walking
     toward the sun stay in frame (default center crops to the unreadable left). */
  .hero__video { object-position: 80% center; }
}

/* --- Featured (sample cards in a gentle auto-scrolling marquee) --- */
/* Saturated purple watercolor with a baked-in white frame (featured-bg.jpg),
   toned down into a soft textured wash: a cream overlay strong across the top
   band (the watercolor's most saturated pigment sits up top, exactly where the
   eyebrow/heading/subtitle live — held ≥0.82 there for AA) easing to ~0.6 behind
   the solid white cards, where the texture can read. At this strength the frame
   melts into the wash rather than reading as a framed picture. Scoped to
   .featured so it never bleeds. background-color is the load fallback. */
/* Softest lavender-tint wash — barely off-white, just enough to separate this
   section from the white Mission above and the Experts section below while the
   purple duotone cards pop against a LIGHT ground. (Dark grounds are reserved
   for the quote + closing bands.) */
/* Step 13: the "second climax" — TALL band; generous vertical room (padding only,
   content untouched) so Featured reads as a peak in the page's height arc. */
.featured { background: var(--lavender-light); padding-block: clamp(4rem, 8vw, 6.5rem); }

/* Homepage experts row — soft lilac leaf-art (experts-bg.jpg) under a very light
   lavender wash, full-bleed behind the centered container. The white specialist
   cards keep their own solid background + shadow and are untouched. */
.section--experts-bg {
  background-color: var(--lavender);   /* fallback while the image loads */
  background-image:
    linear-gradient(rgba(242, 238, 248, 0.42), rgba(242, 238, 248, 0.42)),
    url("../img/backgrounds/experts-bg.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: scroll;
}
.featured h2 { color: var(--purple); font-size: var(--fs-h2); }
.featured__note { color: var(--text-muted); font-size: var(--fs-lede); margin: 0.25rem 0 0; }

/* Marquee viewport: natively scrollable (swipe / drag / wheel / scrollbar).
   ui.js adds a slow auto-scroll with a seamless loop that pauses on hover and
   keyboard focus; with prefers-reduced-motion it stays a static, swipeable row. */
.marquee {
  overflow-x: auto;
  overflow-y: hidden;
  margin-top: 1.25rem;
  scrollbar-width: thin;
  scrollbar-color: rgba(58, 42, 102, 0.35) transparent;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;   /* manual swipes + the JS auto-advance both rest on a whole-card boundary — never a half-card sliver at rest */
}
.marquee:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; border-radius: var(--radius); }
.marquee__track {
  display: flex;
  align-items: stretch;
  width: max-content;
  margin: 0;
  padding: 0.4rem 0 1rem;   /* zero inline pad so the first card aligns to the container edge (= Experts grid edge); top/bottom keep room for the hover lift + scrollbar */
  list-style: none;
}
/* Gap via margin (not flex gap) so the JS loop unit is an exact multiple.
   Gutter matches the Experts grid gap so Featured + Experts share one rhythm. */
.marquee__item { flex: 0 0 auto; display: flex; margin-inline-end: clamp(0.9rem, 2vw, 1.25rem); scroll-snap-align: start; }
/* ============ STATIC PERSPECTIVES ROW (2026-08, carousel retired) ============
   .marquee--static replaces the auto-scroll marquee for the three remaining
   cards: no scroller, no snap, no scrollbar, no JS (the [data-marquee]
   attribute is removed in the HTML so ui.js's generic marquee block finds
   nothing and stays inert - kept because it is generic and is the restore
   path). Card sizes are UNTOUCHED: the existing responsive width rules
   (1-up phone / 2-up tablet / 3-up desktop) still size every card; at
   desktop three cards + two ~20px gutters exactly fill the 1080px container,
   so the row is evenly distributed and flush - "more gap" would require
   shrinking cards, which is locked. Tablet (600-959px) wraps 2+1 (cards are
   half-width there by design); phones stack 1-up. */
.marquee--static {
  overflow: visible;
  scroll-snap-type: none;
  scrollbar-width: auto;
}
.marquee--static .marquee__track {
  width: 100%;
  flex-wrap: wrap;
  justify-content: center;
}
.marquee--static .marquee__item {
  scroll-snap-align: none;
  margin: 0 0.625rem 1.25rem;   /* wrapped ranges (<960): 10px sides = ~20px between cards, rows centred */
}
@media (min-width: 960px) {
  /* Desktop: three cards + two gutters exactly fill the container (the card
     width formula reserves 2 x ~20px) - space-between distributes those
     gutters evenly with zero slack; side margins must be 0 or the row
     overflows its own math and wraps. */
  .marquee--static .marquee__track { justify-content: space-between; }
  .marquee--static .marquee__item { margin: 0 0 0.5rem; }
}
/* (The .marquee--static rules above are INERT since the 2026-08 carousel
   restore - no markup carries the class - and are retained as the static-row
   restore path.) */

/* ============ PERSPECTIVES AUTO-CAROUSEL (restored 2026-08) =================
   Stepped, transform-driven slider (NOT the old rAF drift): ui.js advances one
   card every 7s with a 0.7s slide, clones one set for the seamless wrap,
   pauses on hover/focus/touch/pause-button, and moves nothing under
   prefers-reduced-motion (transition killed below; timer never starts).
   Card sizes/styling are untouched - the .feature-card width formula and the
   .marquee__item gap rule still size everything. NO-JS: the viewport ships as
   a plain native scroller (overflow-x below) and the controls ship [hidden] -
   the .js gates upgrade it, so no-JS never sees a dead control. */
.pcarousel { margin-top: 1.25rem; }
.pcarousel__viewport {
  overflow-x: auto;                          /* no-JS fallback: swipeable row */
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}
.js .pcarousel__viewport { overflow-x: hidden; }   /* the keyframe transform drives position; the viewport clips */
/* CONTINUOUS DRIFT (2026-08, replaces the stepped 7s slide): the track holds
   TWO copies of the card set (ui.js clones one, aria-hidden), so animating to
   -50% lands exactly one set to the left - a seamless, invisible wrap. The
   animation is a pure compositor transform (no JS scroll loop); ui.js sets
   --pmq-dur from the measured set width so the speed is a constant 30px/s at
   every viewport. Pause states flip animation-play-state, preserving the
   position. Keyboard focus (.is-kbd) switches the row to a STATIC native
   scroller so a focused card is always scrollable into view. */
.js .pcarousel.is-animated .marquee__track {
  animation: pcarousel-drift var(--pmq-dur, 40s) linear infinite;
  will-change: transform;
}
@keyframes pcarousel-drift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
.pcarousel.is-paused .marquee__track { animation-play-state: paused; }
.pcarousel.is-kbd .marquee__track { animation: none; }
.js .pcarousel.is-kbd .pcarousel__viewport { overflow-x: auto; }
@media (prefers-reduced-motion: reduce) {
  .js .pcarousel .marquee__track { animation: none !important; }   /* NO automatic motion of any kind */
  .js .pcarousel__viewport { overflow-x: auto; }                   /* static, manually swipeable row */
}
/* (.pcarousel .marquee__item.is-offstage retired with the stepped carousel -
   the marquee's clones are aria-hidden from birth and real cards stay in the
   tab order via the .is-kbd static mode.) */
/* (Controls row retired Aug 2026 at GEM's request - the pause/play control
   and the earlier dot indicators are gone; their .pcarousel__controls/__pause/
   __dot* rules are removed. The marquee's hover/focus/touch/hidden-tab pause
   states above are unaffected.) */

.feature-card {
  display: flex;
  flex-direction: column;
  flex: 1;
  /* Sized so a set number of cards span the container width: 1 (+ a peek) on
     mobile, 2 on tablet, 4 on desktop (breakpoint overrides below). CW = the
     container content width = min(100vw - 3.6rem, 1080px); gap between cards = 1rem. */
  width: calc(min(100vw - 3.6rem, 1080px) - 2.75rem);  /* Step 9: bigger single card, slimmer peek */
  padding: 1.25rem;                /* roomier around media + text (was 1rem) */
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.10);
  border-radius: var(--radius);
  box-shadow: 0 8px 26px rgba(46, 33, 80, 0.13);   /* Step 9: deeper lift for a more immersive row */
  text-decoration: none;
  color: var(--purple);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.feature-card:hover { transform: translateY(-4px); box-shadow: 0 18px 40px rgba(46, 33, 80, 0.20); }
.feature-card:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* "Sample" pill — now carried only by the plain placeholder card. */
.feature-card__tag {
  position: absolute;
  top: 0.5rem; right: 0.5rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--purple-deep);       /* dark on the light pill → AA */
  background: var(--white);
  border: 1px solid var(--gold);
  padding: 0.12rem 0.45rem;
  border-radius: 999px;
}
.feature-card__label {
  font-family: var(--font-head);
  font-size: var(--fs-h3);       /* unified card-title size */
  font-weight: 600;
  color: var(--purple);
  margin-bottom: 0.35rem;
}
.feature-card__teaser { font-size: var(--fs-body); line-height: 1.5; color: var(--text-muted); }  /* unified body size */

/* --- Editorial carousel cards: image fills the card under a duotone overlay ---
   Same visual language as the retired homepage feature tiles. Three stacked
   overlay layers, all deep purple, so wildly different source images (a warm
   portrait, two busy pale infographics) resolve into one family:
     1. top scrim  - carries the gold category label
     2. bottom-heavy gradient - carries the white title + teaser
     3. flat veil  - the duotone unifier
   AA verified against the WORST case (a pure-white infographic showing through):
   title/teaser zone composites to ~rgb(63,51,95) => white is 11.8:1; the gold
   label over the 0.82 top scrim is 4.5:1. Busy images therefore need no
   per-card deepening, and no text was shrunk to achieve it. A calmer 3/2
   landscape ratio (was 4/5 portrait) makes the whole card readable at a glance;
   the bottom overlay still holds two lines of title. */
.feature-card--editorial {
  position: relative;
  display: block;
  padding: 0;
  aspect-ratio: 4 / 5;   /* Part B: taller, portrait-like — was 3/2 landscape */
  overflow: hidden;
  isolation: isolate;
  background: var(--purple-deep);   /* fallback while the image loads */
  border: 0;
}
.feature-card__img {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
/* COMPAT — aspect-ratio fallback (Safari <=14, older Android WebView): these cards'
   heights come ENTIRELY from aspect-ratio (their content is absolutely positioned),
   so without support they would collapse to zero. Approximate the 4:5 with a
   min-height (cards are ~330-360px wide in the 3-up row), and rebuild the expert
   tile's square with the classic padding-top ratio. Supported browsers never see
   any of this. */
@supports not (aspect-ratio: 1 / 1) {
  .feature-card--editorial,
  .feature-card--placeholder { min-height: 420px; }
  .expert-tile__photo { position: relative; padding-top: 100%; }
  .expert-tile__photo img { position: absolute; top: 0; left: 0; }
}
/* Per-card framing: show each image's sharpest / most meaningful region rather
   than a blind centre crop. Position only - the source images are untouched.
   The 3/2 card is landscape and the sources are all >=900px wide, so at a
   ~315px card (even at 3x DPR) nothing is upscaled past native. */
/* Lower the framing so the Chairman's face sits in the UPPER portion of the
   card and the bottom gradient + title fall across his chest/shoulders, not his
   mouth. Higher % reveals more of the lower photo. Photo file untouched. */
.feature-card__img--face { object-position: center 42%; }
.feature-card__img--research { object-position: center 38%; }  /* the microscope subject */
.feature-card__img--story { object-position: center 30%; }     /* the figure, above the fold */
.feature-card--editorial::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 1;
  transition: opacity 0.15s ease;
  /* 2026-08: the flat purple duotone (rgba(58,42,102,.34), third layer) is
     GONE - the photographs read as photographs now. What remains sits behind
     TEXT only: the top vignette under the gold category label (0% stop
     raised 0.82->0.94 to exactly replace the darkness the flat tint had
     contributed there - no contrast regression), and the bottom gradient
     under the title/teaser, which now starts at 58% (was influencing from
     40%) and peaks lighter (0.85, was 0.96) - the midband 34-58% carries NO
     overlay at all. Measured: every title >=8.2:1 and teaser >=8.8:1 on all
     four cards (2026-08 task report). */
  background-image:
    linear-gradient(180deg, rgba(20, 14, 40, 0.96) 0%, rgba(20, 14, 40, 0.44) 20%, rgba(20, 14, 40, 0) 34%),
    linear-gradient(180deg, rgba(46, 33, 80, 0) 58%, rgba(46, 33, 80, 0.38) 72%, rgba(46, 33, 80, 0.72) 86%, rgba(46, 33, 80, 0.85) 100%);
}
.feature-card--editorial:hover::before { opacity: 0.88; }   /* slight lightening (split from :focus-visible — Safari <15.4) */
.feature-card--editorial:focus-visible::before { opacity: 0.88; }
.feature-card__cat {
  position: absolute;
  top: 1.25rem;
  left: 1.35rem;
  z-index: 2;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
}
.feature-card--editorial .feature-card__body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  padding: 0 3.25rem 1.4rem 1.35rem;   /* Step 9: scaled insets for the larger card; right inset clears the arrow */
}
.feature-card--editorial .feature-card__label {
  font-size: var(--fs-h3);        /* unified card-title size */
  line-height: 1.22;
  color: var(--white);
  margin-bottom: 0.35rem;
}
.feature-card--editorial .feature-card__teaser {
  font-size: var(--fs-body);      /* unified body size */
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.92);
}
.feature-card__arrow {
  position: absolute;
  right: 1.35rem;
  bottom: 1.25rem;
  z-index: 2;
  color: var(--gold);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.feature-card--editorial:hover .feature-card__arrow { transform: translateX(4px); }
.feature-card--editorial:focus-visible .feature-card__arrow { transform: translateX(4px); }

/* Placeholder card: deliberately plain - lavender-light, no image, "Sample"
   pill - so it never passes for finished content. Matches the editorial cards'
   height so the carousel row stays even. */
/* Placeholder stays plain and image-less. It now sits ON the lavender-light
   wash, so it goes WHITE (with the base card's border + shadow) to still read
   as a distinct, clearly-unfinished card. Matches the editorial 3/2 height so
   the row stays even. */
.feature-card--placeholder {
  aspect-ratio: 4 / 5;   /* Part B: match the taller editorial cards so the row stays even */
  justify-content: space-between;
  position: relative;
  overflow: hidden;
  border: 0;
  /* Coming-soon fill (was blank white): a soft on-brand purple -> lavender gradient
     so the SAMPLE card carries the same visual weight as the image cards. Reaches
     lavender by ~68% so the title/teaser (bottom) sit on the light end at WCAG AA
     (--purple label ≈ 9:1, --text-muted teaser ≈ 6:1 on lavender). */
  background: linear-gradient(180deg, var(--purple) 0%, var(--purple-bright) 34%, var(--lavender) 68%);
}
/* GEM crest MARK only (no wordmark), centered + low-opacity — a watermark, not a logo. */
.feature-card--placeholder::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 58%;
  aspect-ratio: 1 / 1;
  background: url("../img/gem-crest.png") center / contain no-repeat;
  opacity: 0.16;
  z-index: 0;
  pointer-events: none;
}
.feature-card--placeholder .feature-card__tag { position: relative; z-index: 1; align-self: flex-start; }
.feature-card--placeholder .feature-card__body { position: relative; z-index: 1; display: flex; flex-direction: column; }
@media (prefers-reduced-motion: reduce) {
  .feature-card__arrow { transition: none; }
  .feature-card--editorial:hover .feature-card__arrow { transform: none; }
  .feature-card--editorial:focus-visible .feature-card__arrow { transform: none; }
}

/* Cards per view: tablet 2, desktop 3 + a sliver of the 4th peeking in to signal
   more content (mobile = the base width above, one card + peek). The fractional
   desktop divisor (3.3) is what creates the peek: 3 full cards + ~a quarter card
   visible at the container's 1080px max. */
@media (min-width: 600px) {
  .feature-card { width: calc((min(100vw - 3.6rem, 1080px) - clamp(0.9rem, 2vw, 1.25rem)) / 2); }  /* tablet: clean 2-up (2 cards + 1 gutter = container) */
}
@media (min-width: 960px) {
  .feature-card { width: calc((min(100vw - 3.6rem, 1080px) - 2 * clamp(0.9rem, 2vw, 1.25rem)) / 3); }  /* desktop: clean 3-up, same width/gutter/edges as the Experts 3-col grid (no 4th-card peek) */
}

/* --- Generic prose section --- */
.prose { max-width: var(--maxw); }
.prose .btn { margin-top: 0.5rem; }

/* When .prose is used on a SECTION container, keep the full container width and
   left edge so every section lines up down the page; readability comes from the
   text measure (paragraphs are capped by the base `p` rule), not from shrinking
   the box. Standalone `.prose` text blocks keep the narrow measure above. */
.container.prose { max-width: 1120px; }

/* Centered focal section — a deliberate change of rhythm between the
   left-aligned content sections (used on the home "Honest hope" beat).
   Content is centered within the same page centre, in a comfortable measure. */
.section--focus { text-align: center; }
.section--focus > .container.prose { max-width: 760px; }
.section--focus p { margin-inline: auto; }
.section--focus .btn { margin-inline: 0.25rem; }

/* Honest Hope — its own toned background photo under a warm cream wash (lightest
   behind the centred text) so the copy stays readable and the hands show through.
   Cream reads distinctly warmer than the cool-lavender sections above/below.
   Scoped to #honest-hope so no other .section--focus section is affected. */
#honest-hope {
  background-image:
    radial-gradient(115% 100% at 50% 45%,
      rgba(252, 249, 242, 0.86) 0%,
      rgba(250, 245, 235, 0.72) 45%,
      rgba(244, 234, 219, 0.42) 100%),
    url("../img/backgrounds/bg-honest-hope.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* (Our Story redesign 2026-08: the .section--story-bg lavender flat-lay that
   framed the letter card is RETIRED — the class is gone from the markup and the
   lavender field now grounds the "Hope, told honestly" CTA below, pre-blurred.
   Restore both from history if the framed-card look ever returns.) */

/* Closing lines + signature — set apart from the body, quietly ceremonial. */
.story-closing {
  margin-top: 2.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(58, 42, 102, 0.18);
  max-width: 68ch;
}
.story-closing__lines {
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.15rem;
  line-height: 1.7;
  color: var(--purple);
  margin: 0 0 1rem;
}
.story-closing__signature {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--purple-deep);
  margin: 0;
}

/* --- Our Story: the letter, set CLEAN on the page (redesign 2026-08) ----------
   The cream card/box and its background image are RETIRED (restore from history
   if the framed look ever returns) — the letter now sits directly on the white
   page, styled like the Patient Stories expanded letters: a LEFT-ALIGNED
   reading column on the container spine, capped at a comfortable ~70ch measure,
   with the leftover whitespace on the right as intentional letter margin —
   never centered body text. White ground: title purple ~11.7:1, body
   --text-warm ~8.9:1, eyebrow gold-deep 5.4:1 — all AA+. */
.story-card {
  max-width: 70ch;                     /* the shared comfortable letter measure (matches .story-entry__full) */
  margin-inline: auto;                 /* the COLUMN centres on the page (even side margins — client direction 2026-08) */
  text-align: center;                  /* client direction 2026-08: the whole letter reads as ONE CENTRED piece (body, heading, signature); revert to left + margin 0 rules from history for the left-aligned voice */
  color: var(--text-warm);
  font-size: 1.2rem;                   /* 2026-08 client direction: +13.2% from the 1.06rem letter voice (16.96 -> 19.2px) — more presence for the founding letter. Page-scoped: .story-card exists only on our-story.html; Patient Stories keeps .story-body at 1.06rem. */
  line-height: 1.8;
}
.story-card p { color: var(--text-warm); }
/* Width-capped children (base `p` measure, the 68ch closing block) must centre
   as BLOCKS too, or centred text would sit in a left-hanging box. */
.story-card > *, .story-card .story-closing > * { margin-inline: auto; }
.story-card__title {
  color: var(--purple);
  margin-bottom: 0;
}
.story-card__rule {                    /* small gold accent under the title (decorative) */
  display: block;
  width: 64px;
  height: 3px;
  border-radius: 2px;
  background: var(--gold);
  margin: 1rem auto 1.9rem;            /* centred under the centred heading */
}
/* Closing block: same elegant treatment (italic serif lines over the hairline,
   bold signature), centred with the letter. */
.story-card .story-closing {
  max-width: none;
  border-top-color: rgba(58, 42, 102, 0.18);
}
.story-card .story-closing__lines { color: var(--purple); }
.story-card .story-closing__signature { color: var(--purple-deep); margin-top: 1.1rem; }

/* Hope, told honestly (Our Story page) — grounded by the lavender field that
   used to frame the story letter, as a SOFT-FOCUS background. The blur is
   BAKED INTO the image file (our-story-lavender-blur.jpg; ?v busts the cached
   heavier bake) — a static image blur, deliberately NOT backdrop-filter and
   NOT a runtime CSS filter, so it renders identically on Chrome/Android/
   Windows/iOS/macOS Safari/WeChat and costs nothing at paint time.
   VISIBILITY RETUNE (client direction 2026-08): the first bake (4% bicubic
   down/upsample) + 0.88/0.80 cream wash read as a near-solid wash — the field
   was invisible. Now a GENTLER 15% down/upsample (flower stalks clearly
   recognizable, still out-of-focus) under a THINNER 0.58 -> 0.50 wash, so the
   lavender plainly reads as the background. AA still holds at the measured
   worst case: the image's darkest pixel is L=0.005, so at the wash's thinnest
   (0.50) the ground floor is L=0.48 -> body --text 7.0:1, purple-deep heading
   5.9:1 (large text), both AA with margin; buttons carry their own solid
   fills/rings. The balloons photo this replaced (our-story-hope.jpg) stays in
   the repo, unreferenced — restore from history if wanted. */
.section--hope-bg {
  background-color: var(--lavender);   /* fallback while the image loads */
  background-image:
    linear-gradient(rgba(252, 249, 242, 0.58), rgba(250, 246, 238, 0.50)),
    url("../img/backgrounds/our-story-lavender-blur.jpg?v=20260858");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Placeholder marker for awaiting-GEM content */
.placeholder-note {
  display: inline-block;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--purple);
  background: var(--lavender);
  border: 1px dashed var(--gold);
  border-radius: 999px;
  padding: 0.2rem 0.7rem;
  margin-bottom: 0.75rem;
}

/* Section kicker — the shared editorial label above section/page headings. One
   class, .eyebrow, used site-wide. Text only (no rule). Colour: accessible deep
   gold (--gold-deep, AA on white/cream/lavender) on light; brand gold on
   dark/purple. Size stays small (a kicker, never competing with the heading);
   tracking a touch wider and a semibold weight give it presence without
   enlarging. */
/* Apple-style kicker: small, medium-weight, DARK, quiet — sentence/title case (no
   shouty caps), gentle tracking. Its elegance is the size contrast with the big
   headline directly below, not colour or decoration. */
.eyebrow {
  font-size: var(--fs-kicker);     /* unified kicker size */
  font-weight: 500;                /* medium — a quiet label */
  letter-spacing: 0.02em;          /* refined, not spread (the old 0.16em was for all-caps) */
  text-transform: none;            /* source Title Case reads premium; caps retired */
  /* GOLD kickers site-wide (client direction). COLOUR ONLY — size, weight,
     tracking, case and spacing above are untouched. On LIGHT backgrounds the
     accessible deep gold is required: canonical #BB863F is only ~3.2:1 on white
     and fails AA for small text, while --gold-deep #8A6222 clears it (~5.4:1 on
     white, ~5.2:1 cream, ~5.0:1 lavender). Dark sections switch to the brighter
     brand gold below, where it has the contrast to carry. */
  color: var(--gold-deep);
  margin: 0 0 0.7rem;              /* air under the larger kicker */
}
.section--purple .eyebrow { color: var(--gold); }   /* brand gold — the dark section gives #BB863F the contrast it needs */
/* Quiet kicker icon: SMALL (sized to the kicker text), single-tone monochrome
   outline in muted purple (--purple-mid #5B4A8A) — one refined unit with the text,
   supporting it, never competing (NOT the crest, NOT colorful). Em-sized so it
   scales with the kicker; inline-block keeps it in flow, zero layout change.
   Decorative (aria-hidden). */
.eyebrow__icon {
  display: inline-block;
  /* EXPLICIT FIXED size at every breakpoint (iPad fix): never viewport- or
     container-dependent, and the SVGs also carry width/height ATTRIBUTES — so the
     icon can never fall back to an intrinsic full-width render on any engine or
     with any stale stylesheet. ~22px beside the ~20-25px kicker text. */
  width: 1.375rem;
  height: 1.375rem;
  max-width: 1.5rem;
  max-height: 1.5rem;
  margin-right: 0.45em;
  vertical-align: -0.22em;         /* optically centred against the title-case line */
}
/* Kicker icons in brand gold, ONE consistent treatment site-wide (client direction).
   The SVGs carry a hard-coded stroke="#5B4A8A" presentation attribute; a CSS rule
   outranks a presentation attribute, so this recolours all of them without editing
   a single SVG — COLOUR ONLY, the sizing above is untouched. Icons are graphics
   (3:1 floor), so the brighter #BB863F is fine even on light backgrounds. */
.eyebrow__icon path { stroke: var(--gold); }

/* --- Interior page-header banner (consistent across interior pages) ---
   Brightened direction: a light lavender-light→cream gradient with a faint
   gold glow + the same thin gold divider. Headings are --purple-deep on the
   light band (≥13:1); the eyebrow uses the deepened text gold (5:1). */
.page-banner {
  background:
    radial-gradient(900px 480px at 90% -30%, rgba(187, 134, 63, 0.16), transparent 62%),
    linear-gradient(135deg, var(--lavender-light) 0%, var(--cream) 100%);
  color: var(--text);
  border-bottom: 2px solid rgba(187, 134, 63, 0.55);
  padding-block: clamp(1.5rem, 4.5vw, 3rem);   /* compact on mobile, roomier on desktop */
}
.page-banner .eyebrow { color: var(--gold-deep); margin-bottom: 0.4rem; }   /* deepened gold — AA on the light band */
/* SIGN-OUT IN THE BANNER ROW (2026-08, protected pages only): the quiet ghost
   button sits at the banner's top-right on the eyebrow's own line - page
   furniture, not a floating control. flex-wrap + margin-left:auto: on a very
   narrow screen it wraps BELOW the eyebrow, still right-aligned, never
   crowding the page title. No flex gap (Safari <14.1) - margin-based. */
.page-banner__toprow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
}
.page-banner__toprow .eyebrow { margin-right: 0.75rem; }
.page-banner__signout {
  margin-left: auto;
  min-height: 44px;
  font-size: 0.85rem;
  padding: 0.35rem 0.9rem;
}
.page-banner h1 {
  color: var(--purple-deep);
  font-size: clamp(1.7rem, 4.5vw, 2.61rem);   /* 2026-08: max -10% (was 2.9rem/46.4px -> 41.76px); the 1.7rem mobile minimum is deliberately UNCHANGED (desktop complaint only - see task report) */
  line-height: 1.12;
  margin: 0;
  max-width: 22ch;
}
.page-banner__subtitle {
  color: var(--text-warm);
  font-size: clamp(1rem, 2.2vw, 1.2rem);
  line-height: 1.5;
  max-width: 56ch;
  margin: 0.6rem 0 0;
}
.page-banner__cta { margin: clamp(1rem, 2.5vw, 1.4rem) 0 0; }
.page-banner__cta .btn { min-height: 44px; }   /* comfortable tap target (AA) */
/* Experts banner depth (2026-08, scoped — the shared .page-banner and every
   other page keep the base clamp): a deliberate opening rather than a thin
   strip. ~209px at 1440 (Our Story is ~208; the standardized three-line
   heroes are 259 — this stays under both), LEFT-ALIGNED like everything
   below it on this page. */
.page-banner--experts { padding-block: clamp(1.9rem, 5vw, 3.6rem); }
/* Experts banner: a more compact header on desktop — the title holds one confident
   line and the description stays to two. Mobile keeps the default (title may wrap). */
@media (min-width: 960px) {
  .page-banner--experts h1 {
    max-width: none;
    font-size: clamp(1.7rem, 3.8vw, 2.5rem);
  }
  .page-banner--experts .page-banner__subtitle {
    max-width: 76ch;
    font-size: clamp(1rem, 1.9vw, 1.08rem);
  }
}
/* Our Story banner over a photo (bg-6): the sunrise silhouette now sits under
   a LIGHT lavender-light scrim (heavier on the left where the heading sits),
   matching the homepage hero treatment, so the --purple-deep heading stays AA
   over every part of the photo. */
.page-banner--story {
  background-image:
    radial-gradient(900px 480px at 92% -30%, rgba(187, 134, 63, 0.14), transparent 62%),
    linear-gradient(100deg, rgba(247, 244, 251, 0.94) 0%, rgba(247, 244, 251, 0.82) 55%, rgba(247, 244, 251, 0.88) 100%),
    url("../img/backgrounds/bg-6-our-story.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  /* 2026-08 single-title hero, then RECENTRED + DEEPENED (client direction):
     content centres to match the centred letter below; the ABOUT GEM kicker
     returns; padding lifts the band to ~206px at 1440 (within the 180-220
     target, under the 259px standardized three-line heroes). Modifier is used
     ONLY by our-story.html; the shared .page-banner and every other page keep
     the base clamp(1.5rem, 4.5vw, 3rem) and left alignment. */
  padding-block: clamp(2.25rem, 5.5vw, 3.5rem);   /* 2026-08 deepened: band ~208px at 1440 (mid of the 180-220 target, under the 259px standardized three-line heroes), ~146px at 375 */
  text-align: center;
}
.page-banner--story h1 { margin-inline: auto; }          /* the 22ch-capped title box centres as a block too */
.page-banner--story .eyebrow { margin-inline: auto; }

/* Patient Stories banner over the lavender-sunrise photo — the homepage CTA band
   treatment (.closing-band), layered bottom -> top:
     1. ::after (z-1) the image on its OWN layer, cover, focal point nudged right
        so the four women (centre-right of the frame) stay in shot when the band
        crops wide; 2. ::before (z0) the LEFT dark scrim that protects the copy,
        fading to a clear image on the right; 3. the content (z2).
   background-color is the image-missing fallback, so the copy is never stranded.
   The copy flips LIGHT here (the base banner's deep-purple text could not hold
   AA over a photo scrim). Scoped ENTIRELY to this modifier — the shared
   .page-banner and every other page using it are untouched. */
.page-banner--stories {
  position: relative;
  isolation: isolate;
  background: var(--purple-deep);                  /* image-missing fallback */
  padding-block: clamp(3.5rem, 7.5vw, 5.75rem);    /* banner presence, never full-screen */
}
.page-banner--stories::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: -1;
  /* WebP matches the site's established background pattern (every other photo
     band is webp too). The .jpg twin ships alongside as the swap-in fallback,
     exactly like cta-bg.webp / cta-bg.jpg. */
  background-image: url("../img/patient-stories-hero-2560.webp");
  background-size: cover;
  background-position: 72% center;                 /* women centre-right stay in frame */
  background-repeat: no-repeat;
}
.page-banner--stories::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 0;
  background: linear-gradient(90deg,
    rgba(28, 18, 56, 0.86) 0%,
    rgba(28, 18, 56, 0.72) 30%,
    rgba(28, 18, 56, 0.40) 52%,
    transparent 68%);
}
.page-banner--stories > .container { position: relative; z-index: 2; }   /* copy above the scrim */
/* Light copy + a restrained shadow (the scrim carries AA; the shadow is insurance
   for the brightest sunrise pixels, not a visible halo). */
.page-banner--stories .eyebrow {
  color: #ECD6AE;                                  /* soft champagne — a light tint of brand gold */
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.5);
}
.page-banner--stories h1 {
  color: var(--white);
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.5), 0 2px 12px rgba(20, 14, 40, 0.22);
}
.page-banner--stories .page-banner__subtitle {
  /* Typeface matched to the HOMEPAGE hero subtitle (.hero--editorial
     .hero__subtitle): Lora serif, italic, weight 500. Size and colour are this
     page's own and deliberately unchanged. */
  font-family: var(--font-head);
  font-style: italic;
  font-weight: 500;
  color: #EFEAF6;
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.5);
}
/* Keep the copy column in the LEFT (scrim-protected) half. Without this the
   56ch subtitle ran its tail into the cleared right side of the band at tablet
   widths and measured 2.99:1 — below AA. Capping the measure fixes it without
   dimming the photo further, and matches the intent: text left, image right. */
.page-banner--stories h1 { max-width: 17ch; }
.page-banner--stories .page-banner__subtitle { max-width: 40ch; }
/* Phones: the copy spans nearly the full width, so the scrim keeps a floor of
   protection all the way across (text AA wins over a full image reveal), and the
   focal point shifts slightly left so the women stay in the narrow crop. */
@media (max-width: 639.98px) {
  .page-banner--stories::before {
    background: linear-gradient(90deg,
      rgba(28, 18, 56, 0.86) 0%,
      rgba(28, 18, 56, 0.74) 55%,
      rgba(28, 18, 56, 0.56) 100%);
  }
  .page-banner--stories::after { background-position: 68% center; }
}
/* Tablet: the container loses its side gutters, so the copy reaches further
   right — extend the fade, keeping the far right (women + sunrise) clear. */
@media (min-width: 640px) and (max-width: 1023.98px) {
  .page-banner--stories::before {
    background: linear-gradient(90deg,
      rgba(28, 18, 56, 0.86) 0%,
      rgba(28, 18, 56, 0.76) 38%,
      rgba(28, 18, 56, 0.52) 62%,
      transparent 86%);
  }
}

/* --- Featured experts grid: clickable square tiles, left to right --- */
.expert-grid {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}
.expert-grid > li { display: flex; }   /* let each tile stretch to equal height */

.expert-tile {
  display: flex;
  flex-direction: column;
  flex: 1;
  text-decoration: none;
  color: inherit;
  background: var(--white);
  border: 2px solid var(--lavender);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.expert-tile:hover {
  border-color: var(--gold);
  transform: translateY(-4px);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.12);
}
.expert-tile:focus-visible {
  border-color: var(--gold);
  transform: translateY(-4px);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.12);
}
.expert-tile--anchor { border-color: var(--gold); }
.expert-tile__photo {
  aspect-ratio: 1 / 1;
  background: var(--lavender);
  overflow: hidden;
}
.expert-tile__photo img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }
.expert-tile__body { padding: 0.9rem 1rem 1.1rem; text-align: center; }
.expert-tile__name { display: block; font-family: var(--font-head); color: var(--purple); font-size: 1.05rem; line-height: 1.25; }
.expert-tile__role { display: block; color: var(--purple-deep); font-weight: 600; font-size: 0.82rem; margin-top: 0.2rem; }

@media (min-width: 560px) {
  /* Tiles flow left-to-right and stretch to fill the row (no orphan tile). */
  .expert-grid { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 1.25rem; }
}
/* Shared avatar component — circular, cropped, always centered.
   Used by the Chairman card, expert cards, board cards, and placeholder avatars.
   Only the size is set per context; the circle + crop behaviour lives here. */
.avatar {
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  background: var(--purple);   /* fallback tint if an image is ever missing */
  flex: 0 0 auto;
}
.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* Centered button row (used in the calls-for-action band). */
.cta-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; margin-top: 1rem; }

/* --- Calls-for-action band — clean cream, two columns. --- */
/* Desktop: photo left, text (heading + body + buttons) right, columns vertically
   centred. Mobile: heading + body + buttons stacked, then the photo last. */
/* CTA band — the blurred rose (cta-bg.jpg) under a soft warm-cream wash:
   "warm cream paper", not gold (the earlier #BB863F tint read too golden-yellow
   — re-lightened 2026-07-09). Cream #FBF9F4 at 62% leaves the rose pattern
   gently visible while the band reads pale and light; the purple heading, grey
   body text, and purple buttons stay comfortably AA. */
.cta-band {
  background-color: var(--cream);
  background-image:
    linear-gradient(rgba(251, 249, 244, 0.62), rgba(251, 249, 244, 0.62)),
    url("../img/backgrounds/cta-bg.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: scroll;
}
.cta-split { display: grid; gap: 2rem; }
.cta-split__text h2 { color: var(--purple); margin: 0 0 0.75rem; }
.cta-split__text p { color: var(--text-warm); max-width: 46ch; margin: 0 0 1.5rem; }
.cta-split__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);           /* soft rounded corners — matches the site's cards */
  box-shadow: 0 14px 34px rgba(46, 33, 80, 0.12);
  /* Mirror horizontally so she faces right, toward the hero's upper-right light.
     Scoped to THIS band only (.cta-split__media) — the same asset in Why We Exist
     (.split__media img) is untouched; the source file isn't modified. */
  transform: scaleX(-1);
}

/* Three identical buttons — solid purple, readable on cream. One shared hover +
   focus (lift + darken + ring); the lift is dropped under reduced motion. */
.cta-buttons { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.cta-buttons .btn {
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
.cta-buttons .btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(46, 33, 80, 0.25);
}
.cta-buttons .btn:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .cta-buttons .btn:hover { transform: none; box-shadow: none; }
}

@media (min-width: 820px) {
  .cta-split {
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "media text";     /* photo left, text right */
    align-items: center;                    /* vertically centre the two columns */
    gap: 3rem;
  }
  .cta-split__media { grid-area: media; }
  .cta-split__text { grid-area: text; }
}

/* ===================================================================
   9. Experts hub
   =================================================================== */

/* --- Chairman anchor --- */
.chair {
  display: grid;
  gap: 1.5rem;
  align-items: start;
  grid-template-columns: 1fr;
}
.chair__photo { width: 160px; }
.chair__name { margin-bottom: 0.1rem; }
.chair__role { color: var(--purple-deep); font-weight: 600; margin: 0 0 1rem; }
.chair__welcome {
  margin: 0 0 1.25rem;
  padding: 1.25rem 1.5rem;
  background: var(--lavender);
  border-left: 4px solid var(--gold);
  border-radius: var(--radius);
  font-style: italic;
  color: var(--text);
}
.chair__welcome cite { display: block; font-style: normal; font-weight: 600; color: var(--purple); margin-top: 0.6rem; }

@media (min-width: 760px) {
  .chair { grid-template-columns: 160px 1fr; gap: 2.5rem; }
}

/* --- Board groups --- */
.board-group + .board-group { margin-top: 2.5rem; }
.board-group__title {
  border-bottom: 2px solid var(--gold);
  padding-bottom: 0.4rem;
  margin-bottom: 1.25rem;
}
.board-grid {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
  list-style: none; margin: 0; padding: 0;
}
@media (min-width: 600px) { .board-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) { .board-grid { grid-template-columns: repeat(3, 1fr); } }

/* Homepage only: on phones (single-column) show just the first four cards —
   Prof. Shervin + the next three; hide the last two. Tablet/desktop keep all
   six, and the full roster stays reachable via "See all our experts". */
@media (max-width: 599.98px) {
  .board-grid--home > li:nth-child(5),
  .board-grid--home > li:nth-child(6) { display: none; }
}

/* 2026-08: the placeholder lines ("Name... to follow" / "Awaiting from GEM")
   were stripped from the experts cards - the empty slots are INTENTIONAL.
   Rebalanced for the avatar + role-title composition: roomier centered
   vertical rhythm so the card reads composed, not broken. The __meta/__status
   rules below are KEPT for future real cards (credentials line). Visually
   this renders on experts.html only (index's copy is in a hidden legacy
   section). */
.board-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.55rem;
  padding: 2rem 1.5rem 1.9rem;
  background: var(--white);
  border: 2px solid var(--lavender);
  border-radius: var(--radius);
  text-align: center;
  align-items: center;
}
.board-card__photo { width: 96px; margin-bottom: 0.25rem; }
.board-card__name { font-family: var(--font-head); color: var(--purple); margin: 0; font-size: 1.1rem; }
.board-card__meta { color: var(--text-muted); font-size: 0.9rem; margin: 0; }
.board-card__status {
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--purple);
  background: var(--lavender);
  border: 1px dashed var(--gold);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
}
/* Founding Chairman highlighted as the anchor card (must follow .board-card). */
.board-card--anchor { border-color: var(--gold); }

/* Homepage expert cards link to the Experts page. A stretched link (::after over the
   whole card) makes the entire card clickable while keeping the existing markup and
   layout. Scoped to the homepage grid so the Experts page's own cards are unaffected. */
.board-card__link { color: inherit; text-decoration: none; }
.board-card__link:focus { outline: none; }   /* the focus ring is drawn on the whole card, below */
.board-grid--home .board-card {
  position: relative;
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.board-grid--home .board-card__link::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */                       /* covers the whole card → click anywhere navigates */
}
.board-grid--home .board-card:hover {
  border-color: var(--gold);
  transform: translateY(-3px);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.12);
}
.board-grid--home .board-card:focus-within {
  outline: 3px solid var(--focus);   /* clear keyboard focus ring around the whole card */
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .board-grid--home .board-card:hover { transform: none; }
}
/* Centred CTA below the homepage featured-experts grid. */
.experts-home__cta { margin-top: 1.75rem; text-align: center; }
/* Desktop: left-align it so its left edge lines up with the section title and
   the first column of expert cards (same container left margin). */
@media (min-width: 960px) { .experts-home__cta { text-align: left; } }

/* ===================================================================
   10. Forms
   =================================================================== */
/* Form column: capped for readability and centered on the page. The heading block
   is centered; the form fields stay left-aligned inside the card for easy scanning. */
.container--form { max-width: 600px; text-align: center; }

/* Form + intro sit on a clean white card so every field stays crisp and high-contrast. */
.form-wrap {
  max-width: 600px;
  margin-inline: auto;
  text-align: left;
  background: var(--white);
  border-radius: 18px;
  box-shadow: 0 14px 34px rgba(46, 33, 80, 0.12);
  padding: clamp(1.4rem, 4vw, 2.5rem);
}

.form-intro {
  color: var(--text);
  text-align: center;
  margin-bottom: 1.75rem;
}
.form-intro p:last-child { margin-bottom: 0; }

/* --- Photographic full-bleed backgrounds for the form pages --- */
/* Each page picks its own --page-bg photo. The images are already toned purple,
   so the extra scrim is deliberately light — just enough to unify the page and
   let the white content card pop. Fixed for a gentle parallax on desktop
   (switched to scroll on mobile below, where fixed janks / iOS ignores it).
   background-color is a fallback while the image loads. */
body.form-page {
  background-image:
    linear-gradient(rgba(46, 33, 80, 0.18), rgba(46, 33, 80, 0.18)),
    var(--page-bg, none);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-color: var(--purple-deep);
}
/* (2026-08 header-unification #2: Support's and Get Involved's photographic
   body backgrounds are RETIRED - the dark photo behind the translucent pinned
   header read as a non-standard header block. Both pages join the cream
   treatment below, matching the other inner pages. page-share keeps its
   photographic form-page look, untouched.) */
body.page-share        { --page-bg: url("../img/backgrounds/bg-3-share-your-story.webp"); }

/* Mobile: fixed attachment is ignored on iOS and can jank elsewhere — use scroll
   so the photo still covers cleanly. */
@media (max-width: 759px) {
  body.form-page { background-attachment: scroll; }
}

/* The photo replaces the old faint illustration watermark. */
.form-section { position: relative; overflow: hidden; }
.form-watermark { display: none; }
.form-section > .container { position: relative; z-index: 1; }

/* The encouragement line sits directly over the photo (above the white card).
   White + shadow + a soft, self-contained dark scrim keeps it readable over the
   lighter parts of the images (e.g. the bright skies) — a scrim behind the text
   only, not over the whole photo. */
body.form-page .form-encourage {
  color: var(--white);
  text-shadow: 0 1px 12px rgba(30, 20, 55, 0.85);
  /* Flat, dark-enough core across the whole line (fading only at the outer
     edges) so white stays AA even over the images' bright skies. */
  background: radial-gradient(100% 160% at 50% 50%,
    rgba(30, 20, 55, 0.72) 0%, rgba(30, 20, 55, 0.72) 46%, rgba(30, 20, 55, 0.40) 78%, transparent 100%);
  padding: 0.7rem 1.1rem 0.9rem;
  border-radius: 14px;
}

/* --- Light-cream form pages: Sign In + the two registration pages -----------
   Their content area is cream (#FBF9F4), matching the header/footer, instead of
   the dark form-page background. The white form card + dark text keep everything
   WCAG AA. (support/get-involved/share keep their photographic form-page bg.) */
body.form-page.page-register,
body.form-page.page-signin,
body.form-page.page-support,
body.form-page.page-get-involved {   /* + support & get-involved (2026-08 header-unification #2) */
  background-image: none;
  background-color: var(--cream);
}
/* On cream, the encouragement line is dark purple — drop the white-on-dark scrim. */
body.form-page.page-register .form-encourage,
body.form-page.page-signin .form-encourage,
body.form-page.page-support .form-encourage,
body.form-page.page-get-involved .form-encourage {
  color: var(--purple);
  background: none;
  text-shadow: none;
  padding: 0;
}
/* A light edge defines the white form card against the cream. */
body.form-page.page-register .form-wrap,
body.form-page.page-signin .form-wrap,
body.form-page.page-support .form-wrap,
body.form-page.page-get-involved .form-wrap {
  border: 1px solid rgba(58, 42, 102, 0.12);
}

/* (2026-08 header-unification: the two register pages' photographic dark
   overrides — reaching-hands / four-women photos under a 0.62 purple tint —
   are RETIRED. That dark body showed through the translucent pinned header
   and read as a "solid purple header block". Both pages now fall back to the
   cream register/sign-in treatment above, so their headers match the other
   inner pages exactly.) */
/* Sign In: soft lilac-blooms panorama (signin-lilac.jpg) — on-brand and already
   soft, so NO blur and NO wash (changed 2026-07-09, replacing the blurred
   balloons ::before). The image is a 3:1 pano: lilac blooms fill the left ~35%,
   open lavender the right ~65%. background-position 62% shows that OPEN lavender
   behind the centred white login card (which stays crisp on the calm space)
   while the blooms read as a soft left accent. The white .form-wrap card is
   opaque + shadowed + bordered, so no wash is needed. size/repeat and the
   fixed-desktop / scroll-mobile attachment are inherited from base .form-page. */
body.form-page.page-signin {
  background-image: url("../img/backgrounds/signin-lilac.jpg");
  background-color: var(--lavender);   /* on-brand fallback while the image loads */
  background-position: 62% center;
}
/* (2026-08 header-unification: the white-on-scrim encourage override for the
   two register pages is retired with their photographic backgrounds - the
   cream rule above now applies, purple text, no scrim.) */

/* Warm encouragement subheading — gentle, supporting the heading, not competing. */
.form-encourage {
  font-family: var(--font-head);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.05rem, 2.2vw, 1.25rem);
  line-height: 1.4;
  color: var(--purple);
  max-width: 42ch;
  margin: 0.25rem auto 1.75rem;
}

/* Support page — main content on a clean white card (wider than the narrow form card). */
.support-card {
  max-width: 760px;
  margin-inline: auto;
  background: var(--white);
  border-radius: 18px;
  box-shadow: 0 14px 34px rgba(46, 33, 80, 0.12);
  padding: clamp(1.6rem, 4vw, 2.75rem);
}
.support-card > :first-child { margin-top: 0; }
.support-card > :last-child { margin-bottom: 0; }

/* Trauma-informed safeguarding line near a form (matches the footer's tone). */
.form-safeguard {
  font-size: 0.9rem;
  color: var(--text-muted);
  border-left: 3px solid var(--gold);
  padding: 0.4rem 0 0.4rem 0.9rem;
  margin: 0 0 1.75rem;
  max-width: none;
}
.form-safeguard a { color: var(--purple-deep); font-weight: 600; }

/* "(required)" marker on a fieldset legend. */
.required-tag { font-weight: 600; color: var(--purple-deep); font-size: 0.85rem; }

.field { margin-bottom: 1.4rem; }
.field > label,
.field > .field__legend {
  display: block;
  font-weight: 600;
  color: var(--purple);
  margin-bottom: 0.4rem;
}
.field .optional { font-weight: 400; color: var(--text-muted); font-size: 0.9rem; }
.field__hint { color: var(--text-muted); font-size: 0.9rem; margin: 0 0 0.5rem; }

/* Optional grouped fields (e.g. the patient page's "About your experience"). A small
   heading + hint set them apart so the form doesn't read as a clinical intake. */
.field-group { border: 0; padding: 0; margin: 1.75rem 0 0; }
.field-group__title {
  font-family: var(--font-head);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--purple);
  padding: 0;
  margin: 0 0 0.3rem;
}
.field-group__title .optional { font-family: var(--font-body); font-weight: 400; color: var(--text-muted); font-size: 0.85rem; }
.field-group__hint { color: var(--text-muted); font-size: 0.9rem; margin: 0 0 1.1rem; }

input[type="text"],
input[type="email"],
textarea,
select {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--text);
  background: var(--white);
  border: 2px solid var(--text-muted);
  border-radius: var(--radius);
  padding: 0.7rem 0.85rem;
}
textarea { min-height: 9rem; resize: vertical; line-height: var(--line); }
input:focus, textarea:focus, select:focus { border-color: var(--purple); }

/* CUSTOM FILE PICKER (2026-08, shared: contributor portal + member story
   form; moved here from portal.css when the story form adopted it - the
   class names keep their historical portal- prefix, like .portal-tabs).
   The dashed picker BOX is a wrapper - a native file input cannot contain
   other elements. Flex-wrap drops pieces to a second row at narrow widths,
   still inside the box. Margins, not flex gap (Safari < 14.1).
   WHY CUSTOM: the native control's "Choose File / No file chosen" wording
   is drawn by the BROWSER in the OS language (Chinese on the client's
   machine); no CSS or attribute can reword it. So the REAL input stays in
   the DOM as the source of truth for the FileList, keyboard focus and the
   screen-reader name (its <label for> is untouched), stretched invisibly
   over the whole dashed box: clicking anywhere in the box opens the dialog
   natively, drag-and-drop still lands on the input, and Tab reaches it as
   before (opacity hides it; it is NOT display:none or clipped away, so it
   stays fully operable). The pill and filename line underneath are
   aria-hidden decoration in our own words, always English. The portal's
   Remove control rises above the overlay via its own z-index (portal.css). */
.portal-filebox {
  position: relative;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  width: 100%;
  min-height: 56px;
  padding: 0.25rem 0.6rem;
  background: var(--white);
  border: 2px dashed rgba(58, 42, 102, 0.35);
  border-radius: var(--radius);
}
.portal-filebox input[type="file"] {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}
/* Our "browse" affordance: the same pill the native button wore, now with
   our own text. Decorative only - the overlay above it takes the click. */
.portal-filebox__button {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  min-height: 44px;
  margin: 0.25rem 0.85rem 0.25rem 0;
  padding: 0.55rem 1.15rem;
  border: 1.5px solid var(--purple-bright);
  border-radius: 999px;
  background: var(--white);
  color: var(--purple-bright);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
}
/* Our filename line: truncates with an ellipsis instead of pushing anything
   out of the box (the same contract the native input kept). */
.portal-filebox__name {
  flex: 1 1 8rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
  font-size: 1rem;
}
/* Focus lands on the (invisible) real input; the ring is drawn on the pill.
   Plain :focus, not :focus-visible - Safari 14 has no :focus-visible and a
   keyboard user must always get a ring; the small cost is that a mouse
   click on the box also rings the pill until focus moves on. */
.portal-filebox input[type="file"]:focus + .portal-filebox__button {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* Radio / checkbox groups */
fieldset.field { border: 0; padding: 0; margin-inline: 0; }
.choice {
  display: flex;
  align-items: flex-start;
  padding: 0.6rem 0.75rem;
  border: 2px solid var(--lavender);
  border-radius: var(--radius);
  margin-bottom: 0.5rem;
  cursor: pointer;
}
.choice:hover { border-color: var(--gold); }
.choice input { margin-top: 0.2rem; margin-right: 0.6rem; flex: 0 0 auto; width: auto; }   /* input↔label via margin, not flex gap (Safari <14.1) */
.choice span { font-weight: 400; color: var(--text); }
.choice .choice__title { font-weight: 600; color: var(--purple); display: block; }

/* --- Voice input (member-story.html): mic button inside the story textarea.
   The button ships hidden and is revealed by member-story.js ONLY when the Web
   Speech API exists (feature detection - WeChat/most Firefox never see it).
   Listening state = aria-pressed + ICON SHAPE swap (mic -> stop) + fill change
   + pulse; the pulse is disabled under prefers-reduced-motion, and the shape
   swap keeps the state readable without colour or motion. Focus ring is
   purple-bright (NOT the raw --focus token): 5.9:1 on the white field. */
.voicebox { position: relative; }
.voicebox textarea { padding-right: 3.6rem; }   /* text never runs under the button */
.voice-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  display: grid;
  place-items: center;
  width: 44px;                     /* tap target */
  height: 44px;
  background: var(--white);
  border: 2px solid var(--purple-bright);
  border-radius: 10px;
  color: var(--purple-bright);
  cursor: pointer;
}
.voice-btn svg { width: 20px; height: 20px; display: block; }
.voice-btn:hover { background: var(--lavender); }
.voice-btn:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; }
.voice-btn[aria-pressed="true"] {
  background: var(--purple-bright);
  border-color: var(--purple-deep);
  color: var(--white);
  animation: voicePulse 1.4s ease-in-out infinite;
}
@keyframes voicePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(107, 79, 160, 0.45); }
  50%      { box-shadow: 0 0 0 9px rgba(107, 79, 160, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .voice-btn[aria-pressed="true"] { animation: none; }
}
/* Permission denied (2026-08): the button STAYS, visibly out of service -
   removing it read as a silent malfunction. Dimmed + no hover invitation;
   the explanation sits in the field's voice-note line. */
.voice-btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.voice-btn[disabled]:hover { background: var(--white); }
.voice-note { margin: 0.4rem 0 0; font-size: 0.85rem; color: var(--text-muted); }
/* The JS-injected outcome line ([role=status]) shares .voice-note styling;
   empty until a message lands, so it costs no space beforehand. */
.voice-note--status:empty { display: none; }

/* Consent — clearly a separate, unchecked decision */
.consent {
  display: flex;
  align-items: flex-start;
  background: var(--white);
  border: 2px solid var(--purple);
  border-radius: var(--radius);
  padding: 0.9rem 1rem;
}
.consent input { margin-top: 0.25rem; margin-right: 0.7rem; width: auto; flex: 0 0 auto; }   /* input↔label via margin, not flex gap (Safari <14.1) */
.consent label { font-weight: 500; color: var(--text); }

/* Inline validation errors */
.field__error {
  display: none;
  color: var(--purple-deep);
  font-size: 0.9rem;
  font-weight: 600;
  margin-top: 0.4rem;
}
.field.has-error .field__error { display: block; }
.field.has-error input,
.field.has-error textarea,
.field.has-error select { border-color: var(--purple-deep); }
.field.has-error .consent,
.field.has-error.consent-field .consent { border-color: var(--purple-deep); }

/* Form-level status notice */
.form-status {
  margin-top: 1rem;
  padding: 0.9rem 1.1rem;
  border-radius: var(--radius);
  font-weight: 600;
}
.form-status[hidden] { display: none; }
/* Confirmation placed BELOW its submit button (2026-08, portal-submit +
   member-story): clear separation from the button above and breathing room
   beneath, matching the forms' ~1.5rem field rhythm. Scoped by modifier so
   the many forms still showing status ABOVE their button keep the original
   1rem. As the form's LAST element, revealing it only extends the card
   downward - nothing above it moves. */
.form-status--below { margin: 1.5rem 0 0.5rem; }
.form-status--below:focus { outline: none; }   /* programmatic focus target - the aria-live + visible card carry the announcement */

/* ============ "Your stories" - returning-member record (member-story.html,
   2026-08). A quiet, respectful record: cream cards on the standard radius +
   hairline, generous space between cards, serif titles, comfortable body
   text. The only icon anywhere is the small status dot. Existing tokens
   only. min-height on the list keeps the load from shoving the form around
   (quiet loading line -> content with minimal shift). ============ */
.mystories { padding-bottom: 0; }
.mystories__heading {
  margin: 0 0 0.9rem;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: clamp(1.3rem, 2.2vw, 1.6rem);
  color: var(--purple-deep);
}
.mystories__note { margin: 0 0 0.6rem; font-size: 0.95rem; color: var(--text-muted); }
.mystories__note a, .mystories__another a { color: var(--purple); font-weight: 600; }
#mystories-list { min-height: 3.5rem; }
.mystory {
  background: var(--cream);
  border: 1px solid rgba(58, 42, 102, 0.10);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vw, 1.6rem);
  margin: 0 0 2rem;                       /* unhurried space between cards */
}
.mystory__title {
  margin: 0 0 0.35rem;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 1.2rem;
  line-height: 1.35;
  color: var(--purple-deep);
}
.mystory__title--line { font-style: italic; font-weight: 500; }
.mystory__meta { margin: 0 0 0.5rem; font-size: 0.85rem; color: var(--text-muted); }
.mystory__status { margin: 0 0 0.15rem; font-size: 0.9rem; color: var(--text-muted); }
.mystory__dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 0.45rem;
  border-radius: 50%;
  background: var(--text-muted);
  vertical-align: 1px;
}
.mystory__dot--published { background: var(--gold); }   /* the one warm accent; text stays muted */
.mystory__sharing { margin: 0 0 0.9rem; font-size: 0.9rem; color: var(--text-muted); }
.mystory__excerpt p, .mystory__full p {
  margin: 0 0 0.8rem;
  font-size: 1rem;                        /* comfortable reading size, not small print */
  line-height: 1.65;
  color: var(--text-warm);
}
.mystory__full { margin-top: 0.4rem; }
.mystory__controls { margin: 0.4rem 0 0; display: flex; flex-wrap: wrap; align-items: center; }
.mystory__controls .auth-toggle + .auth-toggle,
.mystory__controls .mystory__withdraw { margin-left: 1.25rem; }
/* Withdraw reads as available, not inviting: same quiet link treatment,
   muted until interaction. */
.mystory__withdraw { color: var(--text-muted); }
.mystory__withdraw:hover { color: var(--purple-deep); }
.mystory__confirm {
  margin-top: 0.9rem;
  padding: 0.9rem 1rem;
  background: var(--lavender-light);
  border: 1px solid rgba(58, 42, 102, 0.14);
  border-radius: var(--radius);
}
.mystory__confirm p { margin: 0 0 0.5rem; font-size: 0.92rem; line-height: 1.55; color: var(--text); }
.mystory__confirm-head { font-weight: 700; color: var(--purple-deep); }
.mystory__confirm-controls { display: flex; flex-wrap: wrap; align-items: center; margin: 0.6rem 0 0; }
.mystory__confirm-controls .auth-toggle { margin-left: 1rem; }
.mystory__confirm-error { color: var(--purple-deep); font-weight: 600; }
.mystories__another { margin: 0.25rem 0 0; font-size: 0.95rem; color: var(--text-muted); }
/* Post-submission rhythm (2026-08): the confirmation and its action link are
   ONE moment; the standing panel (heading, profile link, count, rows) is
   another. Inside the moment, a breath; between the groups, a clear break -
   "Submit something else." used to sit 0px above the heading and read as its
   subtitle. The story page has no link between confirmation and heading, so
   its confirmation takes the same group break directly. The story list's
   end-of-list "Share another story." is untouched: sibling margins collapse
   under the cards' existing 2rem, so these rules change nothing there. */
.form-status--below + .mystories__another { margin-top: 1rem; }
.mystories__another + .mystories__heading,
.form-status--below + .mystories__heading { margin-top: 2.5rem; }
/* Contributor "Your submissions" card content (2026-08): description, author,
   URL, attachment and references lines - same quiet register as the story
   cards. The URL is plain text and truncates on one line so a long link can
   never widen the card. */
.mystory__desc { margin: 0 0 0.5rem; font-size: 1rem; line-height: 1.65; color: var(--text-warm); }
.mystory__author { margin: 0 0 0.5rem; font-size: 0.85rem; color: var(--text-muted); }
.mystory__url {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
  color: var(--text-muted);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mystory__file { margin: 0 0 0.5rem; font-size: 0.9rem; color: var(--text-muted); }
/* Story-card variant (2026-08): a long photo name truncates with an ellipsis
   instead of wrapping or widening the card. Scoped by modifier so the
   contributor rows' file line keeps its existing behaviour. */
.mystory__file--photo {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mystory__reflabel {
  margin: 0.4rem 0 0.15rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* Collapsed submission rows (contributor view, 2026-08): the whole header is
   ONE expand button - h3 wraps the button (valid accordion shape), summary
   lines are blockified spans, the caret is the visual state signal alongside
   aria-expanded. Detail (and the withdraw control) exists only expanded. */
.mystory--row { padding: 0; margin-bottom: 1rem; }   /* rows sit closer than the old full cards */
.mystory__titlerow { margin: 0; font: inherit; }
.mystory__head {
  display: block;
  width: 100%;
  min-height: 44px;
  text-align: left;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  padding: clamp(1rem, 2.5vw, 1.3rem) clamp(1.25rem, 3vw, 1.6rem);
  padding-right: 3.25rem;               /* room for the caret */
  position: relative;
  border-radius: var(--radius);
  cursor: pointer;
}
.mystory__head:hover { background: rgba(58, 42, 102, 0.05); }
.mystory__head:focus-visible {
  outline: 3px solid var(--purple-bright);
  outline-offset: -3px;
}
.mystory__head .mystory__title,
.mystory__head .mystory__meta,
.mystory__head .mystory__sharing,
.mystory__head .mystory__status { display: block; }
.mystory__head .mystory__sharing { margin-bottom: 0.35rem; }   /* status line closes the row */
.mystory__head .mystory__status { margin: 0; }
.mystory__caret {
  position: absolute;
  top: 50%;
  right: 1.4rem;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--purple);
  border-bottom: 2px solid var(--purple);
  transform: translateY(-70%) rotate(45deg);
  transition: transform 0.2s ease;
}
.mystory__head[aria-expanded="true"] .mystory__caret {
  transform: translateY(-30%) rotate(-135deg);
}
@media (prefers-reduced-motion: reduce) {
  .mystory__caret { transition: none; }
}
.mystory__detail {
  padding: 0.2rem clamp(1.25rem, 3vw, 1.6rem) clamp(1.1rem, 3vw, 1.4rem);
}
/* Status CHIP (2026-08): a small pill carrying the human status wording.
   Shared by the contributor rows and the patient story cards. Words carry
   the meaning; the pill and dot are decoration. Declined never gets the
   --chip class - it keeps its plain full-width line. */
.mystory__status--chip {
  display: inline-block;
  max-width: 100%;
  padding: 0.2rem 0.65rem;
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.18);
  border-radius: 999px;
  font-size: 0.82rem;
  line-height: 1.4;
}
/* CONTRIBUTOR ROWS ONLY: float the chip to the collapsed row's top right
   (absolute, so appearing or changing can never shift the row), in flow
   below the title on narrow screens. The patient story cards are full cards,
   not rows - their chip simply sits in flow where the status line already
   was. Title reserves width on wide screens so a long title and the chip can
   never overlap. */
.mystory__head .mystory__status--chip {
  position: absolute;
  top: clamp(0.9rem, 2.2vw, 1.15rem);
  right: 3.25rem;                       /* clear of the caret */
  margin: 0;
  max-width: 40%;
}
@media (min-width: 640px) {
  .mystory__head .mystory__title { max-width: 55%; }
}
@media (max-width: 639.98px) {
  .mystory__head .mystory__status--chip {
    position: static;
    display: inline-block;
    max-width: none;
    margin: 0.2rem 0 0.35rem;
  }
}
/* Submission count + "Show older submissions" row (2026-08). */
.mystories__count { margin: 0 0 0.6rem; font-size: 0.9rem; color: var(--text-muted); }
.mystories__more { margin: 0.5rem 0 0; }

/* ---- Member-area tabs (2026-08) -------------------------------------------
   Shared by the contributor portal (portal-submit.html) and the patient
   member page (member-story.html): both split "do the thing" from "see what
   I've done", and both load THIS stylesheet - so the rules live here rather
   than in portal.css, in one copy. (The .portal-* names are historical: they
   were built for the portal first. Renaming them would mean editing the
   contributor portal's markup, out of scope when the patient page adopted
   them - a rename is a clean follow-up.)
   The selected tab is marked by a 3px underline AND heavier weight AND
   darker text - never colour alone. No transition is declared, so tab
   switching is inherently reduced-motion safe. */
.portal-tabs { padding: clamp(1.4rem, 3.5vw, 2.2rem) 0 0; }
.portal-tabs__list {
  display: flex;
  flex-wrap: wrap;
  border-bottom: 1px solid rgba(58, 42, 102, 0.16);
}
.portal-tab {
  flex: 1 1 12rem;              /* side by side when they fit, stacked when not */
  min-height: 44px;
  margin-bottom: -1px;          /* the selected underline sits ON the hairline */
  padding: 0.7rem 1rem;
  background: none;
  border: 0;
  border-bottom: 3px solid transparent;
  font: inherit;
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.35;
  color: var(--text-muted);
  text-align: center;
  cursor: pointer;
}
.portal-tab:hover { color: var(--purple-deep); }
.portal-tab[aria-selected="true"] {
  font-weight: 700;
  color: var(--purple-deep);
  border-bottom-color: var(--purple-bright);
}
.portal-tab:focus-visible {
  outline: 3px solid var(--purple-bright);
  outline-offset: -3px;
  border-radius: 6px 6px 0 0;
}
.portal-tab__count { font-variant-numeric: tabular-nums; }
/* A hidden panel must stay hidden even though .section/.mystories set layout. */
.portal-panel[hidden] { display: none; }
/* auth-toggle (44px link-style button) is defined in auth.css, which this
   page does not load - carry the same recipe here for these controls. */
.mystory__expand, .mystory__withdraw, .mystory__confirm-controls .auth-toggle,
.mystories__profile-cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.2rem 0.15rem;
  background: none;
  border: 0;
  font: inherit;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--purple);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.mystory__expand:hover, .mystory__confirm-controls .auth-toggle:hover,
.mystories__profile-cta:hover { color: var(--purple-bright); }
.mystory__expand:focus-visible, .mystory__withdraw:focus-visible,
.mystory__confirm-controls .auth-toggle:focus-visible,
.mystories__profile-cta:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; border-radius: 6px; }
/* The recipe above sets display:inline-flex - an author rule that would beat
   the UA's [hidden] { display: none }. Without this the invitation would show
   for everyone, including members who have already completed their profile. */
.mystories__profile-cta { margin: 0 0 0.35rem; }
.mystories__profile-cta[hidden] { display: none; }
/* One-shot "profile saved" line in the member banners (2026-08: was the shared
   --info card; a bordered panel is oversized for four words and it never left).
   Now a quiet line in the banner's own voice - no box, no border, no fill.
   gem-auth.js dismisses it after 8 seconds by adding .is-dismissed: visibility
   (not display) keeps the element's box, so nothing below it shifts when it
   goes, and a polite live region never announces removals, so it goes quietly.
   The fade is motion-gated; reduced motion gets an instant switch. The [hidden]
   guard keeps the pre-reveal state safe from any future display rule. */
.page-banner__saved { margin: 0.75rem 0 0; max-width: 34rem; font-size: 0.95rem; font-weight: 600; color: var(--text-warm); }
.page-banner__saved[hidden] { display: none; }
.page-banner__saved.is-dismissed { opacity: 0; visibility: hidden; }
@media (prefers-reduced-motion: no-preference) {
  .page-banner__saved { transition: opacity 0.6s ease, visibility 0s linear 0.6s; }
}
.form-status--info { background: var(--lavender); color: var(--purple); border: 1px solid var(--gold); }
.form-status--error { background: #fbecec; color: var(--purple-deep); border: 1px solid var(--purple-deep); }

/* Large story textarea (Share Your Story) — extra room to write or dictate. */
textarea.textarea-lg { min-height: 13rem; }

/* Gentle inline note (e.g. "we'll ask for a quick registration first"). */
.form-note {
  background: var(--lavender);
  border-left: 4px solid var(--gold);
  border-radius: 8px;
  padding: 0.85rem 1rem;
  margin: 0 0 1.4rem;
  color: var(--purple-deep);
  text-align: left;
}
.form-note :last-child { margin-bottom: 0; }

/* Standalone preview/info banner at the top of a page — same gentle, on-brand
   language as .form-note (lavender + gold accent, never an error), positioned
   above the form and sized to the form column. AA: purple-deep on lavender. */
.page-notice-wrap { padding-top: clamp(1.25rem, 3vw, 2rem); }
.page-notice {
  display: flex;
  align-items: flex-start;
  max-width: 600px;
  margin-inline: auto;
  background: var(--lavender);
  border-left: 4px solid var(--gold);
  border-radius: 8px;
  padding: 0.9rem 1.1rem;
  color: var(--purple-deep);
  text-align: left;
}
.page-notice p { margin: 0; font-size: 0.95rem; line-height: 1.55; }
.page-notice__icon { flex: 0 0 auto; width: 20px; height: 20px; color: var(--gold); margin-top: 0.15rem; margin-right: 0.65rem; }   /* icon↔text via margin, not flex gap (Safari <14.1) */

/* Prominent "new here? register" call-out on the sign-in page — makes the
   sign-in-or-register fork obvious. On-brand lavender panel; AA throughout. */
.signin-register {
  margin-top: 1.5rem;
  padding: 1.1rem 1.25rem;
  background: var(--lavender);
  border: 1px solid rgba(58, 42, 102, 0.12);
  border-left: 4px solid var(--gold);
  border-radius: 10px;
  text-align: left;
}
.signin-register__lead {
  margin: 0 0 0.2rem;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--purple-deep);
}
.signin-register__text { margin: 0; font-size: 0.98rem; color: var(--text); }
.signin-register__text a { color: var(--purple); font-weight: 600; text-underline-offset: 3px; }

/* --- Patient Stories: scalable, EQUAL-WEIGHT story feed ----------------------
   Review-style cards (tag + person·place + gold divider + short excerpt + Read
   more) that expand IN PLACE into the full left-aligned letter (the base
   .story-body typography below). Every story is one self-contained
   <li><article class="story-entry"> following the same template — no featured
   hero. The old blue-linen photo background is retired: the section sits on the
   site's standard light lavender, the cards on warm letter-paper cream. */
.stories-feed { background: var(--white); }   /* mockup 2026-08: the two slots float on the white page ground */
.stories-feed__heading {
  color: var(--purple);
  font-size: var(--fs-h2);
  margin: 0 0 0.4rem;
}
.stories-feed__lede {
  color: var(--text-warm);
  font-size: var(--fs-lede);
  max-width: 58ch;
  margin: 0 0 clamp(1.5rem, 3.5vw, 2.25rem);
}
/* Warm serif-italic closing line under the whole feed (matches the page's .story-lede voice). */
.stories-feed__closing {
  margin: clamp(2.25rem, 5vw, 3.25rem) auto 0;
  max-width: 46ch;
  text-align: center;
  font-family: var(--font-head);
  font-style: italic;
  font-size: clamp(1.1rem, 2.2vw, 1.35rem);
  line-height: 1.6;
  color: var(--purple);              /* ~9.5:1 on the lavender-light section = AA+ */
}
/* SCALABLE STORY GRID — equal-weight responsive cards (used ONLY on
   patient-stories.html; no other page carries .story-entry). One template per
   card: name/Anonymous -> country -> 4-line line-clamped preview -> Read more
   (expands the full story in place, reusing the shared generic .story-entry
   toggle in ui.js — no JS change). FOLDED cards carry NO image and no
   placeholder; a photo (when one exists) lives inside the expanded story only.
   The 4-line-min preview is what keeps COLLAPSED cards a shared height;
   align-items:start lets an OPENED card grow without stretching its row-mates. */
.stories-feed__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;                /* phones: one column */
  gap: clamp(1rem, 2.5vw, 1.5rem);
  align-items: start;                         /* opened card grows down; siblings never stretch to it */
}
@media (min-width: 620px)  { .stories-feed__list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .stories-feed__list { grid-template-columns: repeat(3, 1fr); } }
/* display:contents lifts each .story-entry OUT of its <li> so the article itself is
   the grid item — that lets an OPENED card span the full row via grid-column below
   (no :has(), no JS parent-toggle). The <ul role="list"> keeps list semantics. */
.stories-feed__list > li { display: contents; }
.story-entry {
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--cream);              /* warm letter-paper cream on the lavender section */
  border: 1px solid rgba(58, 42, 102, 0.10);
  border-radius: var(--radius);
  box-shadow: 0 8px 26px rgba(46, 33, 80, 0.10);
  padding: clamp(1.25rem, 3vw, 1.6rem);
}
.story-entry__head { display: block; }
.story-entry__tag {
  display: inline-block;
  margin: 0 0 0.6rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--purple-mid);              /* ~7:1 on cream = AA */
}
.story-entry__tag--sample {              /* unmistakable placeholder badge (non-negotiable "Sample" mark) */
  color: var(--gold-deep);               /* ~5:1 on cream = AA */
  background: rgba(187, 134, 63, 0.12);
  border: 1px solid rgba(187, 134, 63, 0.5);
  padding: 0.16rem 0.55rem;
  border-radius: 999px;
}
.story-entry__who {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: var(--fs-h3);
  color: var(--purple);
}
.story-entry__place {
  margin: 0.2rem 0 0;
  color: var(--text-muted);              /* AA on cream */
  font-size: 0.9rem;
}
/* Photo slot — client direction: photos appear ONLY in the OPENED story, and only
   when a real one exists. The slot therefore lives INSIDE .story-entry__full (so the
   folded card can never show it) and the markup omits the div entirely when there is
   no photo — nothing is reserved, so the space condenses with no empty frame. The old
   crest-watermark placeholder is gone: no placeholder is drawn anywhere, and there is
   no background here, so a stray empty div would collapse rather than paint a box. */
.story-entry__photo {
  position: relative;
  width: min(100%, 520px);               /* contained, never full-bleed */
  margin: 0 0 1.25rem;                   /* sits above the letter's opening line */
  aspect-ratio: 3 / 2;
  border-radius: 10px;
  overflow: hidden;
}
.story-entry__photo img {
  display: block; width: 100%; height: 100%;
  object-fit: cover;
}
@supports not (aspect-ratio: 1 / 1) {    /* Safari <15 fallback: padding-ratio box */
  .story-entry__photo { height: 0; padding-top: 66.6667%; }
  .story-entry__photo img { position: absolute; top: 0; left: 0; height: 100%; }
}
/* QUOTE + PHOTOGRAPH ROW (2026-08, replaces the top-right corner thumb): the
   folded card's pull-quote (left, 3fr ~60%) and a landscape 4:3 crop of the
   story photo (right, 2fr ~40%) sit as one composition, vertically CENTRED on
   each other (align-items). grid-gap, not flex gap (Safari <14.1). The img
   attrs (800x600) match the 4:3 CSS ratio - no layout shift. object-position
   center 35% biases the crop upward: both faces sit in the frame's 27-45%
   band and the shed 18% is mostly floor. Hidden the moment the card opens
   (the letter opens with the same line and carries the full photograph);
   .js-gated so no-JS (which shows the full letter + real figure) never
   duplicates the image. Not interactive. Repeatable .story-entry template. */
.story-entry__quoterow {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  grid-column-gap: 1.1rem;
  align-items: center;
}
.story-entry__thumb { display: none; }   /* folded preview exists only under .js */
.js .story-entry__thumb {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;                   /* Safari <15: attrs 800x600 give the same ratio via width/height */
  object-fit: cover;
  object-position: center 35%;
  border-radius: 7px;                    /* half the card's 14px - same design system (commit: edge finish) */
  border: 1px solid rgba(46, 33, 80, 0.11);   /* --purple-deep hairline @11% - a felt edge on the cream card */
  margin-top: 1.1rem;                    /* rides the quote's own top margin so the pair centre together */
}
.js .story-entry.is-open .story-entry__quoterow { display: none; }   /* the opened letter takes over (quote line + full figure) */
/* NARROW SCREENS (<640px, the site's true-mobile line): stack - quote first,
   image below at full column width. The image keeps a LANDSCAPE crop but
   shallower (2:1) so it cannot push the Read button far down a small phone -
   the height cost at 375px is ~160px instead of ~250px. */
@media (max-width: 639.98px) {
  .story-entry__quoterow { grid-template-columns: minmax(0, 1fr); grid-row-gap: 0; }
  .js .story-entry__thumb { aspect-ratio: 2 / 1; margin-top: 0.9rem; }
}
/* Preview (JS) vs full story (no-JS default). No-JS: the toggle never renders, so
   the FULL story shows and the preview is hidden. JS: the 4-line preview shows and
   the full story is revealed in place on Read more. */
.story-entry__preview {
  display: none;                         /* no-JS: hidden */
  margin: 1rem 0 0;
  color: var(--text-warm);
  font-size: 1rem;
  line-height: 1.6;
}
.story-entry__preview p { margin: 0; }
.story-entry__full { display: block; margin: 1rem 0 0; }   /* no-JS: shown */
.story-entry .story-body { text-align: left; color: var(--text-warm); margin-inline: 0; }
.js .story-entry__preview {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;                 /* truncates cleanly at 4 lines */
  line-clamp: 4;
  overflow: hidden;
  min-height: 6.4em;                     /* reserve 4 lines so collapsed cards align */
}
@supports not ((-webkit-line-clamp: 4) or (line-clamp: 4)) {
  .js .story-entry__preview { display: block; max-height: 6.4em; overflow: hidden; }   /* 4 lines x 1.6 */
}
.js .story-entry__full { display: none; }                  /* JS: full hidden until opened */
.js .story-entry.is-open .story-entry__preview { display: none; }
.js .story-entry.is-open .story-entry__full { display: block; }
/* OPTION B — an opened card spans the FULL content row (all grid columns) and takes
   its own row; the other cards reflow below it in document order (no dense, so no
   reordering), never overlapping. On phones the grid is 1 column, so 1 / -1 is just
   full width = a normal inline expand. The expanded story reads as a LEFT-ALIGNED
   LETTER (client direction) — see the letter block below. */
.js .story-entry.is-open { grid-column: 1 / -1; }
.js .story-entry.is-open .story-entry__full { animation: storyExpand 0.35s ease both; }   /* gentle fade/rise on reveal */
@keyframes storyExpand { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .js .story-entry.is-open .story-entry__full { animation: none; }
}

/* EXPANDED STORY = LEFT-ALIGNED LETTER/EMAIL (only when .is-open; collapsed cards and
   the 3-across grid are untouched). A deliberate, generous LEFT margin shared by the
   image and the text column; the text is capped at a comfortable measure so the
   leftover whitespace sits on the RIGHT as intentional letter margin — not centred,
   not full-width. Mobile (1-col) just fills the width with the card's normal padding. */
.js .story-entry.is-open {
  padding-left: clamp(1.5rem, 4vw, 3rem);     /* generous, even left margin (the letter's left edge) */
  padding-right: clamp(1.25rem, 2.5vw, 1.75rem);
}
/* (The old .is-open photo rule is gone: the slot now lives inside .story-entry__full,
   so it is already left-aligned to the letter's edge and sized by the base rule.) */
.js .story-entry.is-open .story-entry__full {
  max-width: 70ch;                            /* ~640-760px comfortable letter measure */
  margin-inline: 0;                           /* stays at the left margin; right whitespace is the letter margin */
  text-align: left;                           /* explicit: never centred */
}
.story-entry__more { display: none; margin: auto 0 0; padding-top: 1.15rem; }   /* pinned to the card bottom */
.js .story-entry__more { display: block; }                          /* the control exists only when JS can drive it */
/* 2026-08 quiet close (client direction): while the story is OPEN the toggle
   sheds its gold-button skin and becomes a small "Close" + upward chevron in
   the card's LOWER-RIGHT corner - understated text, not a pill. Still a real
   button: 44px min hit box, full accessible name via aria-label (ui.js), and
   a purple-bright focus ring (NOT the raw --focus token). Closed state (the
   gold "Read Yifei's Story" button) is untouched; the chevron only renders
   while open. */
.story-entry__toggle-chev { display: none; width: 1em; height: 1em; margin-left: 0.3rem; }
.js .story-entry.is-open .story-entry__more { display: flex; justify-content: flex-end; padding-top: 0.5rem; }
.js .story-entry.is-open .story-entry__toggle {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  padding: 0.5rem 0.25rem;
  background: transparent;
  border: 0;
  box-shadow: none;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--purple-bright);           /* 5.9:1 on the cream card */
}
.js .story-entry.is-open .story-entry__toggle:hover { color: var(--purple-deep); background: transparent; }
.js .story-entry.is-open .story-entry__toggle .story-entry__toggle-chev { display: inline-block; }
.js .story-entry.is-open .story-entry__toggle:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; border-radius: 6px; }
.story-body {
  max-width: 66ch;
  margin-inline: auto;
  font-size: 1.06rem;
  line-height: 1.8;
  color: var(--text);
}
.story-body p { margin: 0 0 1.15rem; }
.story-lede {
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.3rem;
  line-height: 1.7;
  color: var(--purple);
  margin-bottom: 2rem;
}
.story-lead {                          /* the manuscript's bold beat lines */
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--purple);
  margin-top: 2rem;
}
.story-pull {                          /* "I was the one waiting. / The disease never was." */
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.4rem;
  line-height: 1.55;
  color: var(--purple-deep);
  border-left: 3px solid var(--gold);
  padding-left: 1.1rem;
  margin: 1.9rem 0;
}
.story-bullet {                        /* manuscript keeps literal bullets — hang the wrap */
  padding-left: 1.2rem;
  text-indent: -1.2rem;
}
.story-closing-line {                  /* the story's final line, set apart */
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.25rem;
  line-height: 1.6;
  color: var(--purple);
  border-top: 1px solid rgba(58, 42, 102, 0.18);
  padding-top: 1.6rem;
  margin-top: 2.4rem;
}
.story-cta { margin-top: 1.9rem; }

/* Empty state — Patient Stories showcase before any stories are published. */
.empty-state {
  max-width: 42rem;
  margin: 0 auto;
  text-align: center;
}
.empty-state__icon {
  display: block;
  width: 52px;
  height: 52px;
  margin: 0 auto 1rem;
  color: var(--gold);
}
.empty-state .placeholder-note { display: inline-block; margin-bottom: 0.75rem; }
.empty-state h2 { color: var(--purple); margin: 0 0 0.6rem; }
.empty-state p { color: var(--text-muted); }
.empty-state .btn { margin-top: 1rem; }

/* Manifesto temporarily pending — a small centered cream "content-pending" card
   (same family as the Awaiting-from-GEM placeholders) while the Chairman revises
   his message: cream paper, gold top accent + dashed pill, purple message. */
.manifesto-pending {
  max-width: 34rem;
  margin: clamp(1.5rem, 5vw, 3rem) auto;
  padding: clamp(1.75rem, 5vw, 2.75rem);
  text-align: center;
  background: var(--cream);
  border: 1px solid var(--lavender);
  border-top: 4px solid var(--gold);
  border-radius: var(--radius);
  box-shadow: 0 4px 16px rgba(46, 33, 80, 0.06);
}
.manifesto-pending .placeholder-note { display: inline-block; margin-bottom: 0.9rem; }
.manifesto-pending p {
  margin: 0;
  max-width: none;
  color: var(--purple);
  font-family: var(--font-head);
  font-size: clamp(1.1rem, 2.4vw, 1.3rem);
  line-height: 1.5;
}

/* Honeypot — visually hidden but present for bots */
.hp-field {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* ===================================================================
   11. Advocacy — mandates
   =================================================================== */
.mandates {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
  counter-reset: mandate;
}
.mandate {
  position: relative;
  padding: 1.5rem 1.5rem 1.5rem 4.25rem;
  background: var(--white);
  border: 2px solid var(--lavender);
  border-radius: var(--radius);
}
.mandate::before {
  counter-increment: mandate;
  content: counter(mandate);
  position: absolute;
  left: 1.25rem; top: 1.25rem;
  width: 2.25rem; height: 2.25rem;
  display: grid; place-items: center;
  font-family: var(--font-head);
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--white);
  background: var(--gold);
  border-radius: 50%;
}
.mandate h3 { margin-top: 0; }
.mandate p:last-child { margin-bottom: 0; }

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

/* ===================================================================
   12. Support / safeguarding
   =================================================================== */
.callout {
  background: var(--purple);
  color: var(--white);
  border-radius: var(--radius);
  padding: 1.5rem 1.75rem;
  margin: 1.5rem 0;
}
.callout h2, .callout h3 { color: var(--white); margin-top: 0; }
.callout p { color: var(--lavender); }
.callout p:last-child { margin-bottom: 0; }

.regions {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
}
.region {
  padding: 1.25rem 1.5rem;
  background: var(--white);
  border: 2px solid var(--lavender);
  border-radius: var(--radius);
}
.region h3 { margin: 0 0 0.35rem; }
.region p { margin: 0; color: var(--text-muted); }

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

/* ===================================================================
   13. Illustrations & media
   =================================================================== */

/* Decorative banner illustration on a page/section. Never upscaled beyond its
   natural size (files are pre-sized); scales down to fit narrow screens. */
.page-illustration {
  display: block;
  width: 100%;
  max-width: min(100%, 640px);
  height: auto;
  border-radius: var(--radius);
  margin: 1.5rem auto;
}

/* Two-column text + image (used by the home "why we exist" section). */
.split {
  display: grid;
  gap: 1.5rem;
  align-items: center;
  grid-template-columns: 1fr;
}
.split__text > :last-child { margin-bottom: 0; }
.split__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);              /* soft rounded corners — matches the site's cards */
  box-shadow: 0 14px 34px rgba(46, 33, 80, 0.12);  /* same soft lift used on the site's other photos */
}
/* Why-we-exist media: a wider image cover-cropped to keep the existing card
   shape (1.49:1), centred so the joined hands stay in frame. */
.split__media--cover img {
  aspect-ratio: 1200 / 804;
  object-fit: cover;
  object-position: center;
  box-shadow: 0 14px 34px rgba(46, 33, 80, 0.12);
}
@media (min-width: 820px) {
  .split { grid-template-columns: 1.05fr 0.95fr; gap: 2.5rem; }
  /* Cap a tall portrait so it doesn't dwarf the text or leave the column empty.
     Aspect ratio is preserved (width follows height); the card hugs the photo. */
  .split__media .photo-card { width: -moz-fit-content; width: fit-content; margin-inline: auto; }
  .split__media .photo-card img { max-height: 420px; width: auto; max-width: 100%; }
}

/* Photo card — rounded, bordered, matching our card style. Aspect ratio preserved
   (width 100% / height auto), never stretched or distorted. */
.photo-card {
  margin: 0;
  border-radius: var(--radius);
  overflow: hidden;
  border: 2px solid var(--lavender);
  box-shadow: 0 4px 16px rgba(46, 33, 80, 0.06);
  background: var(--white);
}
.photo-card img { display: block; width: 100%; height: auto; }

/* Two equal photos side by side on desktop, stacking on mobile. Both images share
   the same aspect ratio, so equal columns give equal heights with no cropping. */
.gem-in-action { margin-top: 2.5rem; }
.gem-in-action h3 { border-bottom: 2px solid var(--gold); padding-bottom: 0.4rem; }
.photo-row {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  margin-top: 1.25rem;
}
/* On desktop, sit side by side at equal height. Widths follow each photo's own
   aspect ratio (portrait vs landscape), so nothing is stretched or cropped. */
@media (min-width: 820px) {
  .photo-row { flex-direction: row; align-items: center; justify-content: center; }
  .photo-row .photo-card { flex: 0 1 auto; }
  .photo-row .photo-card img { width: auto; height: 340px; }
}

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

/* ===================================================================
   15. Advocacy page (Chairman's message)
   =================================================================== */
/* Warm cream base so the white cards and lavender bands read as distinct layers. */
body.page-advocacy { background: var(--cream); }

/* Chairman's opening — a touch larger than body for a personal, letter-like voice. */
/* Chairman's opening: his photo beside his words. Mobile-first — photo stacked
   on top, text below; two columns from 820px with the photo top-aligned to the
   paragraph (align-items: start, not centre). */
.advocacy-lede {
  display: grid;
  gap: 1.5rem;
  align-items: start;
  grid-template-columns: 1fr;
}
.advocacy-lede__photo { max-width: 260px; }
.advocacy-lede__photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);              /* soft rounded corners — matches the site's cards */
  box-shadow: 0 14px 34px rgba(46, 33, 80, 0.12);
}
.advocacy-lede__text { max-width: 68ch; }     /* keep the readable measure the lede had */
.advocacy-lede p { font-size: 1.1rem; }
@media (min-width: 820px) {
  .advocacy-lede {
    grid-template-columns: 240px minmax(0, 68ch);
    gap: 2.5rem;
  }
}

/* Featured pull-quote — deep purple block with a gold edge; deliberately loud. */
.pullquote {
  margin: 2rem 0 0;
  padding: clamp(1.5rem, 4vw, 2.5rem);
  background: linear-gradient(135deg, var(--purple) 0%, var(--purple-deep) 100%);
  border-left: 6px solid var(--gold);
  border-radius: var(--radius);
  color: var(--white);
  box-shadow: 0 12px 32px rgba(46, 33, 80, 0.2);
}
.pullquote p {
  margin: 0;
  max-width: 48ch;
  font-family: var(--font-head);
  font-size: clamp(1.25rem, 2.8vw, 1.6rem);
  line-height: 1.4;
  color: var(--white);
}

/* Three audience blocks — white cards with a gold top edge, generously spaced. */
.audience-card {
  background: var(--white);
  border: 1px solid var(--lavender);
  border-top: 4px solid var(--gold);   /* gold accent top edge — kept */
  border-radius: var(--radius);
  box-shadow: 0 4px 16px rgba(46, 33, 80, 0.06);
  overflow: hidden;                     /* clip the collapsing panel to the rounded corners */
}
.audience-card + .audience-card { margin-top: 1.75rem; }
.audience-card__title { margin: 0; }   /* semantic heading wrapper; the button carries the look */

/* Toggle header — a real <button> spanning the whole title bar, clearly clickable. */
.audience-card__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  margin: 0;
  padding: clamp(1.1rem, 3vw, 1.6rem) clamp(1.5rem, 4vw, 2.75rem);
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: clamp(1.3rem, 3vw, 1.7rem);
  color: var(--purple);
  transition: background-color 0.15s ease;
}
.audience-card__toggle:hover { background: var(--lavender); }   /* subtle hover — reads as clickable */
.audience-card__toggle:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.audience-card__chevron {
  flex: 0 0 auto;
  color: var(--gold);
  font-size: 0.8em;
  transition: transform 0.28s ease;
}
.audience-card__toggle[aria-expanded="true"] .audience-card__chevron { transform: rotate(180deg); }

/* Panel — the text now fills the FULL card width with equal side padding (the old
   68ch cap left wide cards half-empty). Open by default so ALL content is readable
   with NO JavaScript. */
.audience-card__panel { display: grid; grid-template-rows: 1fr; }
.audience-card__panel-inner { min-height: 0; overflow: hidden; }
.audience-card__panel .prose {
  max-width: none;
  padding: 0 clamp(1.5rem, 4vw, 2.75rem) clamp(1.5rem, 4vw, 2.5rem);
}
/* The global `p { max-width: var(--maxw) }` (and it applies to the bold lead line
   and any list too) would otherwise cap the panel text at ~72ch and pin it LEFT
   of the wide card, leaving an empty right column. Clear it on every block child
   so the content fills the full usable width under the heading, with the prose's
   equal side padding. Mobile is unaffected: the card there is narrower than
   --maxw, so this cap never applied on small screens. */
.audience-card__panel .prose > * { max-width: none; }
.audience-card .prose p:last-child { margin-bottom: 0; }

/* JS active → the panels become an accordion, animating real height via the
   grid-template-rows 0fr↔1fr technique (no magic max-height number). */
.js .audience-card__panel { grid-template-rows: 0fr; transition: grid-template-rows 0.32s ease; }
.js .audience-card__panel.is-open { grid-template-rows: 1fr; }
/* Collapsed content leaves the a11y tree + tab order once the collapse finishes;
   it's revealed immediately on open so screen readers read it when expanded. */
.js .audience-card__panel-inner { visibility: hidden; transition: visibility 0s linear 0.32s; }
.js .audience-card__panel.is-open .audience-card__panel-inner { visibility: visible; transition: visibility 0s linear 0s; }
@media (prefers-reduced-motion: reduce) {
  .js .audience-card__panel, .audience-card__chevron { transition: none; }
}
/* The pledge line — bold and lifted so it lands. */
.audience-card__lead {
  font-size: 1.1rem;
  color: var(--purple-deep);
}

/* Superscript reference markers. */
.cite { font-size: 0.7em; }
.cite a { color: var(--purple-deep); font-weight: 600; text-decoration: none; }
.cite a:hover { text-decoration: underline; }
.cite a:focus-visible { text-decoration: underline; }

/* Four demands — numbered cards, gold numeral on a purple disc; 2-up desktop, 1-up mobile. */
.demands__intro { max-width: 68ch; }
.demands {
  list-style: none;
  margin: 1.75rem 0 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}
.demand {
  display: flex;
  align-items: flex-start;
  background: var(--white);
  border: 1px solid var(--lavender);
  border-top: 4px solid var(--gold);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vw, 1.75rem);
  box-shadow: 0 4px 16px rgba(46, 33, 80, 0.06);
}
.demand__num {
  flex: 0 0 auto;
  margin-right: 1.1rem;               /* numeral↔text via margin, not flex gap (Safari <14.1) */
  display: grid;
  place-items: center;
  width: 3rem; height: 3rem;
  border-radius: 50%;
  background: var(--purple);
  border: 2px solid var(--gold);
  color: var(--gold);
  font-family: var(--font-head);
  font-size: 1.5rem;   /* large-text size → gold-on-purple meets AA */
  font-weight: 700;
  line-height: 1;
}
.demand__title { margin: 0.15rem 0 0.5rem; color: var(--purple); font-size: 1.15rem; }
.demand__body p { margin: 0; }
@media (min-width: 760px) {
  .demands { grid-template-columns: repeat(2, 1fr); gap: 1.5rem; }
}

/* Call to action — the whole block ABOVE the gold divider is centered (heading,
   intro paragraph, and button row), matching the already-centered closing quote
   below it. The intro paragraph gets a readable centered measure so lines don't
   stretch edge to edge. :not(.advocacy-emphasis) leaves the closing quote's own
   max-width/margin/gold border untouched. */
.advocacy-cta > .container { text-align: center; }
.advocacy-cta > .container > p:not(.advocacy-emphasis) { max-width: 60ch; margin-inline: auto; }
.advocacy-cta__actions { justify-content: center; }
.advocacy-emphasis {
  max-width: 42ch;
  margin: 1.75rem auto 0;
  padding-top: 1.5rem;
  border-top: 2px solid var(--gold);
  text-align: center;
  font-family: var(--font-head);
  font-size: clamp(1.2rem, 2.6vw, 1.5rem);
  font-weight: 600;
  line-height: 1.35;
  color: var(--purple-deep);
}

/* Signature — short gold rule above the name, like the letter. */
.signature {
  max-width: 26rem;
  margin: 0 0 2.25rem;
  padding-top: 1.25rem;
  border-top: 3px solid var(--gold);
}
.signature__name {
  margin: 0 0 0.15rem;
  font-family: var(--font-head);
  font-weight: 600;
  color: var(--purple);
  font-size: 1.2rem;
}
.signature__role { margin: 0; color: var(--text-muted); }

/* Closing personal appeal — quieter and more intimate: italic, muted, soft indent. */
.advocacy-appeal {
  max-width: 62ch;
  margin: 0 0 2.75rem;
  padding-left: 1.25rem;
  border-left: 3px solid var(--lavender);
}
.advocacy-appeal p {
  margin: 0;
  font-style: italic;
  color: var(--text-muted);
  font-size: 0.98rem;
}

/* References — small footnotes; long URLs wrap so nothing overflows on mobile. */
.references { border-top: 1px solid var(--lavender); padding-top: 1.5rem; }
.references__title {
  margin: 0 0 0.75rem;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.references__list { margin: 0; padding-left: 1.3rem; font-size: 0.85rem; color: var(--text-muted); }
.references__list li { margin-bottom: 0.5rem; line-height: 1.5; }
.references__list li:last-child { margin-bottom: 0; }
.references__list a { color: var(--purple-deep); overflow-wrap: anywhere; }

/* ===================================================================
   11. Editorial redesign — index.html only (branch: redesign-v4-preview)
   Everything here is scoped to .site-header--editorial / .hero--editorial
   so the shared header/hero on other pages is untouched. Brightened
   palette: light --lavender-light scrim with dark headings over the video
   (dark surfaces are reserved for the footer and the future quote band);
   actions and accents use --purple-bright. rgba() literals are the
   tokens' RGB values, commented where used.
   =================================================================== */

/* Slim single-row masthead → smaller anchor offset than the 3-row header.
   Plain html rule, not :root:has() (Safari 15.4+): every page carries the
   editorial header, so the condition was unconditionally true anyway. Being
   later in the sheet, this also outranks the base 82px rule — 88px everywhere,
   exactly what the :has() version computed to. */
html { scroll-padding-top: 124px; }   /* taller masthead (bigger logo) — anchor jumps clear it */

/* --- "Join Us" — gold-outlined pill, filled with the bright violet (white
   label, 6.5:1 = AA). Gold stays outline-only (decorative ring, 3.2:1 against
   the white header = UI-component AA); hover settles into the deeper --purple. --- */
.header-join {
  display: none;                 /* desktop-only; hidden in the mobile cluster */
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  line-height: 1;
  padding: 0.5rem 1.15rem;
  border: 2px solid var(--gold);
  border-radius: 999px;
  background: var(--purple-bright);
  color: var(--white);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.header-join:hover {
  background: var(--purple);
  border-color: var(--gold);
  color: var(--white);
}
.header-join:focus-visible {
  background: var(--purple);
  border-color: var(--gold);
  color: var(--white);
}
.header-join:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* =======================  Desktop masthead (>=1200px)  =======================
   ONE true flex row in normal document flow: THREE dedicated columns —
   [.brand: flex 0 0 auto] [.primary-nav: flex 1 1 auto, min-width 0]
   [.header-actions: flex 0 0 auto] — no absolute positioning, no transforms,
   no negative layout margins, so the columns' BOXES can never overlap.
   THE OLD SAFARI OVERLAP was not box overlap: the nav's nowrap 7-item <ul>
   (justify-content: flex-end) OVERFLOWED its column when Safari's wider text
   metrics pushed the row past the old 1360px cap minus padding (~1320px of
   room vs ~1330-1365px of content) — flex-end overflow spills LEFT, painting
   "Home" over the logo. Chrome's narrower metrics just squeaked in. Fixed
   structurally, not by spacing: (1) the row's cap is 1520px (real room), and
   (2) the <ul> is flex-wrap: wrap — if ANY engine/zoom/font combo ever exceeds
   the space, trailing items wrap to a second line below (bar grows taller),
   NEVER painting over the brand. That wrap net is why the desktop entry point is
   at 1600px (2026-08 refine: down from 1620 after the cluster/gutter tightening reclaimed 31px - the true fit point is ~1511px Chrome / ~1534px Safari of content, so 1560px of content at the 1600 threshold keeps a 26px Safari margin): at narrow desktop widths the row may
   wrap to 2 lines, but it can never re-create the Mac overlap. Where the row fits
   (wide desktops), wrap renders identically to nowrap — zero shift on correct
   platforms. Spacing stays margin-based (no flex gap — Safari <14.1); logo size
   untouched. */
@media (min-width: 1400px) {
  .site-header--editorial { background: var(--white); border-bottom: 1px solid rgba(58, 42, 102, 0.12); }
  .site-header--editorial::before { display: none; }

  .site-header--editorial .header-inner {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0;                         /* spacing via margins below */
    padding-block: 1.5rem;          /* noticeably taller, premium breathing room (desktop) — balanced top/bottom */
    /* The FULL 7-item row (lockup + 7 links/carets + utilities + Join) measures
       ~1330px in Chrome and ~1365px in Safari (wider text metrics) — the old
       1360px cap left only ~1320px of content box (cap minus the container's
       1.25rem side padding), so Safari OVERFLOWED on every MacBook. 1520px
       gives the measured Safari row ≥115px of spare at full width; below the
       row's natural width (narrow desktops from the 1200px entry point up) the
       flex-wrap net drops trailing items to a 2nd line rather than overflowing. */
    max-width: 1620px;   /* 2026-08: raised from 1520 - the measured row (logo 225 + menu 908 + gaps + utilities 365 = ~1518px Chrome, ~1540px Safari-metrics) no longer fit the old cap ANYWHERE, so the wrap net fired at every width. 1620 gives >=40px spare. */
  }

  /* Order: logo (left) → nav (fills the middle) → utilities + Join (right). */
  .site-header--editorial .brand {
    order: 1;
    flex: 0 0 auto;                 /* the lockup never shrinks or wraps */
    padding-block: 0;
    margin-right: 1rem;             /* 2026-08 tighten: 16px gutter (was 28) - still a real logo/nav buffer; the wrap net + the raised hamburger threshold carry the Safari no-overlap guarantee */
  }
  .site-header--editorial .primary-nav   { order: 2; display: block; flex: 1 1 auto; min-width: 0; }
  .site-header--editorial .header-actions {
    order: 3;
    display: flex;
    align-items: center;
    flex: 0 0 auto;                 /* utilities never shrink under the nav */
    margin-left: 0.75rem;           /* 2026-08 tighten: 12px inter-group gap (was 20) */
  }
  .site-header--editorial .header-actions > * + * { margin-left: 0.55rem; }

  /* Crest sizing (wordmark tracks it via --crest-h). MAXIMIZED logo: the bar adapts
     to the lockup (taller row), never the reverse — the tagline "From Silent
     Suffering to Collective Action" reads at a glance. Aspect preserved (width auto). */
  .site-header--editorial .brand { --crest-h: clamp(64px, 5.5vw, 88px); }

  /* Nav → single horizontal row (override the base 3-row grid nav). */
  .site-header--editorial .primary-nav > ul {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;      /* nav clusters by the utilities; slack stays beside the logo */
    flex-wrap: wrap;                /* STRUCTURAL OVERLAP GUARD: if content ever exceeds the column,
                                       items wrap BELOW (bar grows) instead of spilling left over the
                                       logo. Identical to nowrap wherever the row fits (all current
                                       widths/engines) — zero shift on correct platforms. */
    width: 100%;
    gap: 0;                         /* spacing via li margins below */
    padding: 0;
    border-top: 0;
  }
  .site-header--editorial .primary-nav > ul > li { margin: 0; }
  .site-header--editorial .primary-nav > ul > li + li { margin-left: clamp(0.35rem, 0.6vw, 0.6rem); }   /* 2026-08 menu-shrink: ~9.6px item gaps at 1920 (was 13.6) - measured trim; with the header width passes the one-line menu now survives down to the 1400px breakpoint */
  .site-header--editorial .primary-nav > ul a,
  .site-header--editorial .nav-menu__toggle {
    font-size: 0.95rem;             /* 2026-08 menu-shrink: 15.2px (was 1.05rem/16.8px) - deliberate, still >=15px for effortless legibility */
    font-weight: 600;
    padding: 0.5rem 0.3rem;         /* 2026-08 menu-shrink: 4.8px side padding (was 8.8) - hover is an opacity fade, no box to crowd */
    white-space: nowrap;
  }

  /* Utilities cluster = real flex items (override the base util-strip grid area). */
  .site-header--editorial .header-tools {
    display: flex;
    align-items: center;
    gap: 0;                         /* kill the legacy 0.7rem flex gap — spacing is the margins below */
    min-height: 0;
  }
  /* 2026-08 divider removal (client direction): both hairlines hidden via CSS
     only - the <span> elements stay in all 39 pages, so this reverses in one
     line. The 3.2px member gap was sized to sit beside a hairline; without
     one it read crowded, so the three controls now sit on a uniform 12px.
     NET: the cluster GROWS 9.2px vs the pre-divider state (12px gaps cost
     more than the 8.4px the hairlines freed) - flagged in the task report. */
  .site-header--editorial .header-tools .header-divider--tools { display: block; }   /* 2026-08 RESTORED (client direction, option 1): both hairlines back between search|language|account */
  .site-header--editorial .header-tools > * + * { margin-left: 7px; }   /* 7px each side of each divider - the gate-passing geometry (cluster 166.48, fit 1333 + 65 = 1398 <= 1400) */
  /* 2026-08 TRUE symmetry (supersedes the margin-nudge pass): instead of
     compensating per-control glyph insets with unequal margins, the three
     controls now share ONE inset geometry - search becomes a 44x44 box with
     its glyph centered (13px insets, matching the login button exactly; this
     also fixes its former 26px-wide sub-44 tap target), and the language
     pill's inner padding aligns to the same 13px. With uniform member
     margins, the gaps are now equal in BOTH senses - box gaps AND visible
     glyph gaps - so the icons + dividers read as one evenly-spaced set. */
  .site-header--editorial .header-search {
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
  }
  /* 2026-08 de-box (client direction): the language control drops its pill -
     no border, no radius, no side padding - leaving the bare globe + EN +
     caret glyph run (box 70.75px -> ~48.5px). The 44x44 tap target survives
     via the ::after overlay below, which consumes ZERO layout width. */
  .site-header--editorial .header-tools .lang-switcher__button {
    padding-left: 0;
    padding-right: 0;
    border: 0;
    border-radius: 0;
    position: relative;
  }
  .site-header--editorial .header-tools .lang-switcher__button::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);   /* centred 44x44 hit-area overlay */
  }
  /* With the pill border gone the control had only the UA default ring at
     desktop (the site's standard cluster ring lives in the mobile block).
     Explicit WHITE ring: var(--focus) is #3A2A66, tuned for light surfaces -
     it measures 1.18:1 on this purple header (invisible). White measures
     10.4:1 on the solid header and >=4.8:1 on every glass stage, and every
     desktop header state on all 39 pages is purple/dark (38 pinned-glass +
     the homepage's dark-hero floating state). */
  .site-header--editorial .header-tools .lang-switcher__button:focus-visible {
    outline: 3px solid #FFFFFF;
    outline-offset: 2px;
  }
  /* More air before the CTA: the Join button separates clearly from the
     icon cluster (was the uniform 8.8px). No divider there by design. */
  .site-header--editorial .header-join { margin-left: 0.75rem; }   /* 2026-08 option 1: 12px before the CTA (was 20) - the cluster sits grouped, close to the button */
  /* 2026-08 width pass: slimmer CTA sides, 18.4px -> 10.4px each (vertical
     unchanged). Scoped to the desktop ROW ONLY - the base .header-join padding
     stays for the drawer's full-width pill (drawer is scope-locked). */
  .site-header--editorial .header-actions .header-join { padding-left: 0.65rem; padding-right: 0.65rem; }
  /* NO hover decoration on the three utility icons (client direction) - and
     none existed as :hover rules (the constant drop-shadow is a static
     legibility filter, not a hover). These defensive resets guarantee the
     icons stay flat under the mouse; the keyboard focus-visible rings are
     preserved below/elsewhere. */
  .site-header--editorial .header-search:hover,
  .site-header--editorial .header-tools .lang-switcher__button:hover,
  .site-header--editorial .login-menu .header-signin:hover {
    background: none;
    box-shadow: none;
    transform: none;
    text-decoration: none;
  }
  /* Drop the desktop text "Sign in" and the trailing lang|sign-in divider. */
  .site-header--editorial .header-signin { display: none; }
  /* 2026-08: BOTH tool dividers show in the full-menu state — Search | Language
     | Login, evenly separated (the cluster's uniform 0.55rem margins give each
     divider identical spacing on both sides). No divider before Join — the CTA
     stands on its own. The old rule here hid the second divider back when the
     desktop sign-in link was dropped; the login icon has returned. */
  .site-header--editorial .header-tools .header-divider--tools:last-of-type { display: block; }   /* 2026-08 RESTORED with its sibling above - this 0,4,1 legacy selector must agree with the 0,3,0 rule or divider 2 diverges (it once hid divider 2 alone) */

  /* Small accents go bright violet (6.5:1 on the white header — AA). */
  .site-header--editorial .header-search,
  .site-header--editorial .header-tools .lang-switcher__button { color: var(--purple-bright); }

  .site-header--editorial .header-join { display: inline-flex; }   /* original size from the base .header-join rule */
}

/* (The desktop row begins at 1200px; below that the hamburger takes over. Between
   ~1200 and the row's natural width the flex-wrap net may drop trailing nav items
   to a 2nd line — acceptable, and structurally overlap-proof — rather than raising
   the threshold back up.) */
/* The CTA never wraps or shrinks — the nav gives way first. */
.header-join { flex-shrink: 0; }

/* --- Floating masthead (homepage only) -------------------------------------
   Fixed and transparent at the top of the page so the hero (wash + scrim +
   footage) runs edge-to-edge behind it; past ~80px of scroll (ui.js raises
   the is-scrolled threshold for this variant) it slides ~0.25s into the plum
   GLASS settled look (defined in §13) and shrinks ~17%, then eases back to
   transparent at the top. Inner pages carry .site-header--pinned and wear the
   same plum glass from the start. Header items stay WHITE in every settled
   state (see §13); at the top their contrast over the raw video is carried by
   the localized per-glyph shadows in §13 (the old top wash was removed). */
.site-header--floating {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
}
/* Background/border/blur for ALL scroll stages live in the three-stage block in
   §13 — Stage 1 (top) is a solid opaque bar, so there is no transparent state. */
@media (prefers-reduced-motion: reduce) {
  .site-header--editorial { transition: none; }  /* instant stage swap is fine */
}

/* =======================  Editorial hero  ======================= */
/* Full-viewport statement from the very top of the viewport: the floating
   masthead is position:fixed (out of flow), so the hero itself compensates by
   running a full 100svh — nothing hides behind the header and nothing jumps
   on load. svh keeps mobile browser chrome from over-growing it; the vh line
   is the no-svh fallback. Top padding clears the fixed header band. */
/* Full viewport height so the looping footage owns the entire first screen; the
   Evidence card then tucks only a small lip over the very bottom (see the
   overlap block). svh keeps mobile browser chrome from over-growing it; the vh
   line is the no-svh fallback. Top padding clears the fixed header band. */
.hero--editorial {
  /* Cinematic column layout: the title/subtitle sit in the UPPER third; the four
     gateway doorways sit as a full-width row in the LOWER hero, aligned to the
     evidence 4-column grid below. align-items:stretch makes the container fill the
     hero height for the top/bottom split. The doorways END WITHIN the hero (no
     overflow onto the evidence), so overflow stays hidden (from base .hero) — no
     shadow or halo can bleed onto the light section. padding-top clears the nav. */
  align-items: stretch;
  min-height: 100vh;                         /* fallback chain: vh -> dvh -> svh (svh wins: the */
  min-height: 100dvh;                        /* SMALL viewport height, so with the mobile toolbar */
  min-height: 100svh;                        /* visible nothing — panels or chevron — is clipped) */
  padding-top: calc(var(--header-h, 6rem) + clamp(0.75rem, 2vh, 1.75rem));
  /* NO fade at the bottom: the full-rich video runs edge-to-edge and meets the
     evidence band with a clean, crisp horizontal edge. padding-bottom gives the
     doorways comfortable breathing room below, with the chevron slotted beneath
     them over rich video near the bottom edge. */
  padding-bottom: clamp(4.25rem, 8vh, 5.5rem);
}

/* (The old light lavender scrim lived here; the cinematic dark scrim in
   section 12 now owns .hero--editorial::after at every width — the pseudo
   element's structural props come from the base .hero::after rule.) */

/* (REMOVED — client direction: the top strip that darkened the header band
   over the video (a 0.72→0 rgba(20,14,40) gradient on .hero--editorial::before)
   is gone, so the transparent header blends COMPLETELY into the raw footage at
   the top state. White logo/nav legibility over bright frames is now carried by
   LOCALIZED aids only — the per-glyph text/drop shadows in §13 plus a soft
   drop-shadow on the white logo — never a tint spread across the video.) */

/* Nudge the (still left-aligned) copy rightward so it sits comfortably in the
   frame instead of hugging the far-left edge. The offset scales down on phones
   and stays modest so the text never leaves the dark scrim zone (strongest
   0-55% of the hero width) — AA holds over every video frame. */
.hero--editorial .hero__intro {
  max-width: 42rem;
  padding-left: clamp(0.5rem, 4vw, 3.5rem);
  display: flex;
  flex-direction: column;
  flex: 1;                                   /* fill the container so the bridge can sit at the bottom */
  padding-top: clamp(0.5rem, 8vh, 5rem);     /* cinematic: drop the title/subtitle into the upper third */
}
/* Bridge wrapper: pushes the panel to the hero's bottom, then overlaps it ~18-20%
   past the edge onto the evidence top. The WRAPPER carries the overlap transform,
   so the panel's own entrance-reveal transform (heroRise) is undisturbed. */
.hero--editorial .hero__bridge {
  margin-top: auto;                          /* push the doorways into the lower hero */
  width: 100%;                               /* full container width — the doorways align to the evidence grid */
}
@media (max-width: 559.98px) {
  .hero--editorial .hero__intro { padding-top: clamp(0.5rem, 4vh, 2rem); }
}

/* Headline — large Lora, three staged lines, deep purple over the light scrim
   (headings stay --purple/--purple-deep on light surfaces); the last line is
   italic --purple-bright — the lively accent of the brightened palette. At
   headline sizes the accent needs 3:1 (large text) and holds ≥4.5:1 over the
   scrim's worst-case frame. No text-shadow: dark-on-light needs none. */
.hero--editorial .hero__headline {
  margin: 0;
  max-width: 20ch;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  /* Cap at 4.6rem (was 5rem): with the scrim now fully transparent at ~55%,
     the longest line ("no woman suffers") must end by ~51% of the hero width
     at wide viewports to stay inside the scrim + glow protection. */
  font-size: clamp(2.6rem, 6.2vw, 4.6rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--purple-deep);
  text-shadow: none;               /* cancel the base .hero h1 white-copy shadow */
}
.hero--editorial .hero__line { display: block; }
.hero--editorial .hero__line--accent { color: var(--purple-bright); }
.hero--editorial .hero__line--accent em { font-style: italic; }

/* Subtitle — brand-gold line under the big serif. The dark hero now runs at
   every width, so canonical --gold applies everywhere; section 12 layers the
   strong text-shadow that carries it over the footage's bright moments. */
/* Subtitle — now TWO stacked lines, in the closing CTA heading's font
   (.closing-band__quote = --font-head / Lora, italic, weight 500). Matched
   family/weight/style exactly; colour is white (not the CTA's purple-deep,
   which is for light surfaces) so it stays AA on the dark hero scrim — §12
   adds the layered shadow. Size sits clearly below the H1, above body. */
.hero--editorial .hero__subtitle {
  margin: 0.7rem 0 1.35rem;
  max-width: 46ch;
  font-family: var(--font-head);             /* Lora — matches the closing CTA heading */
  font-style: italic;                        /* matches the CTA heading */
  font-weight: 500;                          /* matches the CTA heading */
  font-size: clamp(1.2rem, 2.2vw, 1.6rem);   /* subtitle scale: below the H1, above body */
  line-height: 1.4;
  color: var(--white);
  text-shadow: none;
}
.hero--editorial .hero__subtitle-line { display: block; }

/* Button — a single CTA since identity selection moved to the Gateway page
   (the old two-button flex-wrap/gap layout is gone with it). The wrapper stays
   because it is the entrance choreography's animation target. */
.hero--editorial .hero__actions {
  display: flex;
  flex-wrap: wrap;                 /* row on desktop; wraps to a 2nd row rather than overflowing */
  gap: 0.6rem;
  margin: 0;
  max-width: 40rem;                /* stays inside the left scrim, clear of the video's right-side subjects */
}
/* Four gateway persona buttons. Patient = primary (--purple-bright fill, white
   label 6.5:1 on the opaque fill). The other three = on-dark OUTLINE (white
   border + white label, transparent) with a soft shadow for AA over the footage.
   Base .btn carries shape/padding; here we floor the 44px tap target + centre. */
.hero--editorial .hero__persona {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  text-align: center;
}
.hero--editorial .hero__persona--outline {
  background: transparent;
  color: var(--white);
  border-color: rgba(255, 255, 255, 0.7);
  text-shadow: 0 1px 3px rgba(20, 14, 40, 0.6);   /* keeps the white label AA over brighter video frames */
}
.hero--editorial .hero__persona--outline:hover,
.hero--editorial .hero__persona--outline:focus-visible {
  background: rgba(255, 255, 255, 0.14);
  border-color: var(--white);
  color: var(--white);
}
/* One step larger than the base .btn (0.85rem/1.4rem, 1rem type) so the lone
   CTA reads as the confident primary action — ~54px tall, still in proportion.
   White on --purple-bright stays 6.5:1 (opaque fill) over every video frame. */
.hero--editorial .hero__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1.05rem 1.9rem;
  font-size: 1.1rem;
}
.hero--editorial .hero__cta-arrow { margin-left: 0.55rem; transition: transform 0.18s ease; }   /* label↔arrow space via margin, not flex gap (Safari <14.1) */
.hero--editorial .hero__cta:hover .hero__cta-arrow { transform: translateX(3px); }
.hero--editorial .hero__cta:focus-visible .hero__cta-arrow { transform: translateX(3px); }

/* Solid violet lifts gently off the footage. White on --purple-bright is
   6.5:1 and the fill is opaque, so the CTA holds AA over every video frame
   regardless of what the scrim is doing behind it. */
.hero--editorial .btn--primary { box-shadow: 0 6px 18px rgba(58, 42, 102, 0.20); }

/* Phone: the lone CTA goes full-width — a bigger, easier target than a
   left-hugging pill, and it never wraps at 375px. */
@media (max-width: 559.98px) {
  .hero--editorial .hero__actions { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
  .hero--editorial .hero__persona { width: 100%; }   /* full-width stacked targets, never wrap at 375px */
}

/* --- Hero "four doorways" frosted-glass panel (replaces the persona pills) -----
   ONE continuous frosted object split into four columns by faint 1px hairline
   dividers: the panel itself is a hairline-coloured grid whose 1px gaps show
   between the four frosted cells, so dividers appear only BETWEEN doorways (never
   on the outer edges) and re-flow automatically at 4-up / 2x2 / 1-up. Each cell
   blurs the sunrise video behind it (nav-frost token ~#4B2E83); a solid rgba is
   the @supports fallback. White copy over the dark frost + §12 scrim stays WCAG
   AA even over the video's brightest frames. */
.hero__doorways {
  position: relative;
  z-index: 3;                                   /* above the hero scrim/overlay */
  display: grid;
  /* 2026-08 three-doorway rebalance (Collaborate panel removed): each panel
     KEEPS its exact former width - minmax(0, 246px) is the same 246px the old
     4-col/1fr grid computed inside the 1080px container - and the freed room
     becomes breathing space: gap 32px -> 48px (1.5x), group centred. The old
     1:1 column alignment with the four evidence stats below no longer applies
     by design. */
  grid-template-columns: repeat(3, minmax(0, 246px));
  justify-content: center;
  gap: 48px;
  width: 100%;
  margin: 0;
  /* NO panel: no background box, border, radius, mask or shadow. The doorways sit
     directly over the video, on the same .container + grid as the evidence stats
     below, so the four doorways line up column-for-column above the four stats.
     Legibility comes from a soft feathered per-column scrim on each .doorway + faint
     hairline dividers (below); nothing here casts a shape or bleeds onto the light
     evidence section. */
}
.doorway {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;                       /* centre content so the scrim + feather sit symmetrically around it */
  text-align: center;
  gap: 0.4rem;
  padding: clamp(0.9rem, 1.8vw, 1.25rem) clamp(0.65rem, 1.3vw, 1rem);   /* gentle trim: ~15% less vertical padding (fonts/icons untouched — legibility first) */
  min-height: 44px;                              /* tap target floor */
  text-decoration: none;
  color: var(--white);
  border-left: 1px solid rgba(255, 255, 255, 0.14);   /* faint hairline divider between columns (kept) */
  background: transparent;                             /* the frosted glass lives on ::before (below) */
  transition: transform 0.2s ease;
}
/* WATERY glass pane behind the icon + labels — the HEADER'S material, exactly
   (client direction): the same near-transparent light-purple tint the scrolled
   header uses (--glass-bg-header, tokens.css — the ONE shared token, so header
   + panels stay in sync), and NO backdrop-filter, matching the header (its
   blur was removed long ago). WHY no blur: backdrop-filter renders heavier /
   less transparent on Apple engines (iOS/macOS Safari) than on Chrome — the
   cross-device inconsistency the client saw. A flat translucent tint
   composites IDENTICALLY on Chrome, Android, Windows, Apple and the WeChat
   webview. The old frost (+ its @supports blur block and edge-feather mask)
   is retired — restore from history if the frosted look ever returns. Text AA
   over the now-lighter pane is carried by the per-glyph halos below, exactly
   like the header's white nav text. */
.doorway::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 0;
  background: var(--glass-bg-header);
}
.doorway__icon, .doorway__text { position: relative; z-index: 1; }   /* content sits above the glass pane */
.doorway:first-child { border-left-color: transparent; }   /* no divider on the outer-left edge */
.doorway:hover { transform: translateY(-2px); }             /* gentle lift on hover — no box, no shadow */
.doorway:focus-visible { outline: 3px solid var(--gold); outline-offset: -3px; }   /* inset gold ring */
.doorway__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: clamp(40px, 4.6vw, 46px);               /* Phase 4: scaled down with the panel */
  height: clamp(40px, 4.6vw, 46px);
  border-radius: 50%;
  color: var(--white);
}
.doorway__icon svg { width: 52%; height: 52%; }
/* Circle accent colours — approved in-brand palette (glyph stays white). */
.doorway--help .doorway__icon     { background: #C77B6B; }   /* Rose-Clay */
.doorway--pro .doorway__icon      { background: #3A2A66; }   /* Purple */
.doorway--advocate .doorway__icon { background: #BB863F; }   /* Gold */
.doorway--collab .doorway__icon   { background: #5E8B7E; }   /* Sage-Teal */
/* ONE frosted layer per panel: the text wrapper carries NO background of its own —
   no inner box, no darker container. Icon + heading + description all sit directly on
   the single light frosted pane (.doorway::before). AA over bright frames comes from
   the strengthened text-shadows below, never a second fill. */
.doorway__text {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  align-items: center;
}
.doorway__heading {
  font-family: var(--font-head);                 /* Lora serif */
  font-weight: 600;
  font-size: clamp(0.84rem, 1.2vw, 0.98rem);     /* Phase 4: scaled down with the panel; labels still 1-2 lines */
  line-height: 1.25;
  color: var(--white);
  text-wrap: balance;
  /* Strengthened glyph halo (tight edge + double diffuse) — the shadow alone
     carries AA over the brightest video frame. Stepped up slightly when the
     pane tint lightened 0.30 -> 0.14 (header material, no blur): full-opacity
     edge + denser, wider diffuse rings. */
  text-shadow: 0 1px 2px rgba(20, 14, 40, 1), 0 1px 7px rgba(20, 14, 40, 0.9), 0 2px 16px rgba(20, 14, 40, 0.68);
}
.doorway__sub {
  font-size: clamp(0.74rem, 1.05vw, 0.82rem);    /* Phase 4: scaled down with the panel */
  font-weight: 500;                              /* a step up from 400 — crisper strokes over bright frames (no inner box) */
  line-height: 1.4;
  color: var(--white);                           /* full white (was 0.96 alpha) for maximum contrast */
  text-shadow: 0 1px 2px rgba(20, 14, 40, 1), 0 1px 6px rgba(20, 14, 40, 0.9), 0 2px 14px rgba(20, 14, 40, 0.68);   /* stepped up with the lighter pane, same as the heading halo */
}
@media (prefers-reduced-motion: reduce) {
  .doorway { transition: none; }
  .doorway:hover { transform: none; }
}
/* Tablet: 2x2 — MATCHES the evidence stats' 2-col reflow (same <=899.98px break) so
   the doorways stay column-aligned with the stats. The divider now sits between the
   two columns of each row (2nd + 4th keep it; 3rd becomes an outer-left, no line). */
@media (max-width: 899.98px) {
  /* 2026-08 three-panel reflow: the old 2x2 grid would strand one panel alone
     on its own row with three items - single column instead (the phone
     pattern, no orphans); the nth-child(3) divider fix died with the 2x2. */
  .hero__doorways { grid-template-columns: 1fr; }
  .doorway { border-left-color: transparent; }
}
/* Mobile: 1 column — MATCHES the stats' single-column stacking; no vertical dividers. */
@media (max-width: 479.98px) {
  .hero__doorways { grid-template-columns: 1fr; }
  .doorway { border-left-color: transparent; }
}

/* Mobile hero sizing: the video now plays on phones too (section 12 carries
   the phone scrim + framing); reduced-motion/data-saver phones see the still
   under the same dark treatment. */
@media (max-width: 759px) {
  /* Phones keep the same cinematic ~90vh (inherited from the base rule; min-height
     only grows — the stacked 1-col doorways may exceed it naturally, never clipped). */
  .hero--editorial .hero__headline { font-size: clamp(2.35rem, 10.5vw, 3.4rem); }
}

/* PHONES ONLY — crop position: the walking women are on the RIGHT of the 16:9 frame,
   and object-fit: cover's default CENTER crop cuts them off on narrow screens. Shift
   the visible window right (75% keeps a little left context vs. a hard `right`).
   Applies to BOTH stacked <video> layers (A + the loop clone share .hero__video),
   the <video poster> (object-position covers it), and the .hero background-image
   still (the reduced-motion / no-video fallback) — so poster and playing video frame
   identically. Tablet/desktop keep their current centered crop, untouched. */
@media (max-width: 639.98px) {
  .hero--editorial .hero__video { object-position: 75% center; }
  .hero--editorial { background-position: 75% center; }
}

/* --- Entrance choreography (JS-driven, strict order) ------------------------
   Over the frozen solitude still, ui.js reveals a) the title (in from the LEFT),
   b) then the subtitle, c) then the doorway bar — each on its own timer
   (HERO_TITLE_IN_MS / HERO_SUBTITLE_IN_MS / HERO_PANELS_IN_MS) so the stagger is
   tunable. The classes are never removed, so the content stays for every video loop.
   Before the reveal the items are hidden so the opening reads first; if autoplay is
   blocked or motion is reduced, ui.js reveals them at once. The opacity:0 hold is gated
   behind html.js (no-JS always sees the text) and lives inside no-preference so
   reduced-motion never hides it. */
@media (prefers-reduced-motion: no-preference) {
  .js .hero--editorial .hero__line,
  .js .hero--editorial .hero__subtitle,
  .js .hero--editorial .hero__doorways {
    opacity: 0;
  }
  /* a) title — in from the LEFT */
  .hero--editorial.is-revealed .hero__line {
    animation: heroRise 0.85s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
  /* b) subtitle — follows, same left entrance */
  .hero--editorial.subtitle-in .hero__subtitle {
    animation: heroRise 0.85s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
  /* c) the four doorway panels — gentle rise; duration via --hero-panel-fade-ms */
  .hero--editorial.panel-in .hero__doorways {
    animation: heroPanelIn var(--hero-panel-fade-ms, 900ms) cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
}
@keyframes heroRise {
  from { opacity: 0; transform: translate3d(-1.4rem, 0, 0); }   /* in from the LEFT */
  to   { opacity: 1; transform: none; }
}
@keyframes heroPanelIn {
  from { opacity: 0; transform: translateY(0.8rem); }
  to   { opacity: 1; transform: none; }
}


/* --- The Evidence — floating card (unboxed, hairline-divided figures) -------
   Three large Lora figures + short Inter lines on cream, split by the stats
   strip's hairline (vertical between columns >=760px, horizontal when stacked)
   — no cards. AA on cream: figures --purple ~11:1, lines --text-warm ~8.6:1,
   heading --purple-deep ~12:1, gold eyebrow (#8A6128) 5.1:1, link 6.1:1. */
/* Floating card: the section itself is transparent (the page is white behind
   it) and the cream now sits in a contained, rounded card inside the container
   — so it lifts gently off the page. Internals (typography, hairline dividers,
   the "See the evidence" link) are unchanged. */
/* Quiet transition line between the hero and the evidence — a soft breath, not
   a heading or a band. Serif italic (matches the closing CTA heading
   .closing-band__quote, the calmer of the two heading treatments); deep purple
   on the light page (~14:1, AA); generous breathing room. Static — the site has
   no generic section fade-in to reuse, so no animation is invented. */
.hero-bridge {
  position: relative;
  z-index: 4;                        /* above the evidence card that lifts toward it */
  max-width: 54rem;
  margin: 0 auto;
  padding-top: clamp(2.75rem, 6vw, 4.25rem);
  padding-bottom: clamp(2.5rem, 6vw, 3.5rem);
  padding-inline: 1.25rem;
  text-align: center;
  font-family: var(--font-head);     /* Lora — same serif family as the hero title + CTA heading */
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.35rem, 2.6vw, 1.9rem);   /* larger than body, well below the hero H1 */
  line-height: 1.4;
  color: var(--purple-deep);
  text-wrap: balance;                /* graceful wrap — one line on desktop, at most two on mobile */
}
@media (min-width: 768px) {
  /* The evidence card lifts -72px toward this line; a taller bottom pad keeps
     that lift in empty whitespace, well clear of the sentence. */
  .hero-bridge { padding-bottom: clamp(6.5rem, 8vw, 8rem); }
}

.why-gem { background: transparent; }
/* Thin horizontal stat bar (was a cream card): a slim hairline-delimited band,
   NOT a box. Transparent, slim padding; the four stats sit in a row, the Explore
   button pinned to the lower-right. (border-top/bottom longhand, not border-block
   — Safari <14.1.) */
.why-gem__card {
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  border-top: 1px solid rgba(58, 42, 102, 0.16);
  border-bottom: 1px solid rgba(58, 42, 102, 0.16);
  padding: clamp(1rem, 2.4vw, 1.5rem) 0;
  display: flex;
  flex-direction: column;
  gap: clamp(0.6rem, 1.6vw, 1rem);
}
/* Counting numbers: tabular digits inside a width reserved by ui.js (in ch,
   from the final value) so running digits never shift or jitter the layout. */
.why-gem__num {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.why-gem__heading {
  margin: 0.4rem 0 0;
  max-width: 22ch;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1.2;
  color: var(--purple-deep);
}
.why-gem__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);     /* mobile: 2x2 */
}
.why-gem__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.6rem 0.85rem;
  text-align: center;
}
.why-gem__figure {
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.35rem, 4vw, 2rem);      /* sized so four figures sit across */
  line-height: 1.15;
  color: var(--purple);
}
/* Placeholder figure: a deliberate, honest stand-in — a small gold SAMPLE pill
   over a muted "pending" line — so it never reads as a real figure or a broken
   token. When GEM confirms the real figure, drop this modifier so it matches the
   others. */
.why-gem__figure--placeholder {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
  font-size: 1rem;                           /* not the big Lora number scale */
}
.why-gem__sample {
  font-family: var(--font-body);             /* Inter */
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1.4;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--gold);                    /* #BB863F pill */
  color: var(--purple-deep);                 /* deep-purple ink on gold ≈ 4.55:1 = AA */
}
.why-gem__pending {
  font-family: var(--font-body);             /* Inter, not the Lora figure */
  font-weight: 500;
  font-size: clamp(0.9rem, 2.2vw, 1.05rem);
  line-height: 1.3;
  color: var(--text-muted);                  /* muted — clearly pending, not a stat */
}
.why-gem__text {
  max-width: 34ch;
  font-size: clamp(0.85rem, 2.2vw, 0.95rem);
  line-height: 1.55;
  color: var(--text-warm);
}
.why-gem__more { margin: 0; align-self: flex-end; }   /* Explore button at the bar's lower-right */
/* 2x2 (below 760px): hairlines run vertically between the columns and
   horizontally between the rows; outer edges stay flush with the card padding. */
@media (max-width: 759.98px) {
  .why-gem__grid li:nth-child(2n) { border-left: 1px solid rgba(58, 42, 102, 0.16); }
  .why-gem__grid li:nth-child(n + 3) { border-top: 1px solid rgba(58, 42, 102, 0.16); }
  .why-gem__grid li:nth-child(2n + 1) .why-gem__item { padding-left: 0; }
  .why-gem__grid li:nth-child(2n) .why-gem__item { padding-right: 0; }
}
/* Four across from 760px: vertical hairlines only. */
@media (min-width: 760px) {
  .why-gem__grid { grid-template-columns: repeat(4, 1fr); }
  .why-gem__grid li + li { border-left: 1px solid rgba(58, 42, 102, 0.16); }
  .why-gem__item { padding: 0.25rem clamp(0.85rem, 1.9vw, 1.5rem); }
  .why-gem__grid li:first-child .why-gem__item { padding-left: 0; }
  .why-gem__grid li:last-child .why-gem__item { padding-right: 0; }
}
/* Phones: tighter side inset and a smaller radius so the card keeps its
   breathing room instead of feeling cramped. (The figures already stack here,
   with the hairlines running horizontally between them.) */
@media (max-width: 559.98px) {
  .why-gem > .container { padding-inline: 0.9rem; }
}

/* --- Meet our experts — full row: Chairman card + coming-soon placeholders ---
   A row of equal-height, equal-style cards: card 1 is the real Founding Chairman
   (approved photo, verbatim details); cards 2-3 are intentional "coming soon"
   placeholders (a soft lavender circle with a light brand-purple person
   silhouette — never a fake photo). 1 per row on phones, 3 across from tablet
   up. One muted honest
   line sits below. AA on white: eyebrow --gold-deep ~5.4:1, name --purple-deep
   ~14:1, credentials/coming-soon --text-muted ~7:1, note --text-warm ~8.6:1. */
/* Step 13: MEDIUM band — clearly shorter than the TALL Featured above so the two read
   as peak -> settle (padding only; the experts grid/content is untouched). */
.meet-experts { padding-block: clamp(2.75rem, 5.5vw, 4rem); }
.meet-experts__heading {
  margin: 0.4rem 0 clamp(1.5rem, 3.5vw, 2.25rem);
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.2;
  color: var(--purple-deep);
}
.meet-experts__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;                /* phone: 1 per row */
  gap: clamp(0.9rem, 2vw, 1.25rem);
}
.meet-experts__grid > li { display: flex; }  /* cards stretch to a shared row height */
@media (min-width: 620px) {
  .meet-experts__grid { grid-template-columns: repeat(3, 1fr); }   /* tablet+desktop: 3 advisors across (Step 10) */
}
.expert-card {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.15rem;
  padding: clamp(1.35rem, 3vw, 1.75rem) clamp(1rem, 2.5vw, 1.35rem);
  background: var(--white);
  border: 1px solid var(--lavender);
  border-radius: var(--radius);
  box-shadow: 0 2px 10px rgba(46, 33, 80, 0.08);
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.22s ease;
}
/* 2026-08: the hover lift is now scoped to the LINKED card only (the
   Chairman's, an <a>) - the two "coming soon" placeholder <article>s no
   longer receive it, so nothing non-interactive reads as clickable. The link
   resets keep the card's own type colours (no browser blue/underline). */
a.expert-card { text-decoration: none; color: inherit; cursor: pointer; }
.expert-card--link:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.16);
}
.expert-card--link:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 3px; }   /* NOT the raw --focus token */
.expert-card__media {
  flex: 0 0 auto;
  width: clamp(84px, 20vw, 104px);
  height: clamp(84px, 20vw, 104px);
  margin-bottom: 0.65rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--lavender-light);         /* #F7F4FB — soft placeholder circle */
}
.expert-card__photo { width: 100%; height: 100%; object-fit: cover; display: block; }
.expert-card__media--mark {
  display: grid;
  place-items: center;
  color: var(--purple);                      /* #3A2A66 light person silhouette — a tasteful placeholder, not a real photo */
}
.expert-card__media--mark svg { width: 38%; height: 38%; display: block; }
.expert-card__eyebrow {
  margin: 0;
  font-family: var(--font-body);             /* Inter */
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--gold-deep);                   /* deep gold on white — AA at label size */
}
.expert-card__name {
  margin: 0.15rem 0 0;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.25;
  color: var(--purple-deep);
}
.expert-card__name--muted { color: var(--text-muted); font-weight: 500; }   /* "Profile coming soon" — calm, not a name */
.expert-card__cred {
  margin: 0.25rem 0 0;
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text-muted);
}
.meet-experts__note {
  margin: clamp(1.25rem, 3vw, 1.75rem) 0 0;
  max-width: 52ch;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--text-warm);
}
.meet-experts__cta { margin: clamp(1.5rem, 3vw, 2rem) 0 0; text-align: right; max-width: none; }   /* 2026-08: quiet link sits FAR RIGHT, on the card row's right edge (max-width:none defeats the base p cap so right-align reaches the container edge) */
/* Demoted (2026-08): same quiet arrow-link treatment as the footer Join link. */
.meet-experts__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.2rem 0.1rem;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--purple);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.18s ease;
}
.meet-experts__link:hover { color: var(--purple-bright); }
.meet-experts__link:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 6px; }
@media (max-width: 639.98px) {
  .meet-experts__cta { text-align: left; }            /* phones: tidy left alignment */
}

/* --- Gateway page: persona routing (premium "choose your path") -------------
   A soft dawn hero over four editorial image-cards. Cards mirror the homepage
   Featured treatment: the photo fills the card, a bottom-weighted purple veil
   carries white copy, an icon badge sits top-left, and the primary button (the
   card's link) is pinned to the foot. Stacked on phones, 2x2 on tablet, four
   across on wide screens. AA: hero --purple-deep on dawn ~12:1, accent
   --purple-bright ~6:1; on cards, white title/desc sit in the >=0.86 veil zone
   (~7:1) and the violet button is 6.5:1. */
.gateway-scene { position: relative; }
.gateway-hero {
  position: relative;
  text-align: center;
  padding-top: clamp(3.25rem, 7vw, 5.25rem);         /* more room between header and heading */
  padding-bottom: clamp(3rem, 6.5vw, 4.75rem);       /* phone: no overlap, modest sky band */
  /* Daylight lavender field (mobile, 2026-08: replaced the dusk sunrise sky;
     the -mobile variant is 1080x720 so phones never download the 1920px
     file). The sky sits behind the hero only and fades to white at its foot,
     so the cards below stack cleanly on white.
     (On tablet/desktop this background is removed and moved onto
     .gateway-scene so it spans the full card row — see the 768px block.) */
  /* 2026-08: NO wash over the photograph at all - heading, subtitle and
     accent clear 5.0:1+ on the raw image, darkest sub-regions included. The
     only gradient left is the FOOT FADE (86-100%): the hero's bottom rows
     are lavender field and this hands them off to the white cards section
     below - a layout blend under no text, not a wash. The lede (the one
     element the raw photo fails, 2.56:1 at its darkest clumps) gets a
     LOCALISED plate on the element itself - see the media block after
     .gateway-hero__lede. */
  background-image:
    linear-gradient(180deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, 0) 86%,
      rgba(255, 255, 255, 0.97) 100%),
    url("../img/gateway/gateway-sunrise-mobile.webp");   /* 2026-08: sunrise swap (was gateway-lavender-mobile) */
  background-size: cover;
  background-position: center top;                    /* smooth sky up top, field lower */
  background-repeat: no-repeat;
}
.gateway-hero__title {
  margin: 0 auto;                            /* truly centred within the container */
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.9rem, 4.6vw, 3rem);
  line-height: 1.15;
  color: var(--purple-deep);
  text-wrap: balance;
}
.gateway-hero__subtitle {
  margin: 1rem auto 0;                       /* auto keeps it centred, not left-boxed by the inherited p max-width */
  max-width: 46ch;
  font-size: clamp(1.15rem, 2.6vw, 1.5rem);
  line-height: 1.35;
  color: var(--purple-deep);
}
.gateway-hero__accent { color: var(--purple-bright); font-weight: 600; }
.gateway-hero__divider {
  display: block;
  width: 56px;
  height: 3px;
  margin: 1.4rem auto 0;
  border-radius: 2px;
  background: var(--gold);
}
.gateway-hero__lede {
  margin: 1.4rem auto 0;
  max-width: 58ch;
  font-size: clamp(1rem, 2vw, 1.1rem);
  line-height: 1.6;
  color: var(--text);   /* 2026-08: was --text-warm, a borderline 4.44:1 over the old mobile mountain band */
}
/* The lede's plate is now UNIVERSAL (2026-08, sunrise image): body text
   needs 4.5:1 and neither dark (3.02 avg as white... inverted: white lede
   measures 3.02, purple 4.60/4.07 worst) nor any bare colour clears it on
   the mid-tone sky, so the dark lede keeps its translucent plate at every
   width - measured 9.9:1+ over the plate on the brightest sky patches. */
.gateway-hero__lede {
  background: rgba(246, 243, 251, 0.72);
  border-radius: 12px;
  padding: 0.55rem 0.9rem;
}
/* LIGHT hero text from 768px on the sunrise sky (2026-08: purple-deep
   measured 2.75 worst-patch on the heading and 1.96 on the accent there).
   White heading/subtitle pass large-text AA on the average sky; their
   brightest patches are shadow-carried - the closing statement's exact
   precedent and treatment. The accent is VERY pale gold so it still reads
   as an accent beside the white lines. Below 768px the pale mobile sky
   inverts the math: purple stays (white would measure ~2.9 there). */
@media (min-width: 768px) {
  .gateway-hero__title,
  .gateway-hero__subtitle {
    color: var(--white);
    text-shadow: 0 1px 2px rgba(46, 33, 80, 0.45), 0 2px 14px rgba(46, 33, 80, 0.30);
  }
  .gateway-hero__accent {
    color: #F7E8C4;
    text-shadow: 0 1px 2px rgba(46, 33, 80, 0.45), 0 2px 14px rgba(46, 33, 80, 0.30);
  }
}
.gateway__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;                /* phone: stacked */
  gap: 1.1rem;
}
.gateway__grid > li { display: flex; }       /* cards share a row height */

/* Per-card brand accents — warm (gold) / cool (purple) alternation. Only the
   icon circle + the button take these; titles, bottom gradient and hover-lift
   are shared. Retune a card by editing its three vars here (no repeated
   literals). Each --*-accent-hover is a slightly darker shade of that card's
   own accent, used on button hover. */
.gateway__grid {
  --card1-accent: var(--gold);          --card1-ink: var(--purple-deep); --card1-accent-hover: #B07E3A;  /* Patient — gold / deep-purple */
  --card2-accent: var(--purple-bright); --card2-ink: var(--white);       --card2-accent-hover: #5A4189;  /* Professional — purple-bright / white */
  --card3-accent: var(--gold);          --card3-ink: var(--purple-deep); --card3-accent-hover: #B07E3A;  /* Advocate — gold / deep-purple */
  --card4-accent: var(--purple-deep);   --card4-ink: var(--white);       --card4-accent-hover: #211840;  /* Partner — deep-purple / white */
}
.gateway__grid > li:nth-child(1) .gateway-card { --accent: var(--card1-accent); --ink: var(--card1-ink); --accent-hover: var(--card1-accent-hover); }
.gateway__grid > li:nth-child(2) .gateway-card { --accent: var(--card2-accent); --ink: var(--card2-ink); --accent-hover: var(--card2-accent-hover); }
.gateway__grid > li:nth-child(3) .gateway-card { --accent: var(--card3-accent); --ink: var(--card3-ink); --accent-hover: var(--card3-accent-hover); }
.gateway__grid > li:nth-child(4) .gateway-card { --accent: var(--card4-accent); --ink: var(--card4-ink); --accent-hover: var(--card4-accent-hover); }   /* matches nothing while the Collaborate card is commented out (Aug 2026) — retained for restore; cards 1-3 are position-stable */
.gateway-card {
  position: relative;
  flex: 1;
  overflow: hidden;
  isolation: isolate;
  border-radius: var(--radius);
  aspect-ratio: 4 / 5;
  background: var(--purple-deep);
  box-shadow: 0 2px 10px rgba(46, 33, 80, 0.10);
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.22s ease;
}
.gateway-card:hover,
.gateway-card:focus-within {
  transform: translateY(-4px);
  box-shadow: 0 14px 30px rgba(46, 33, 80, 0.24);
}
.gateway-card__img {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
/* Per-card framing (files are not re-cropped; we shift the visible window). */
.gateway-card__img--left  { object-position: 25% center; }  /* woman sits far left of frame */
.gateway-card__img--right { object-position: 78% center; }  /* doctor sits far right of frame */
.gateway-card::before {                      /* deep-purple veil, heavier at foot */
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 1;
  /* 2026-08: foot stops softened 0.86->0.62 / 0.96->0.78 (the old values
     converged on near-solid #2E2150 across the lower 40% - a heavy band).
     FLAT LAYER (2026-08, second pass): the purple tint became a NEUTRAL
     darkening - rgba(20,20,20,.15) - after a measured three-way trial
     (gold rgba(187,134,63,.14) and lavender rgba(183,170,220,.20) both
     dropped card 2's title to 4.49/4.44 at 1440px): each photograph keeps
     its own colour, and every title/description stays >=5.05 worst-region
     at 390 and 1440. The bottom gradient is unchanged - it carries the
     text. */
  background-image:
    linear-gradient(180deg, rgba(46, 33, 80, 0.12) 0%, rgba(46, 33, 80, 0.42) 40%, rgba(46, 33, 80, 0.62) 72%, rgba(46, 33, 80, 0.78) 100%),
    linear-gradient(rgba(20, 20, 20, 0.15), rgba(20, 20, 20, 0.15));
}
.gateway-card__icon {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: var(--accent);            /* per-card accent (icon circle) */
  color: var(--ink);                   /* per-card glyph ink */
}
.gateway-card__icon svg { width: 22px; height: 22px; display: block; }
.gateway-card__body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  padding: clamp(1.1rem, 2.6vw, 1.4rem);
}
/* Alignment: reserve 2 lines for the title (bottom-aligned so 1- and 2-line
   titles share a baseline) and 2 lines for the description, so titles, descs and
   buttons sit at the same vertical positions across all four cards. The button
   is full-width and pinned to the card foot on one line — a crisp, even row. */
.gateway-card__title {
  margin: 0;
  min-height: 2.4em;                         /* 2 lines at line-height 1.2 */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;                 /* bottom-align: 1-line titles sit snug above the description */
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.25rem, 2.4vw, 1.5rem);
  line-height: 1.2;
  color: var(--white);
}
.gateway-card__desc {
  margin: 0.4rem 0 0;
  min-height: 2.9em;                         /* 2 lines at line-height 1.45 */
  font-size: 0.93rem;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.92);
}
/* Scoped to .gateway-card so the per-card accent beats the base .btn--primary
   colours (which the markup keeps for shape/padding). */
.gateway-card .gateway-card__btn {
  margin-top: 0.9rem;
  align-self: stretch;                 /* full width → uniform, crisp; pinned to the card foot */
  justify-content: center;
  white-space: nowrap;                 /* keep the label on one line */
  font-size: 0.85rem;                  /* fits the longest label in the narrowest 4-col card */
  padding: 0.8rem 0.7rem;              /* ~46px tall (>=44px tap target) */
  display: inline-flex;
  align-items: center;
  background: var(--accent);           /* per-card accent (button fill) */
  color: var(--ink);                   /* per-card ink (label) */
  border-color: var(--accent);         /* .btn base carries a 2px transparent border */
}
.gateway-card .gateway-card__btn > span { margin-left: 0.45rem; }   /* label↔arrow space via margin, not flex gap (Safari <14.1) */
.gateway-card .gateway-card__btn:hover {
  background: var(--accent-hover);     /* darken each button's OWN accent */
  color: var(--ink);                   /* ink stays per spec (deep-purple on gold, white on purple) */
  border-color: var(--accent-hover);
}
.gateway-card .gateway-card__btn:focus-visible {
  background: var(--accent-hover);
  color: var(--ink);
  border-color: var(--accent-hover);
}
/* --- Per-card fixes ---------------------------------------------------------
   1) Card 4's deep-purple button vanishes on its dark image — give it a visible
      lavender edge in every state (fill/text stay per the accent scheme).
      :focus-visible is a SEPARATE rule: grouping it would drop the whole list —
      including the base border — in Safari <15.4. */
.gateway__grid > li:nth-child(4) .gateway-card__btn,
.gateway__grid > li:nth-child(4) .gateway-card__btn:hover {
  border: 1.5px solid rgba(247, 244, 251, 0.7);   /* #F7F4FB @ 70% — clear shape on any background */
}
.gateway__grid > li:nth-child(4) .gateway-card__btn:focus-visible {
  border: 1.5px solid rgba(247, 244, 251, 0.7);
}
/* 2) Card 4's building photo reads cool/blue; add an extra brand-purple wash
      over the shared veil (#3A2A66, matched opacity) so the set is cohesive. */
.gateway__grid > li:nth-child(4) .gateway-card::before {
  /* Shared layers kept in step with the base veil (this card is commented
     out in the markup today - consistency for restore; retune the extra
     wash then). */
  background-image:
    linear-gradient(180deg, rgba(46, 33, 80, 0.12) 0%, rgba(46, 33, 80, 0.42) 40%, rgba(46, 33, 80, 0.62) 72%, rgba(46, 33, 80, 0.78) 100%),
    linear-gradient(rgba(20, 20, 20, 0.15), rgba(20, 20, 20, 0.15)),
    linear-gradient(rgba(58, 42, 102, 0.30), rgba(58, 42, 102, 0.30));   /* extra warm-purple wash */
}
/* 3) Gold cards (1, 3): deep-purple glyphs on the gold circle (AA), matching
      their dark button text. Purple cards (2, 4) keep white glyphs. */
.gateway__grid > li:nth-child(1) .gateway-card__icon,
.gateway__grid > li:nth-child(3) .gateway-card__icon { color: var(--purple-deep); }
/* 5) Tighten the gap between the card row and the reassurance band. */
.gateway { padding-bottom: clamp(1.5rem, 3vw, 2.25rem); }
/* --- Pathway openings (the four Gateway destinations) -----------------------
   Each destination opens with the persona's greeting and a small set of clear
   choices, so nobody lands straight inside a single function. Cards reuse the
   site's card language; the disabled variant is visibly inert (not a link,
   muted dashed surface, gold COMING SOON label). AA on white: heading
   --purple-deep 14.9:1, card title 14.9:1, body --text-warm 8.6:1, the gold
   label uses the deepened #8A6128 (5.4:1 at label size). */
.pathway { background: var(--white); }
.pathway__heading {
  margin: 0;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  line-height: 1.25;
  color: var(--purple-deep);
}
.pathway__lede {
  margin: 0.75rem 0 0;
  max-width: 58ch;
  font-size: clamp(1rem, 2vw, 1.08rem);
  line-height: 1.6;
  color: var(--text-warm);
}
.pathway__grid {
  list-style: none;
  margin: clamp(1.5rem, 3.5vw, 2.25rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;                /* phone: stacked */
  gap: 1rem;
}
.pathway__grid > li { display: flex; }       /* cards share a row height */
.choice-card {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 0.4rem;
  padding: clamp(1.1rem, 2.5vw, 1.5rem);
  background: var(--white);
  border: 1px solid var(--lavender);
  border-radius: var(--radius);
  box-shadow: 0 2px 10px rgba(46, 33, 80, 0.08);
  text-decoration: none;
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.22s ease;
}
a.choice-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.16);
}
a.choice-card:focus-visible {
  transform: translateY(-4px);
  box-shadow: 0 10px 24px rgba(46, 33, 80, 0.16);
}
a.choice-card:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.choice-card__title {
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.05rem, 2.2vw, 1.2rem);
  line-height: 1.3;
  color: var(--purple-deep);
}
a.choice-card:hover .choice-card__title { color: var(--purple-bright); }
.choice-card__text { font-size: 0.93rem; line-height: 1.5; color: var(--text-warm); }
/* Not-yet-available choice: a <div>, never a link. */
.choice-card--disabled {
  background: var(--lavender-light);
  border-style: dashed;
  box-shadow: none;
}
.choice-card--disabled .choice-card__title { color: var(--purple); }
.choice-card__soon {
  align-self: flex-start;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-deep);                            /* deepened gold - AA at label size */
}
.pathway__grid--1 { grid-template-columns: 1fr; max-width: 32rem; }
@media (min-width: 620px) { .pathway__grid { grid-template-columns: repeat(2, 1fr); gap: 1.15rem; } }
@media (min-width: 900px) { .pathway__grid--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1060px) { .pathway__grid--4 { grid-template-columns: repeat(4, 1fr); } }
@media (prefers-reduced-motion: reduce) {
  .choice-card { transition: box-shadow 0.22s ease; }
  a.choice-card:hover { transform: none; }
  a.choice-card:focus-visible { transform: none; }
}

/* Reassurance close: community line, a compact subline, and a quiet,
   lock-marked privacy note. AA on white: line --purple-deep ~14:1, sub
   --text-warm ~8.6:1, privacy --text-muted ~4.6:1 at 0.88rem. */
/* 2026-08: the close section moved INSIDE .gateway-scene so the statement
   sits within the photograph - its old solid white slab would have hidden
   the image. The photograph now runs ALL THE WAY to the footer's top edge
   (client request - the white band that used to resolve before the footer
   is gone); the bottom padding is breathing room below the statement, over
   open field. The statement's veil is ELEMENT-ANCHORED here, so it tracks
   the statement at every width (its scene-percentage position drifts from
   82% at 1440px to ~94% at 768px). */
.gateway-close { background: transparent; text-align: center; padding-top: clamp(1.75rem, 3.5vw, 2.5rem); padding-bottom: clamp(4.5rem, 8vw, 7rem); }
/* 2026-08: the panel/veil behind the closing statement is REMOVED at the
   client's explicit direction - the statement sits directly on the raw
   photograph at every width, no replacement treatment. Measured on the raw
   field at the statement's position (darkest sub-regions): 10.99:1 at
   390px, 3.29:1 at 768px, 1.15:1 at 1440px - the sub-768 figure passes AA,
   the desktop figures do not; recorded here and in the task report as the
   client's accepted trade-off. */
@media (max-width: 767.98px) {
  /* Phones: the scene image lives on the hero only, so the close section
     carries its OWN soft-edged band of the same landscape - positioned at
     the horizon (center 45%), where the statement measures 10.99:1 raw at
     its darkest patch, NO veil needed. The white feather at the TOP blends
     from the white cards above; the bottom runs the photograph straight to
     the footer's edge. */
  .gateway-close {
    background-image:
      linear-gradient(180deg,
        rgba(255, 255, 255, 1) 0%,
        rgba(255, 255, 255, 0) 16%,
        rgba(255, 255, 255, 0) 100%),
      url("../img/gateway/gateway-sunrise-mobile.webp");
    background-size: cover;
    background-position: center 45%;
    background-repeat: no-repeat;
  }
}
.gateway-close__line {
  margin: 0 auto;
  max-width: 30ch;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.4rem, 2.9vw, 2rem);
  line-height: 1.25;
  color: var(--purple-deep);
  text-wrap: balance;
}
/* 2026-08: WHITE from 768px (lowered from 1024 when the SUNRISE background
   landed - its 768-1023 band is deep blue where purple measured 1.65:1 and
   white measures 8.77:1). Below 768 the statement sits on the mobile band's
   pale horizon: purple stays right there (6.60:1) and white would fail
   (2.19:1). The soft purple shadow reads as depth, not an outline; WCAG
   gives shadows no credit - at 1440px white's brightest sunlit patch is
   3.29:1, the same shadow-carried trade-off the homepage hero ships by
   explicit owner decision. */
@media (min-width: 768px) {
  .gateway-close__line {
    color: var(--white);
    text-shadow: 0 1px 2px rgba(46, 33, 80, 0.45), 0 2px 14px rgba(46, 33, 80, 0.30);
  }
}
/* REMOVED Aug 2026 at client request — served only the sub + privacy lines
   commented out in gateway.html; retained for restore.
.gateway-close__sub {
  margin: 0.6rem auto 0;
  font-size: clamp(0.95rem, 2vw, 1.05rem);
  letter-spacing: 0.03em;
  color: var(--text-warm);
}
.gateway-close__privacy {
  margin: 1.5rem auto 0;
  display: inline-flex;
  align-items: center;
  font-size: 0.88rem;
  color: var(--text-muted);
}
.gateway-close__privacy svg { width: 16px; height: 16px; flex: 0 0 auto; margin-right: 0.4rem; }
*/
/* REMOVED Aug 2026 - the 620-899px TWO-COLUMN band wrapped three equal cards
   2+1, which read as unbalanced (flagged twice). The grid is now single-column
   below 900px and three-across from 900px up (the 3-col rule later in the
   sheet) - no width shows 2+1. Retained for restore:
@media (min-width: 620px) { .gateway__grid { grid-template-columns: repeat(2, 1fr); gap: 1.25rem; } }
*/
/* Tablet + desktop: deepen the hero's sky band and pull the cards up so their
   upper third floats over the sunrise. The hero keeps ~3rem of clear sky
   between the subtitle and the card tops. Cards gain a soft depth shadow. */
@media (min-width: 768px) {
  /* The sky now spans the whole scene (hero + full card row) and fades to white
     BELOW the cards, so the entire card row floats within the sunrise. The
     hero's own sky is removed so the tones don't double up. Same purple-leaning
     wash: strong up top (heading AA), light through the middle (mountains show),
     opaque-light at the foot (clean hand-off to the white close section). */
  .gateway-hero {
    background-image: none;
    padding-bottom: clamp(9.5rem, 15vw, 13.5rem);   /* more sunrise above the cards; overlap (pull) unchanged, so they still float */
  }
  .gateway-scene {
    /* 2026-08: NO wash and NO scene-level fade - the photograph runs clean
       from the sky through the card row to the closing statement (every
       hero text element clears 5.16:1+ raw, darkest sub-regions included).
       The statement's veil and the long fade to white are ELEMENT-ANCHORED
       on .gateway-close below: the statement's position as a percentage of
       the scene varies hugely with width (82% at 1440px, ~94% at 768px
       where the stacked cards make the scene very tall), so scene-anchored
       stops could never track it. */
    background-image: url("../img/gateway/gateway-sunrise.webp");
    background-size: cover;
    background-position: center top;
    background-repeat: no-repeat;
  }
  .gateway {
    position: relative;
    z-index: 2;                                       /* float above the sky */
    margin-top: clamp(-9rem, -10vw, -6rem);           /* pull cards up into the sky */
    padding-top: 0;
  }
  .gateway-card { box-shadow: 0 16px 36px rgba(46, 33, 80, 0.26); }
  .gateway-card:hover,
  .gateway-card:focus-within { box-shadow: 0 22px 48px rgba(46, 33, 80, 0.34); }
}
@media (min-width: 900px) {
  /* 2026-08 WIDEN + TIGHTEN (client direction; replaces the 255px/157.5px
     spread): gap fixed at 40px and the cards take the rest - width =
     (100% - 80px) / 3 = 333.3px in the 1080px container (the requested
     420-460px cannot physically fit three-up in a 1080px container with 40px
     gaps: it needs >=1340px - reported). Flush both edges, zero slack;
     aspect 3/4 keeps the cards portrait (333x444). ALSO the tablet fix:
     this 3-across now holds down to 900px (cards ~260px there, matching the
     old desktop size) and below 900 the grid is single-column - the 620-1099
     two-column band that wrapped 2+1 is retired below. */
  .gateway__grid { grid-template-columns: repeat(3, calc((100% - 80px) / 3)); justify-content: center; column-gap: 40px; }
  .gateway-card { aspect-ratio: 3 / 4; }
}
@media (prefers-reduced-motion: reduce) {
  .gateway-card { transition: box-shadow 0.22s ease; }
  .gateway-card:hover,
  .gateway-card:focus-within { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .expert-card { transition: box-shadow 0.22s ease; }
  .expert-card--link:hover { transform: none; }   /* shadow only - no lift under reduced motion */
}

/* --- Layered hero → stats → cards overlap (>=900px) ------------------------
   The Evidence card now takes over the role the stats strip played: from
   tablet up it rides onto the hero's lower portion so the footage stays
   visible above and just behind its top edge, and the page reads as one
   layered flow (video -> floating card -> rest of page) with no dead gap.
   Geometry: the hero reserves a bottom zone under its centred copy; the card
   lifts into it by less than that reserve, so the copy is never touched, and
   the scroll cue is parked between the two - above the card's top edge and
   below the hero copy. Mobile keeps a normal stacked flow (no overlap). */
/* Overlap knob: tune --evidence-overlap per breakpoint (negative = how far the
   card's top lifts over the hero's bottom edge). Card corners/shadow/contents/
   count-up are untouched. */
@media (max-width: 430px) {
  .why-gem {
    position: relative;
    z-index: 3;
    --evidence-overlap: -16px;      /* phones: nearly flush lip */
    margin-top: var(--evidence-overlap);
    padding-top: 0;                 /* the lift replaces the section's top pad */
  }
}
@media (min-width: 768px) {
  .hero--editorial { padding-bottom: clamp(4.25rem, 8vh, 5.5rem); }   /* breathing room below the doorways + the chevron slot (crisp edge, no fade) */
  .why-gem {
    position: relative;
    z-index: 3;                     /* above the hero's isolated stack */
    --evidence-overlap: -72px;      /* tablet + desktop: small lip tucking over the hero's bottom */
    margin-top: var(--evidence-overlap);
    padding-top: 0;                 /* the lift replaces the section's top pad */
  }
  /* (The cue is re-parked for this overlap after its base rule below.) */
}
@media (min-width: 1100px) {
  .hero--editorial { padding-bottom: clamp(4.25rem, 8vh, 5.5rem); }   /* breathing room below the doorways + the chevron slot (crisp edge, no fade) */
}

/* --- Hero scroll cue --------------------------------------------------------
   Gentle 2s bounce at the hero's visual bottom, none under
   prefers-reduced-motion (ui.js also swaps smooth scroll for instant). */
/* Editorial hero: the cue sits just beneath the doorway row, over rich video, near
   the crisp bottom edge. White + drop-shadow for legibility over the footage (beats
   the >=768px re-park overrides via higher specificity). */
.hero--editorial .hero__scroll {
  display: inline-flex;
  bottom: clamp(0.75rem, 2vh, 1.25rem);
  z-index: 3;
  color: var(--white);
}
.hero__scroll {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 1.25rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  color: var(--purple);                      /* over the light mobile still */
}
.hero__scroll svg {
  width: 26px;
  height: 26px;
  filter: drop-shadow(0 1px 2px rgba(24, 16, 44, 0.35));
}
.hero__scroll:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* From tablet up the Evidence card rides onto the hero's bottom, so the cue is
   parked in the reserved gap between the hero copy and the card's top edge —
   ~1.5rem clear of the card, well clear of the copy. (Must sit after the base
   rule above: media queries add no specificity.) */
@media (min-width: 768px) {
  .hero__scroll { bottom: 5.5rem; color: var(--white); }
}
@media (min-width: 1100px) {
  .hero__scroll { bottom: 8rem; }
}
@media (prefers-reduced-motion: no-preference) {
  .hero__scroll svg { animation: heroCueBounce 2s ease-in-out infinite; }
}
@keyframes heroCueBounce {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}

/* --- Floating AI-assistant button (placeholder) ------------------------------
   Fixed lower-right circular FAB using the repo's chatbot icon (deep-purple disc,
   gold ring, white bubble — the SVG carries its own design; the button is just a
   transparent circular hit area). z-index 90: above page content, below the
   header (100). ui.js adds .is-shown past the hero and removes it while the
   footer is visible; no-JS shows it always (the .js gate keeps it functional
   without JavaScript). Placeholder only — no chat logic. */
/* Shared geometry for the bottom-right FAB STACK: the chat button is anchored in
   the corner and the back-to-top button sits directly above it. One set of values
   drives both, so the gap can never drift out of sync. */
.chatbot-fab,
.chatbot-bubble,
.to-top {
  --fab-inset: clamp(1rem, 2.5vw, 1.5rem);   /* distance from the corner */
  --fab-size: 60px;                          /* the chat FAB's diameter — the PRIMARY of the pair */
  --fab-size-2: 41.6px;                      /* 2026-08 demotion (client direction): 52px - 20% = 41.6px (69.3% of the 60px launcher) so the GEM Assistant clearly leads the pair. Visible size only - the 44px hit floor lives on a centred ::after overlay. The derived right-offset ((size - size-2)/2 = 9.2px) keeps both on one centreline. */
  --fab-gap: 1rem;                           /* 2026-08: 16px between the two buttons (was 12px) */
  /* ONE shared drop shadow = the pair's shared DNA (soft purple-tinted lift). */
  --fab-shadow: 0 8px 22px rgba(75, 46, 131, 0.35), 0 2px 6px rgba(46, 33, 80, 0.25);
  --fab-shadow-hover: 0 12px 28px rgba(75, 46, 131, 0.45), 0 3px 8px rgba(46, 33, 80, 0.3);
}
/* DESKTOP-ONLY +15% (2026-08 client direction): the launcher orb 60 -> 69px at
   >=1024px - the stylesheet's existing tablet/desktop breakpoint - while
   phones and small tablets keep 60px UNTOUCHED pending real-device testing.
   Everything derived from --fab-size (the back-to-top's bottom offset and
   centring formula, the greeting bubble's offsets, the cookie-bar lift) reads
   the variable, so all spacing relationships hold automatically. The inner
   PNG is width/height 100% and scales with the box - nothing else to size. */
@media (min-width: 1024px) {
  .chatbot-fab,
  .chatbot-bubble,
  .to-top { --fab-size: 69px; }
}
.chatbot-fab {
  position: fixed;
  right: var(--fab-inset);
  bottom: var(--fab-inset);
  z-index: 90;
  width: var(--fab-size);
  height: var(--fab-size);                   /* 60px (>=44px tap target); 69px at >=1024px via the --fab-size flip above */
  padding: 0;
  /* 2026-08 GEM Assistant icon (replaces the drawn robot disc): the PNG is a
     transparent orb with its OWN soft outer glow, so the button is now a bare
     transparent container - no disc background, no gold ring, no shadow (a
     container would fight the artwork's glow). */
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  box-shadow: none;                           /* the artwork's baked-in glow is the only halo at rest */
  transition: box-shadow 0.18s ease;
}
.chatbot-fab__icon {
  display: block;
  width: 100%;
  height: 100%;
}
.js .chatbot-fab {                            /* hidden until ui.js reveals it */
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.5rem);
  transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
}
.js .chatbot-fab.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.chatbot-fab__bot {
  width: 100%;
  height: 100%;
  display: block;
}
/* Idle life (2026-08 robot spec): the WHOLE robot bobs gently and the antennae
   tilt with it - replaces the old 1.0<->1.03 breathe pulse on the button. The
   transforms live on inner SVG groups, so they can never fight the reveal
   fade/rise on the button itself. transform-box: view-box makes the px origins
   read in the SVG's own 60x60 coordinate space (engines without it fall back to
   a slightly different pivot - motion stays subtle either way). */
/* (INERT since the 2026-08 GEM Assistant icon swap - the drawn robot markup is
   gone, so the bob/antennae rules match nothing. RESTING STATE = the icon
   as-is, deliberately unanimated. Kept as the robot's restore path.) */
.chatbot-fab__bot-body {
  animation: chatBotBob 2.6s ease-in-out infinite;
  transform-box: view-box;
  transform-origin: 30px 36px;
}
.chatbot-fab__bot-antennae {
  animation: chatBotAntennae 2.6s ease-in-out infinite;
  transform-box: view-box;
  transform-origin: 30px 26px;
}
@keyframes chatBotBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2.5px); }
}
@keyframes chatBotAntennae {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(-5deg); }
}
/* ---- GEM Assistant states (2026-08). Three states, none colour-only:
   RESTING = the icon as-is, no animation (the old bob/antennae rules are
   inert above). NEW MESSAGE = .has-message dot (presence/shape cue) at the
   upper-right - purple-bright fill (5.9:1 on white pages) inside a 2px white
   ring, so it separates from both the icon's purple orb and any page ground.
   Nothing sets the class on load; ui.js exposes the inactive hook
   window.GEM_ASSISTANT_SET_NEW_MESSAGE(bool) for the future backend.
   ACTIVE = a soft halo ring on BOTH hover and keyboard focus (size/shape
   change, not colour alone); its 0.18s ease is killed under reduced motion so
   the ring appears instantly. */
.chatbot-fab.has-message::before {
  content: "";
  position: absolute;
  top: 1px;
  right: 1px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--purple-bright);           /* 5.9:1 vs white page; the white ring separates it from the orb */
  border: 2px solid var(--white);
  z-index: 1;
}
.chatbot-fab:hover,
.chatbot-fab:focus-visible {
  box-shadow: 0 0 0 6px rgba(107, 79, 160, 0.22), 0 0 20px 6px rgba(107, 79, 160, 0.30);   /* the gentle lift halo */
  border-radius: 50%;
}
.chatbot-fab:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 3px; }   /* NOT the raw --focus token; 5.9:1 on white */
.chatbot-fab__tip {                           /* "coming soon" — shows on hover/focus */
  position: absolute;
  right: calc(100% + 0.6rem);
  bottom: 50%;
  transform: translateY(50%);
  white-space: nowrap;
  background: var(--purple-deep);
  color: var(--white);                        /* ~13:1 = AA */
  font-size: 0.8rem;
  padding: 0.35rem 0.65rem;
  border-radius: 8px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
}
.chatbot-fab:hover .chatbot-fab__tip,
.chatbot-fab:focus-visible .chatbot-fab__tip { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .js .chatbot-fab, .js .chatbot-fab.is-shown, .chatbot-fab, .chatbot-fab__tip { transition: none; }
  .chatbot-fab__bot-body, .chatbot-fab__bot-antennae { animation: none; }   /* static robot - no bob, no antenna tilt */
}

/* --- "Need help? I'm here." bubble (2026-08, ui.js injects the markup) -------
   One line, LEFT of the robot launcher (extends left, never up, so it cannot
   collide with the back-to-top button stacked above). Vertically centred on
   the 60px disc. Fixed position = zero layout shift; ui.js owns the timing
   (appears with the reveal, waits out the cookie card, auto-fades ~7s). */
.chatbot-bubble {
  position: fixed;
  right: calc(var(--fab-inset) + var(--fab-size) + 12px);   /* clear of the disc + a small gap - derived, so the desktop 69px orb pushes it left automatically (identical maths at the mobile 60px) */
  bottom: calc(var(--fab-inset) + (var(--fab-size) - 64px) / 2);   /* (orb - 64px card)/2 - the bubble's vertical CENTRE sits exactly on the launcher's at BOTH orb sizes (resolves to the old inset - 2px at 60px) */
  z-index: 90;
  display: flex;
  align-items: center;
  min-height: 44px;
  background: var(--white);
  border: 0.5px solid rgba(75, 46, 131, 0.35);   /* light purple hairline */
  border-radius: 14px 14px 4px 14px;             /* tight corner = the tail, pointing at the launcher */
  padding: 0.5rem 2.1rem 0.5rem 0.6rem;          /* 2026-08 card: right padding clears the corner X */
  box-shadow: 0 8px 22px rgba(46, 33, 80, 0.18);
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity 0.35s ease, transform 0.35s ease, visibility 0s linear 0.35s;
}
.chatbot-bubble.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.35s ease, transform 0.35s ease;
}
/* 2026-08 card restyle (mockup): icon left, two stacked lines, X upper-right. */
.chatbot-bubble__icon {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  margin-right: 0.55rem;                         /* margin, not flex gap */
}
.chatbot-bubble__text {
  display: block;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
}
.chatbot-bubble__hi {
  display: block;
  font-family: var(--font-head);
  font-size: 14px;
  font-weight: 700;
  color: var(--purple);                          /* brand purple on white - 11.7:1 */
}
.chatbot-bubble__sub {
  display: block;
  margin-top: 1px;
  color: var(--text);                            /* body colour - 14.9:1 on white */
}
.chatbot-bubble__close {
  position: absolute;                            /* upper-right of the card, per the mockup */
  top: 0;
  right: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;                                  /* past the 24px WCAG 2.5.8 minimum; dismisses the BUBBLE only */
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--text-muted);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
}
.chatbot-bubble__close:hover { color: var(--purple); }
.chatbot-bubble__close:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 1px; }   /* NOT the raw --focus token */
@media (prefers-reduced-motion: reduce) {
  .chatbot-bubble, .chatbot-bubble.is-shown { transition: none; transform: none; }   /* appears/disappears instantly */
}

/* --- GEM Assistant window (2026-08, ui.js injects the markup) ----------------
   NAVIGATION GUIDE, not a chat: header (icon/name/minimise/close), verbatim
   greeting, five routing buttons, and the REQUIRED safeguarding footer line.
   NO input field by design. Anchored above the launcher, bottom-right, z=110
   (above the FABs at 90 and the header at 100, below the cookie card at 120);
   while body.has-cookie-bar it lifts with the same formula as the FABs so the
   two never collide. Open/close fade is killed under reduced motion. */
.gembot {
  position: fixed;
  right: var(--fab-inset, 1.5rem);
  /* Anchored above the WHOLE corner stack (launcher 60 + gap 12 + back-to-top
     52 + 12 clearance) so it can never cover either button; the max-height
     mirrors the bottom offset so the top never leaves the viewport. */
  bottom: calc(var(--fab-inset, 1.5rem) + 136px);
  z-index: 110;
  width: min(340px, calc(100vw - 24px));
  max-height: min(560px, calc(100dvh - var(--fab-inset, 1.5rem) - 136px - 12px));
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.16);
  border-radius: 16px;
  box-shadow: 0 22px 54px -18px rgba(20, 12, 40, 0.5);
  overflow: hidden;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.gembot.is-open { opacity: 1; transform: none; }
body.has-cookie-bar .gembot {
  bottom: calc(var(--fab-inset, 1.5rem) + 136px + var(--cookie-bar-h, 150px) + 24px);
  max-height: min(560px, calc(100dvh - var(--fab-inset, 1.5rem) - 136px - var(--cookie-bar-h, 150px) - 24px - 12px));
}
@media (prefers-reduced-motion: reduce) {
  .gembot, .gembot.is-open { transition: none; transform: none; }   /* no open/close animation */
}
.gembot__head {
  display: flex;
  align-items: center;
  padding: 0.7rem 0.5rem 0.7rem 0.85rem;
  background: var(--purple);                 /* brand purple bar - white text 12.3:1 */
  color: var(--white);
}
.gembot__icon { flex: 0 0 auto; width: 36px; height: 36px; margin-right: 0.6rem; }   /* margin, not flex gap */
.gembot__id { flex: 1 1 auto; min-width: 0; }
.gembot__name { margin: 0; font-family: var(--font-head); font-weight: 700; font-size: 1rem; line-height: 1.2; }
.gembot__tag { margin: 0; font-size: 0.78rem; color: #EFEAF6; }   /* 10.4:1 on the purple bar */
.gembot__min,
.gembot__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;                               /* tap floor */
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--white);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}
.gembot__min:hover,
.gembot__close:hover { background: rgba(255, 255, 255, 0.14); }
.gembot__min:focus-visible,
.gembot__close:focus-visible { outline: 3px solid var(--white); outline-offset: 2px; }   /* white ring on the purple bar (12.3:1); NOT the raw --focus token */
.gembot__body { padding: 0.9rem 0.85rem 0.4rem; overflow-y: auto; }
.gembot__greet { margin: 0 0 0.8rem; font-size: 0.95rem; line-height: 1.5; color: var(--text); }
.gembot__greet strong { font-family: var(--font-head); font-size: 1.02rem; color: var(--purple); }
.gembot__list { display: block; }
.gembot__opt {
  display: flex;
  align-items: center;
  min-height: 44px;                          /* tap floor */
  margin: 0 0 0.45rem;
  padding: 0.55rem 0.8rem;
  background: var(--lavender-light);
  border: 1px solid rgba(58, 42, 102, 0.14);
  border-radius: 10px;
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--purple);                      /* 11.5:1 on lavender-light */
  text-decoration: none;
}
.gembot__opt:hover { background: var(--lavender); border-color: var(--purple-bright); }
.gembot__opt:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; }   /* NOT the raw --focus token */
.gembot__foot {
  display: flex;
  align-items: flex-start;
  margin: 0;
  padding: 0.6rem 0.85rem 0.7rem;
  border-top: 1px solid rgba(58, 42, 102, 0.12);
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--text-warm);                   /* 8.9:1 on white */
}
.gembot__shield { flex: 0 0 auto; width: 16px; height: 16px; margin: 0.1rem 0.5rem 0 0; color: var(--gold-deep); }
.gembot__shield svg { width: 16px; height: 16px; display: block; }

/* --- Back-to-top button (shared, every page) ---------------------------------
   Fixed LOWER-RIGHT, stacked directly ABOVE the chat FAB (client direction — the
   chat FAB now ships on every page, so one shared corner stack is consistent
   site-wide). Position is DERIVED from the shared --fab-* values above, not
   hand-tuned: bottom = inset + the FAB's diameter + the gap, so the two can never
   touch however the clamp resolves; right is nudged by half the size difference
   ((--fab-size - --fab-size-2) / 2) so the smaller button is optically CENTRED
   over the FAB.
   Same z-index 90 as the FAB (above page + footer content, below the header at
   100), so both stay clickable to the bottom of the page. Hidden until ui.js adds
   .is-shown; with no JS it never appears (the .js gate) since nothing would
   drive it. */
.to-top {
  position: fixed;
  /* Optically centred over the primary FAB: right offset = half the size
     difference, DERIVED from the shared vars so it can never drift. */
  right: calc(var(--fab-inset) + (var(--fab-size) - var(--fab-size-2)) / 2);
  bottom: calc(var(--fab-inset) + var(--fab-size) + var(--fab-gap));
  z-index: 90;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--fab-size-2);
  height: var(--fab-size-2);                 /* 52px — a small deliberate step under the 60px primary; >=44px target */
  padding: 0;
  /* 2026-08 FAMILY MATCH (client direction): the old purple disc + gold ring
     read as unrelated to the GEM Assistant orb. Now the launcher's own
     lavender-glass: fill = the artwork's sampled mid-orb tone
     rgb(199,166,241) at 0.9, glow = its sampled halo rgb(229,211,243) at
     0.54, NO ring, WHITE geometric chevron matching the orb's white line
     art. ⚠️ Reported, not hidden: white on this lavender measures ~2.1:1 -
     the same accepted ratio the launcher artwork's own white line art
     carries; a purple-deep arrow is the AA alternative if wanted. */
  border: 0;
  border-radius: 50%;
  /* 2026-08 LIGHTENED 15% (client direction, quieter sibling): each channel
     moved 15% toward white - r 199+0.15(255-199)=207.4, g 166+0.15(255-166)
     =179.35, b 241+0.15(255-241)=243.1 -> rgb(207,179,243).
     Same lavender family as the launcher orb, one step lighter. Glow
     unchanged: it renders OUTSIDE the disc against the page, so the lighter
     fill does not wash it out - no opacity adjustment needed.
     Alpha 0.9 -> 0.72 (-20% resting opacity) per GEM, August 2026; the 3:1
     non-text contrast floor is client-waived for this control. Hover stays
     alpha 1 so the lift reads clearly against the quieter resting state. */
  background: rgba(207, 179, 243, 0.72);
  color: var(--white);
  cursor: pointer;
  box-shadow: 0 0 18px 6px rgba(229, 211, 243, 0.54), 0 0 4px 1px rgba(229, 211, 243, 0.4);
  transition: background-color 0.18s ease, box-shadow 0.18s ease;
}
.to-top svg { width: 17px; height: 17px; display: block; }   /* scaled with the 41.6px button - stays ~40% of the diameter (21px of 52px before) */
/* 44px HIT FLOOR (2026-08): the visible disc is 41.6px, under the 44px tap
   minimum - a centred transparent overlay carries the hit area without
   consuming layout width or changing the visual size. */
.to-top::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}
.js .to-top {                                /* hidden until ui.js reveals it */
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.5rem);
  transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
}
.js .to-top.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
/* Hover/focus lift lives on colour + shadow only (never transform) so it cannot
   fight the reveal's transform, which wins on specificity. */
.to-top:hover {
  background: rgba(207, 179, 243, 1);        /* settles solid — the gentle lift (lightened with the base fill) */
  box-shadow: 0 0 22px 8px rgba(229, 211, 243, 0.62), 0 0 5px 2px rgba(229, 211, 243, 0.45);
}
.to-top:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 3px; }   /* NOT the raw --focus token; 5.9:1 on light pages */
@media (prefers-reduced-motion: reduce) {
  .js .to-top, .js .to-top.is-shown, .to-top { transition: none; }
}

/* --- Gold eyebrow variant ---------------------------------------------------
   Deepened gold for small caps on light surfaces: canonical #BB863F reads
   ~2.9:1 on lavender-light (fails AA at eyebrow size), so text usages darken
   within the gold family — 5.1:1 here. Icons/dividers keep the true gold. */
.eyebrow--gold { color: var(--gold-deep); }   /* gold kickers REINSTATED (client direction): matches the base .eyebrow gold; the accessible deep gold, since these sit on light homepage sections */

/* --- The Founder's Vision — full-width portrait + vision --------------------
   Portrait ~40% left, text ~60% right from 760px up; stacks portrait-first
   below (figure is first in source order). The photo is a square source shown
   in a 4/5 PORTRAIT crop via object-fit: cover — cropped, never distorted. AA
   on lavender-light: --purple-deep pull-quote ≈ 12:1, --text-warm note ≈ 8.6:1,
   --purple name ≈ 10:1, --text-muted role ≈ 6:1, gold eyebrow (#8A6128) 5.1:1. */
.founder-vision { background: var(--lavender-light); }
.founder-vision__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.75rem, 4vw, 3rem);
}
@media (min-width: 760px) {
  .founder-vision__grid {
    grid-template-columns: 40% 1fr;          /* portrait ~40%, text ~60% */
    gap: clamp(2rem, 4.5vw, 3.75rem);
    align-items: center;
  }
}
.founder-vision__portrait { margin: 0; }
.founder-vision__photo {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;                        /* large portrait — not a small avatar */
  object-fit: cover;                          /* square source cropped, never stretched */
  object-position: center;                    /* keeps the centred face in frame */
  border-radius: 18px;
  box-shadow: 0 12px 32px rgba(46, 33, 80, 0.18);
}
.founder-vision__id { margin-top: 1.1rem; }
.founder-vision__name {
  margin: 0;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.05rem, 1.7vw, 1.25rem);
  line-height: 1.3;
  color: var(--purple);
}
.founder-vision__role {
  margin: 0.3rem 0 0;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--text-muted);
}
.founder-vision__text { max-width: 42rem; }
.founder-vision__quote { margin: 0.7rem 0 0; }
.founder-vision__quote p {
  margin: 0;
  font-family: var(--font-head);             /* Lora italic pull-quote */
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.4rem, 2.6vw, 2rem);     /* large */
  line-height: 1.4;
  color: var(--purple-deep);
}
.founder-vision__note {
  margin: 1.5rem 0 1.9rem;
  max-width: 52ch;
  font-size: clamp(1rem, 1.4vw, 1.08rem);
  line-height: 1.6;
  color: var(--text-warm);
}


/* Hidden v3 sections (marquee / experts row / old cta-band) stay hidden even
   if a display rule ever lands on them. */
section[hidden] { display: none !important; }

/* --- Closing band — light sunrise (dawn gradient) ---------------------------
   The page's warm close before the dark footer, so the run of light sections
   ends light -> light -> light-sunrise -> dark footer (no two dark bands
   adjacent). A warm gold glow eases down into soft lavender using existing
   tokens. Everything centered. AA on the lightest point (the lavender foot):
   --purple-deep quote 12.9:1; the source uses the deepened text-gold #8A6128
   (5.4:1 at its small-caps size - canonical gold fails on a light ground);
   the button is white on opaque --purple-bright (6.5:1). */
.closing-band {
  /* Lavender-field image band, layered bottom -> top:
       1. ::after (z-1) — the image itself on its OWN layer, cover, nudged right,
          with the sharpening filter (contrast/saturate/brightness) that must never
          touch the text or scrim;
       2. ::before (z0) — the LEFT text-protecting dark-purple scrim, fading to
          fully-revealed image on the right;
       3. the content (z2).
     background-color is the image-missing fallback so text is never stranded on
     white. */
  position: relative;
  isolation: isolate;
  background-color: var(--purple-deep);         /* image-missing fallback (the image now lives on ::after, below) */
  /* TALLER, cinematic band — clearly taller than the footer beneath; the generous
     vertical padding gives the lavender scene room to breathe and keeps the
     left-aligned content vertically balanced. */
  padding-block: clamp(4rem, 8vw, 6.5rem);
  text-align: left;                             /* editorial left-aligned copy; the image owns the right */
  /* Step 13: the gold CTA→footer hairline lives ONCE, on .site-footer's border-top.
     Removed the duplicate border-bottom here that was stacking into a 2px double line. */
}
/* The ONLY overlay: a NARROW left text-protecting scrim. No full-band frost/tint —
   the image shows at near-full clarity and warmth (the mockup look): golden sunrise,
   field, path and women all clean and bright across the centre + right. The soft
   dark-purple fade lives only behind the left text column and is fully transparent
   by ~60% — the right ~40% carries nothing at all. */
.closing-band::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: 0;
  background: linear-gradient(90deg,
    rgba(28, 18, 56, 0.66) 0%,
    rgba(28, 18, 56, 0.52) 28%,
    rgba(28, 18, 56, 0.26) 46%,
    transparent 60%);
}
/* Phones: the left-aligned copy spans most of the narrow width, so the scrim keeps a
   floor of protection across the band (text AA wins over full image reveal here). */
@media (max-width: 639.98px) {
  .closing-band::before {
    background: linear-gradient(90deg, rgba(28, 18, 56, 0.68) 0%, rgba(28, 18, 56, 0.52) 55%, rgba(28, 18, 56, 0.3) 100%);
  }
}
/* TABLET (iPad audit fix): between 640-1023px the container has no side gutters, so
   the quote's right edge reaches ~60% of the band — exactly where the desktop scrim
   has already faded out. Extend the fade to ~76% in this band only, keeping the far
   right (women + sun) clear. Desktop (>=1024) keeps the original narrow scrim. */
@media (min-width: 640px) and (max-width: 1023.98px) {
  .closing-band::before {
    background: linear-gradient(90deg,
      rgba(28, 18, 56, 0.7) 0%,
      rgba(28, 18, 56, 0.56) 34%,
      rgba(28, 18, 56, 0.3) 58%,
      transparent 76%);
  }
}
/* The IMAGE on its own layer so a sharpening filter can hit ONLY the photo — never
   the scrim, text or button. z-index -1 inside the band's isolated stacking context
   paints it above the element's fallback colour but below the ::before scrim (z0)
   and the content (z2). Filter values (nudge here): contrast 1.15 / saturate 1.1 /
   brightness 1.02 — conservative, premium, not cooked. NOTE: the source file is
   only 1024x434, so some softness is resolution, not styling. */
.closing-band::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  z-index: -1;
  background-image: url("../img/cta-bg.webp");
  background-size: cover;
  background-position: 70% center;              /* women + sun stay in frame on the right */
  background-repeat: no-repeat;
  filter: contrast(1.15) saturate(1.1) brightness(1.02);
}
.closing-band > .container { position: relative; z-index: 2; }   /* copy + button above the scrim */
/* PHONES ONLY: keep the taller cinematic feel at narrow widths too. */
@media (max-width: 639.98px) {
  .closing-band { padding-top: 4.5rem; padding-bottom: 4rem; }
}
.closing-band__quote {
  margin: 0;                                 /* left-aligned block at the container's content margin */
  max-width: 22ch;                           /* narrower measure keeps the whole headline INSIDE the left scrim column (AA) while the image stays clear beside it */
  font-family: var(--font-head);             /* Lora */
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  line-height: 1.4;
  color: var(--white);                        /* headline white over the scrimmed image */
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.7), 0 2px 12px rgba(20, 14, 40, 0.4);   /* soft glyph halo — AA held over the image's brighter patches */
}
.closing-band__source {
  margin: 1.2rem 0 0;                        /* left-aligned under the headline */
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);                                 /* canonical gold on the scrimmed centre */
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.85), 0 1px 6px rgba(20, 14, 40, 0.5);   /* the small caps are the tightest AA margin — the shadow + centre scrim carry them */
}
.closing-band__cta { margin: clamp(1.25rem, 3vw, 1.85rem) 0 0; }   /* button aligns LEFT under the text */
.closing-band__btn {
  font-size: 1.1rem;
  padding: 1.05rem 2.1rem;                    /* large, confident primary */
  background: var(--gold);                    /* Gold #BB863F fill */
  color: var(--purple-deep);                  /* dark label on gold ≈ 4.5:1 = AA */
  border-color: var(--gold);
}
.closing-band__btn:hover {
  background: var(--gold-deep);               /* deepen on hover */
  color: var(--white);                        /* white on gold-deep ≈ 5.5:1 = AA */
  border-color: var(--gold-deep);
}
.closing-band__line {
  margin: clamp(1.1rem, 2.5vw, 1.6rem) 0 0;   /* left-aligned closing line */
  font-family: var(--font-head);             /* Lora italic */
  font-style: italic;
  font-size: clamp(1rem, 2.2vw, 1.2rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.9);           /* lifted from 0.82 — over the image band, the closing line needs the extra strength */
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.7), 0 1px 8px rgba(20, 14, 40, 0.4);
}

/* --- Mission statement — oversized editorial treatment ----------------------
   A deep-breath moment on pure white: display-scale Lora, with the two verbs
   italic in --purple-bright (6.5:1 large-text on white; the rest --purple-deep,
   14.9:1). The founder's mission runs ~200 characters, so the measure is ~34ch
   — narrower would stack it into a tower; at this width it balances into ~6
   stately lines at full scale. Now lives on our-story.html (the homepage keeps
   a short bridge line in its place). */
.mission {
  background: var(--white);
  padding-block: clamp(4.5rem, 12vw, 8.5rem);
  text-align: center;
}
.mission__statement {
  margin: 0 auto;
  max-width: 34ch;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1.5rem, 3.2vw, 2.5rem);   /* sized down (was clamp(2rem, 5vw, 4rem) — display scale read too large under the letter); same family/weight/style/emphasis. 24px min keeps the purple-bright verbs large-text AA (6.5:1) */
  line-height: 1.18;
  letter-spacing: -0.01em;
  color: var(--purple-deep);
  text-wrap: balance;
}
.mission__accent { font-style: italic; color: var(--purple-bright); }

/* --- What We Believe (homepage) — belief statement + three movement pillars --
   Design Review V2. A MEDIUM-height cream band (warm alternating beat between
   the white Evidence section above and the white Founder-quote below): a gold
   kicker, a Lora heading, a short italic supporting line, then three equal
   on-brand pillar cards (Educate / Connect / Advocate) that stack to one column
   on phones and sit 3-across from 640px up. A preserved gold "Read the Founder's
   Vision" button closes the section. AA on cream: --gold-deep kicker ≈5.2:1;
   --purple-deep heading ≈13:1; --purple lede ≈10:1. On the white pillar cards:
   --purple-deep title ≈14:1; --text-warm body ≈8.6:1; icons are decorative. */
.believe {
  background: var(--cream);
  padding-block: clamp(2.75rem, 6vw, 4.25rem);   /* medium height per the visual-rhythm plan */
  text-align: center;
}
.believe__heading {
  margin: 0.4rem 0 0.75rem;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.15;
  color: var(--purple-deep);
}
.believe__lede {
  margin: 0 auto;
  max-width: 40ch;
  font-family: var(--font-head);             /* Lora */
  font-style: italic;
  font-weight: 500;
  font-size: var(--fs-lede);
  line-height: 1.45;
  color: var(--purple);
  text-wrap: balance;
}
.believe__pillars {
  list-style: none;
  margin: clamp(2rem, 4.5vw, 3rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;                /* phone: one column */
  gap: clamp(1rem, 2.5vw, 1.5rem);
}
@media (min-width: 640px) {
  .believe__pillars { grid-template-columns: repeat(3, 1fr); }   /* tablet + desktop: 3 pillars across */
}
.pillar {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5rem;
  padding: clamp(1.5rem, 3vw, 2rem) clamp(1.15rem, 2.5vw, 1.5rem);
  /* Display content, not a button: flat on the cream band — no raised white
     card, no shadow, no hover affordance (none ever existed; these are plain
     <li> display blocks). Border kept but transparent so the box size is
     byte-identical to the old card => zero layout shift. */
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  box-shadow: none;
}
.pillar__icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin-bottom: 0.35rem;
  border-radius: 50%;
  background: var(--lavender-light);         /* soft brand circle */
  color: var(--purple-bright);               /* icon stroke — decorative, strong on lavender-light */
}
.pillar__icon svg { width: 28px; height: 28px; display: block; }
.pillar__title {
  margin: 0;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.2;
  color: var(--purple-deep);
}
.pillar__text {
  margin: 0;
  max-width: 26ch;
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--text-warm);
}
.believe__cta { margin: clamp(1.75rem, 4vw, 2.5rem) 0 0; }

/* --- Founder quote (homepage) -----------------------------------------------
   A quiet, dignified pull-quote from the Founding Chairman on pure white,
   sitting between the cream What We Believe section and the lavender Featured
   strip so the alternating rhythm holds. One oversized gold opening quotation mark is
   the only ornament; the quote is graceful Lora italic, the attribution small
   and calm beneath. Quote text, attribution and role line are verbatim.
   Quote-only: the Chairman's portrait already appears twice on this page.
   AA on white: --purple-deep quote 12.9:1; --gold-deep attribution ≈5.4:1 at
   its size; --text-muted role ≈7:1. */
.founder-quote {
  background: var(--white);
  padding-block: clamp(3.5rem, 8vw, 5.75rem);
  text-align: center;
}
.founder-quote__inner {
  margin: 0 auto;
  max-width: 44rem;
  padding: 0 1.25rem;
}
.founder-quote__mark {
  display: block;
  font-family: var(--font-display);          /* Playfair — a graceful quotation mark */
  font-size: clamp(3.25rem, 8vw, 5rem);
  line-height: 0.7;
  color: var(--gold);
  margin-bottom: 0.4rem;
}
.founder-quote__text {
  margin: 0;
  font-family: var(--font-head);             /* Lora */
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.55rem, 3.4vw, 2.35rem);
  line-height: 1.4;
  color: var(--purple-deep);
  text-wrap: balance;
}
.founder-quote__text p { margin: 0; }
.founder-quote__cite {
  display: block;
  margin-top: clamp(1.5rem, 3.5vw, 2.25rem);
}
.founder-quote__attr {
  display: block;
  font-family: var(--font-head);             /* Lora */
  font-weight: 600;
  font-size: clamp(1rem, 2.2vw, 1.1rem);
  letter-spacing: 0.01em;
  color: var(--gold-deep);                   /* deepened text-gold — AA on white */
}
.founder-quote__role {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ============================================================================
   Fused band (Part A): the evidence stats (light lavender) flow straight into
   the two-column belief + founder quote (cream) as ONE continuous band — the
   only seam is the background tint change; both regions share the container so
   they read as a single unit. (The old .why-gem__card / .founder-quote* rules
   above are now unused and can be pruned later.)
   ============================================================================ */

/* TOP — light-lavender stats strip */
.fusion__stats-wrap {
  background: var(--lavender-light);
  /* Step 13: medium-tall band — airier TOP so the transition line gets a quiet breath
     before the stats; bottom kept moderate leading into the belief block. */
  padding-top: clamp(2.5rem, 5vw, 3.75rem);
  padding-bottom: clamp(1.75rem, 4vw, 3rem);
}
/* Reuse the approved transition-line treatment as the band's lead-in; trim its
   large standalone padding so it sits directly above the stats (0,2,0 beats the
   base .hero-bridge rules, incl. the >=768px one). */
.fusion__stats-wrap .hero-bridge {
  padding-top: 0;
  padding-bottom: clamp(1.5rem, 4vw, 2.5rem);
}
.fusion__stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);        /* desktop: one row of four */
  gap: clamp(1rem, 2.5vw, 2rem);
  align-items: start;
}
.fusion-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.25rem;
  padding: 0 clamp(0.25rem, 1.5vw, 1rem);
}
.fusion-stat__figure {
  font-family: var(--font-head);                /* Lora */
  font-weight: 700;
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);      /* Phase 3: clearly BELOW the section-heading scale (--fs-h2 caps at 2.3rem) while staying the row's prominent display (was 2rem-2.9rem) */
  line-height: 1.05;
  color: var(--purple);                         /* #3A2A66 on lavender-light ≈ 9.5:1 */
}
.fusion-stat__label {
  margin-top: 0.15rem;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: clamp(0.98rem, 1.8vw, 1.1rem);
  line-height: 1.25;
  color: var(--purple-deep);                    /* ≈ 13:1 */
}
.fusion-stat__sub {
  max-width: 24ch;
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text-muted);                     /* ≈ 6:1 on lavender-light = AA */
}

/* "One Global Movement" emphasis (2026-08): the intentional resolution of the
   stats row - number ~18% larger than its siblings, number + label in deep
   gold #8A6222 (5.01:1 on the lavender band; brand #BB863F measured 2.92:1
   here and fails AA, per the task's escape hatch). Same rhythm, same grid. */
.fusion-stat--one .fusion-stat__figure {
  /* SHINE PASS (2026-08): larger still (~1.4x the sibling numbers) and
     metallic - a gold gradient clipped to the glyph, dark accessible ends
     with a champagne highlight streak, plus a soft gold glow that lifts it
     off the pale band. AA strategy: the flat #8A6222 below is BOTH the
     no-clip fallback and the gradient's dominant tone (measured 5.01:1 on
     the band; large-text bar is 3:1) - the light streak is a highlight
     accent, not the carrier. Static - nothing animates. */
  font-size: clamp(2.1rem, 3.6vw, 3rem);
  color: #8A6222;                                /* fallback + AA anchor */
  filter: drop-shadow(0 1px 6px rgba(187, 134, 63, 0.45));
}
@supports (-webkit-background-clip: text) {
  .fusion-stat--one .fusion-stat__figure {
    background: linear-gradient(163deg, #8A6222 0%, #8A6222 34%, #E9C97C 52%, #B0842F 68%, #8A6222 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
.fusion-stat--one .fusion-stat__label { color: #8A6222; font-size: clamp(1.078rem, 1.98vw, 1.21rem); }   /* 2026-08: +10% at EVERY stop of the shared clamp(0.98rem,1.8vw,1.1rem) - 19.36px at desktop, 17.25px at 375 - so this label alone grows and keeps its proportion to the siblings at all widths; colour/weight/tracking/gradient treatment untouched */
.fusion-stat__note {
  margin-top: 0.3rem;
  font-style: italic;
  font-size: 0.74rem;
  line-height: 1.35;
  color: var(--text-muted);                     /* muted placeholder flag, still AA */
}
/* "Explore More Evidence" — lower-right of the Evidence band; reuses the existing
   ghost-button styling (.btn--ghost: purple-bright outline/text, AA on lavender-light). */
.fusion__more { margin: clamp(1.25rem, 3vw, 1.75rem) 0 0; text-align: right; max-width: none; }
/* DEMOTED (2026-08): "Explore More Evidence" is a quiet underlined text link
   (same treatment as the demoted footer Join link) - the outlined pill is
   retired so it stops competing with the stats band. 44px tap via min-height. */
.fusion__more-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.2rem 0.1rem;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--purple);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.18s ease;
}
.fusion__more-link:hover { color: var(--purple-bright); }
.fusion__more-link:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 6px; }   /* max-width:none defeats the base p{max-width:72ch} cap — without it the 72ch box ended mid-container and the right-aligned button LOOKED centered; now it right-aligns to the section's full content width, flush with the 4th stat column's edge */
.fusion__more .btn > span { margin-left: 0.4rem; }   /* label<->arrow via margin (Safari <14.1 flex-gap) */

/* Stats reflow: 2x2 on tablet, single column on the smallest phones. */
@media (max-width: 899.98px) {
  .fusion__stats { grid-template-columns: repeat(2, 1fr); row-gap: clamp(1.5rem, 4vw, 2rem); }
}
@media (max-width: 479.98px) {
  .fusion__stats { grid-template-columns: 1fr; }
}

/* LOWER — cream two-column belief + founder quote */
.fusion__belief-wrap {
  background: var(--cream);
  padding-block: clamp(2.5rem, 5.5vw, 4rem);
}
.fusion__cols {
  display: grid;
  grid-template-columns: 1fr;                   /* stack: belief first, founder below */
  gap: clamp(2rem, 4vw, 2.75rem);
}
@media (min-width: 900px) {
  .fusion__cols {
    grid-template-columns: 0.85fr 1.3fr;         /* 2026-08 second rebalance: the compact icon trio needs less width - the founder quote takes the difference */
    gap: 0;                                      /* the divider + column paddings own the gap */
    align-items: start;
  }
  /* Faint vertical divider between the two columns (desktop only). */
  .fusion__belief {
    padding-right: clamp(2.25rem, 4vw, 3.5rem);
    border-right: 1px solid rgba(58, 42, 102, 0.14);
  }
  .fusion__founder { padding-left: 1.5rem; }   /* 2026-08 widen: explicit 24px off the divider (the old clamp resolved to 56px measured at a 1440px-wide viewport) - the quote takes the reclaimed width */
}

/* LEFT column — reuse the belief type, left-aligned for the two-column layout. */
.fusion__belief { text-align: left; }
.fusion__belief .believe__heading { margin-top: 0; }
.fusion__belief .believe__lede { margin-left: 0; margin-right: 0; max-width: 42ch; }
.fusion__belief .believe__pillars { margin-top: clamp(1rem, 2vw, 1.4rem); gap: clamp(0.35rem, 0.9vw, 0.55rem); }
/* 2026-08 horizontal tighten (>=640px only - phones keep the stacked rows):
   auto tracks shrink each item to its content and the trio centers as one
   compact, evenly-gapped group instead of stretching across 1fr tracks. */
@media (min-width: 640px) {
  .fusion__belief .believe__pillars { grid-template-columns: repeat(3, auto); justify-content: center; column-gap: clamp(1.1rem, 2.2vw, 1.9rem); }
}
/* Compact the pillar cards a touch for the narrower column (icons + text unchanged). */
.fusion__belief .pillar { padding: clamp(0.35rem, 0.8vw, 0.55rem) clamp(0.6rem, 1.4vw, 0.9rem); }   /* 2026-08 tighten: ~60% less vertical padding per item */
.fusion__belief .pillar__icon { width: 46px; height: 46px; }
.fusion__belief .pillar__icon svg { width: 24px; height: 24px; }
/* Pillar title + text inherit the unified --fs-h3 / --fs-body scale (no size override). */

/* PHONE (<640px — where the pillars stack single-column): each belief pillar
   becomes a compact horizontal row: small FIXED-size icon left, title + text
   stacked right, left-aligned, tight vertical rhythm (~40% shorter than the
   stacked layout). Grid with grid-gap (no flex gap, per compat rules); keeps
   the flat display treatment. Placed AFTER the .fusion__belief overrides so
   these equal-specificity rules win the cascade. Tablet/desktop untouched. */
@media (max-width: 639.98px) {
  .believe__pillars .pillar {
    display: grid;
    grid-template-columns: 28px auto;   /* auto (not 1fr) so the title track shrinks to the word - the icon+label pair can center as a unit (2026-08 mobile centering) */
    grid-column-gap: 0.85rem;
    grid-row-gap: 0.15rem;
    align-items: center;           /* icon + lone title sit centered (2026-08, subtitles removed) */
    justify-content: center;       /* 2026-08: phone view reads CENTERED, not left-flush rows */
    text-align: left;
    padding: 0.6rem 0;
  }
  .believe__pillars .pillar__icon {
    grid-column: 1;
    grid-row: 1;                   /* single row now - subtitles removed (2026-08) */
    width: 28px;                   /* explicit fixed size, not viewport-scaled */
    height: 28px;
    margin-bottom: 0;
    margin-top: 0.15rem;           /* optical alignment with the title cap */
    background: transparent;       /* flat: bare stroke icon, no badge circle */
    border-radius: 0;
  }
  .believe__pillars .pillar__icon svg { width: 26px; height: 26px; }
  .believe__pillars .pillar__title { grid-column: 2; }
  .believe__pillars .pillar__text { grid-column: 2; max-width: none; }
  .fusion__belief .believe__pillars { gap: 0.3rem; }

  /* 2026-08 mobile centering, Evidence band: "Explore More Evidence ->" sits
     centred on phones (desktop keeps the right-align from the base rule).
     nowrap keeps label + arrow on ONE line; the .arrowlink-text underline
     treatment is untouched. */
  .fusion__more { text-align: center; }
  .fusion__more-link { white-space: nowrap; }

}

/* RIGHT column — founder quote, portrait, attribution, button */
.fusion__founder {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
}
.fusion__founder-quote {
  margin: 0;
  font-family: var(--font-head);                /* Lora */
  font-style: italic;
  font-weight: 500;
  /* Sized for the four-decades excerpt (a multi-line quote, not the old
     one-liner): calmer scale + taller leading + a capped measure so it reads
     as an editorial passage and never crowds the photo/name/button below
     (the figure is a flex column, so they simply flow after it). */
  font-size: clamp(1.1rem, 1.6vw, 1.35rem);
  line-height: 1.55;
  max-width: 70ch;   /* 2026-08 widen: guard cap only - the column width is the real measure; 46ch was binding at tablet widths and starving the line length */
  color: var(--purple-deep);                    /* ≈ 13:1 on cream */
  /* text-wrap: balance removed 2026-08: balance evens every line at the
     SHORTEST equal length (~40ch here), visually re-narrowing the measure
     the widen pass just reclaimed - normal greedy wrap lets lines fill the
     full column width. */
}
/* Two stacked paragraphs (2026-08); the opening mark lives inline at the start
   of p1, the closing mark at the end of p2. */
.fusion__founder-quote p { margin: 0 0 0.7em; display: block; }
.fusion__founder-quote p:last-child { margin-bottom: 0; }
.fusion__founder-mark--close { margin-right: 0; margin-left: 0.08em; }
.fusion__founder-mark {
  font-family: var(--font-display);             /* Playfair */
  color: var(--gold);
  font-weight: 700;
  font-size: 1.5em;
  line-height: 0;
  margin-right: 0.1em;
  vertical-align: -0.32em;
}
.fusion__founder-person {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.fusion__founder-photo {
  flex: 0 0 auto;
  width: clamp(68px, 12vw, 88px);
  height: clamp(68px, 12vw, 88px);
  border-radius: 50%;
  object-fit: cover;                            /* no distortion */
}
.fusion__founder-cite { display: flex; flex-direction: column; gap: 0.1rem; }
.fusion__founder-name {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: var(--fs-h3);
  color: var(--purple-deep);
}
.fusion__founder-role {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--gold-deep);                      /* ≈ 5.2:1 on cream = AA */
}
.fusion__founder-org {
  font-size: 0.85rem;
  color: var(--text-muted);
}
/* 2026-08: signature row - person LEFT, quiet Founder's Vision arrow-link
   RIGHT, vertically centered; the link drops below full-row on phones. */
.fusion__founder-row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;   /* 2026-08 client direction: signature flush LEFT on the quote text's edge, button flush RIGHT on the quote's right edge - one shared container, one rectangle. (Replaces the earlier right-anchored flex-end pairing; the phone query below centres instead.) */
  flex-wrap: wrap;
}
.fusion__founder-row .fusion__founder-person { margin-right: 0; }   /* no independent inset - the row's left edge IS the signature's left edge (space-between owns the middle gap) */
/* Fit the pair on one line in the ~420px column: slightly smaller photo in
   this row + the long org line wraps (21ch) - measured 475px needed vs 418px
   available before this squeeze. */
.fusion__founder-row .fusion__founder-photo { width: 72px; height: 72px; }
.fusion__founder-row .fusion__founder-org { max-width: 150px; }   /* only the long org line wraps; the name stays one line */
.fusion__founder-row .fusion__founder-name { font-size: 1.05rem; }   /* signature scale beside the 72px photo (was --fs-h3 21.6px, too wide for the shared row) */
.fusion__founder-cta { margin: 0; }
.fusion__founder-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.2rem 0.1rem;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--purple);
  text-decoration: none;                 /* the inner .arrowlink-text carries the continuous underline */
  transition: color 0.18s ease;
}
.fusion__founder-link:hover { color: var(--purple-bright); }
.fusion__founder-link:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 6px; }
@media (max-width: 479.98px) {
  /* Button drops to its own full row: kill the shared-row gap and centre it
     (2026-08 mobile centering - matches the centred signature above). */
  .fusion__founder-row .fusion__founder-cta { flex-basis: 100%; margin-top: 0.75rem; margin-left: 0; text-align: center; }   /* 2026-08: signature->button gap 8px -> 12px (1.5x) above the quieter CTA */
}
/* 2026-08 mobile centering, founder block (same 639.98 phone query as the
   belief-pillars centering; placed AFTER the base founder rules so it wins
   the cascade - the earlier phone flex-start block that sat here was
   superseded by this, client direction). The quote container, the photo+
   signature pair, and the Founder's Vision button all centre on phones;
   tablet/desktop keep their own alignment from the base rules above.
   Quote wording/size untouched. */
@media (max-width: 639.98px) {
  .fusion__founder { align-items: center; }
  .fusion__founder-row { justify-content: center; }
  .fusion__founder-row .fusion__founder-person { margin-right: 0; }   /* no off-centre bias from the old signature->button gap */
  .fusion__founder-row .fusion__founder-cta { margin-left: 2.25rem; } /* the pair's gap, on the button side (480-639.98 shared row) */
  /* 2026-08 phone CTA refinement: quieter secondary action - side padding
     22.4px -> 16px, vertical 13.6px -> 8px; the 44px min-height is the tap
     floor (unpadded height would be ~39px). Font/border/radius/colour/label
     untouched. */
  .fusion__founder-cta .btn {
    padding: 0.5rem 1rem;
    min-height: 44px;
  }
  /* FOUNDER QUOTE MOBILE ALIGNMENT — change to `center` to fully centre the quote text */
  .fusion__founder-quote p { text-align: left; }
}
@media (max-width: 479.98px) {
  /* Button on its own full row (<480): kill the shared-row gap so the row
     above centres truly; the full-row button centres via its own text-align
     (set in the flex-basis:100% rule earlier). */
  .fusion__founder-row .fusion__founder-cta { margin-left: 0; }
}

/* ===================================================================
   12. Cinematic dark hero (homepage, ALL widths) — dark-to-light arc
   The page OPENS dark (the suffering) and brightens down the scroll
   (the hope): full-bleed footage — phones included — with a dark text
   scrim + dark top strip, light copy, white header items at the top
   state; the floating stats band below is the "dawn" handover to the
   bright page. These rules override the light-hero rules earlier in
   the sheet by file order at every width; phone-specific scrim shape
   and video framing sit at the end of this section.
   =================================================================== */
  /* TEXT-ANCHORED SCRIM (2026-08, replaces the left-anchored horizontal
     fog that reached 82% of the frame): one feathered plum POOL sits
     behind the headline + subtitle block (upper-left) and fades to
     NOTHING by 85% of its ellipse, so the footage plays clear across the
     rest of the frame. SIZED FOR THE WORST POSSIBLE FRAME BY
     CONSTRUCTION, not by sampling: at the 0.60 core even a PURE WHITE
     frame composites to 4.91:1 under white text (both hero elements are
     large text, 3.0 required) - no frame the footage can contain can
     break it. (A 39-step seek sweep of the real footage was attempted
     first; a headless pane returns undecoded black frames, so the
     guarantee was moved into the math; the bright final-scene still
     measures 5.8-6.6:1 as the realistic case.) Every corner of both text
     rects measures inside the 0.60 core at 1440px. The text shadows
     below stay as the second belt. */
  .hero--editorial::after {
    background-image: radial-gradient(75% 80% at 30% 38%,
      rgba(20, 14, 40, 0.62) 0%,
      rgba(20, 14, 40, 0.60) 60%,
      rgba(20, 14, 40, 0) 85%);
  }

  /* Copy flips light-on-dark. Soft layered shadows (v3 pattern) insure
     the tails where the scrim thins. Entrance choreography untouched. */
  .hero--editorial .hero__headline {
    color: var(--white);
    /* Subtle layered glow — a tight dark edge + two soft haloes — for depth and
       legibility over the video, while the headline stays powerful white. */
    text-shadow: 0 1px 3px rgba(20, 14, 40, 0.6), 0 3px 22px rgba(20, 14, 40, 0.55), 0 0 46px rgba(20, 14, 40, 0.32);
  }
  /* Accent: soft light lavender — purple-bright is too dark on dark.
     #CDBBEB holds ≥3:1 large-text through the scrim even vs pure white. */
  .hero--editorial .hero__line--accent { color: #CDBBEB; }
  /* Subtitle — a two-line hierarchy for emotional impact (line 1 is the hopeful,
     human focus). Both lines sit in the strengthened left scrim; the layered
     shadow gives each glyph a dark halo so the light warm/cool tints stay legible
     over the footage's bright tail (the owner-approved v3 shadow-carried pattern).
     Tested over both the dark opening frame (very high contrast) and the bright
     sunrise frame (scrim + shadow carry it). */
  .hero--editorial .hero__subtitle {
    color: var(--white);   /* fallback; the two lines set their own tones below */
    text-shadow: 0 1px 2px rgba(20, 14, 40, 0.92), 0 1px 10px rgba(20, 14, 40, 0.72), 0 3px 22px rgba(20, 14, 40, 0.5);
  }
  /* Short, thin gold accent rule between the headline and the subtitle. */
  .hero--editorial .hero__subtitle::before {
    content: "";
    display: block;
    width: 2.75rem;
    height: 2px;
    margin-bottom: 0.9rem;
    border-radius: 2px;
    background: var(--gold);                    /* #BB863F — a subtle premium editorial accent */
    box-shadow: 0 1px 6px rgba(20, 14, 40, 0.5);
  }
  /* Line 1 — larger, warm soft cream-gold, serif italic: the hopeful, human line. */
  .hero--editorial .hero__subtitle-line:first-child {
    font-size: clamp(1.4rem, 2.7vw, 1.95rem);   /* larger than line 2 — the emotional focus */
    font-style: italic;
    color: #ECD6AE;                             /* soft champagne — a light, legible tint of brand gold #BB863F */
    margin-bottom: 0.1rem;                      /* tight — the two lines read as ONE flowing paragraph */
  }
  /* Line 2 — same serif italic as line 1, sentence case, slightly smaller, in a
     soft lavender-cream, tight beneath line 1: one continuous subtitle (not a
     separate tagline/kicker). */
  .hero--editorial .hero__subtitle-line:last-child {
    font-family: var(--font-head);              /* Lora serif italic — same family as line 1 */
    font-style: italic;
    font-weight: 500;
    font-size: clamp(1.15rem, 2.2vw, 1.55rem);  /* slightly smaller than line 1 */
    line-height: 1.3;
    letter-spacing: normal;                     /* remove the small-caps tracking */
    text-transform: none;                       /* sentence case */
    color: #E7DEEA;                             /* soft lavender-cream */
  }


  /* Scroll cue rides the dark footage from tablet width up. */
  .hero__scroll { color: var(--white); }

  /* Header top state (transparent over the dark strip): every visible
     control flips white — including the tablet cluster's icons and
     hamburger — and eases back (~0.25s) to the existing solid state on
     scroll. The crest keeps its real colours in every state (NO filter); only
     the white HTML wordmark carries the "white on dark" treatment. */
  .site-header--floating .header-search,
  .site-header--floating .lang-switcher__button,
  .site-header--floating .header-signin { transition: color 0.25s ease, border-color 0.25s ease; }
  .site-header--floating:not(.is-scrolled) .header-search,
  .site-header--floating:not(.is-scrolled) .lang-switcher__button,
  .site-header--floating:not(.is-scrolled) .header-signin { color: var(--white); }
  .site-header--floating:not(.is-scrolled) .nav-toggle-bar { background: var(--white); }

/* Video framing per breakpoint: the 16:9 footage keeps its key subject (the
   seated/rising woman) on the right third. Wide frames show enough at the
   default center; smaller frames slide toward her. */
@media (min-width: 760px) and (max-width: 1023.98px) {
  .hero--editorial .hero__video { object-position: 70% center; }   /* tablet portrait */
}
@media (max-width: 759.98px) {
  .hero--editorial .hero__video { object-position: 78% center; }   /* phone: woman + sunrise */
  /* Phone scrim (2026-08, reshaped): the copy spans nearly the full width
     of the top ~44%, so the scrim is a TOP BAND that fades to NOTHING by
     68% - the lower third of the footage plays clear (the old band held
     0.4 fog to the very bottom). Same 0.60 pure-white-frame guarantee as
     the desktop pool (4.91:1 under white text); the doorways below carry
     their own self-contained per-column scrims. */
  .hero--editorial::after {
    background-image: linear-gradient(180deg,
      rgba(20, 14, 40, 0.62) 0%,
      rgba(20, 14, 40, 0.60) 46%,
      rgba(20, 14, 40, 0) 68%);
  }
}

/* (The old phone letterbox/zoom "is-panning" opening was removed: it existed to
   reveal a sentence burned into the previous hero video. The footage is now
   text-free and the opening is coded (.hero__opening), so phones just use the
   standard object-fit:cover framing.) */

@media (min-width: 1400px) {
  /* Desktop nav links + EN pill at the top state. TOP-LEVEL links only
     (> ul > li > a): the broader "> ul a" also caught the dropdown-panel
     links and painted them white on the white panel — invisible menus.
     Hover is the same minimal label fade as the rest of the nav (Part A) — no
     veil, box or underline. */
  .site-header--floating .primary-nav > ul > li > a,
  .site-header--floating .nav-menu__toggle { transition: color 0.25s ease, opacity 0.2s ease; }
  .site-header--floating:not(.is-scrolled) .primary-nav > ul > li > a,
  .site-header--floating:not(.is-scrolled) .nav-menu__toggle { color: var(--white); }
  .site-header--floating:not(.is-scrolled) .primary-nav > ul > li > a:hover,
  .site-header--floating:not(.is-scrolled) .nav-menu__toggle:hover {
    opacity: 0.7;
    color: var(--white);
  }
  .site-header--floating:not(.is-scrolled) .lang-switcher__button { border-color: rgba(255, 255, 255, 0.65); }
  .site-header--floating:not(.is-scrolled) .header-divider { background: rgba(255, 255, 255, 0.45); }
}

@media (prefers-reduced-motion: reduce) {
  .site-header--floating .header-search,
  .site-header--floating .lang-switcher__button,
  .site-header--floating .header-signin,
  .site-header--floating .primary-nav > ul a,
  .site-header--floating .nav-menu__toggle { transition: none; }   /* instant state swap */
}

/* --- Pinned masthead (inner pages) ------------------------------------------
   Same fixed positioning as the homepage's floating header, but always solid
   (cream on mobile, white on desktop via the editorial rules) so navigating
   between pages never jumps. Because the header sits out of flow, <main> is
   padded down by the measured header height (ui.js sets --header-h; the
   static values are a close no-JS fallback). */
.site-header--pinned {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
}
/* Sibling selector, not body:has() — :has is Safari 15.4+; without this rule
   inner-page content would sit hidden UNDER the fixed header on older Safari.
   The header and <main> are body-level siblings on every page. */
.site-header--pinned ~ main { padding-top: var(--header-h, 4.35rem); }
@media (min-width: 1400px) {
  .site-header--pinned ~ main { padding-top: var(--header-h, 3.9rem); }
}

/* Mobile menu "Join Us" — the pill joins the open hamburger panel (the top-bar
   pill stays desktop-only). Hidden wherever the desktop row shows the real one. */
.header-join--menu {
  display: inline-flex;
  min-height: 44px;                /* comfortable tap target in the panel */
  margin: 0.35rem 0.4rem 0.5rem;
}
/* 2026-08 centering fix: the drawer's shared link rule (.primary-nav a,
   specificity 0,1,1) beats both .header-join rules (0,1,0) and forces
   display:block - so the pill rendered as a full-width LEFT-aligned list
   item and the base rule's flex centering never applied. This 0,2,0 rule
   outranks it: still a full-width block-level box (same size, zero layout
   shift), but the label is centred both ways. Drawer-scoped - the desktop
   pill never carries --menu. */
.primary-nav .header-join--menu {
  display: flex;
  align-items: center;             /* vertical centring within the >=44px box */
  justify-content: center;         /* horizontal centring */
  text-align: center;
}
@media (min-width: 1400px) {
  .nav-item--join { display: none; }
}

/* ===================================================================
   13. Plum-glass sticky header — homepage scrolled + all inner pages
   The settled header is semi-transparent deep plum (rgba of --purple-deep =
   rgb(46,33,80)) with a 12px backdrop blur + a light hairline; a more opaque
   solid is the no-backdrop-filter fallback. Header items stay WHITE (never
   purple) over it, and it shrinks ~17% vs the top state. AA: white over the
   0.75 glass composited on the LIGHTEST band it floats over (white) ≈ 6.5:1
   (pass); over cream/lavender/dark bands it only darkens (higher). The
   homepage TOP state stays transparent with white items (§12). Inner pages
   (.site-header--pinned) wear this glass from the start (no transparent state).
   =================================================================== */

/* ============ Three-stage progressive frosted glass (scroll-driven) ==========
   ui.js toggles .is-scrolled (past the first threshold, 80px) and then
   .is-scrolled-deep (past the second, 560px) on the header. The bar background
   deepens in three stages; the LOGO never changes (constant size, full colour)
   — ONLY this background does. Tint is the mockup's deep purple #4B2E83
   (rgb 75,46,131) — deep enough that white items stay AA even at ~72%; never
   the rejected light #9E7AC8. Each stage has a SOLID fallback first, then an
   @supports layer adds the real backdrop blur WITH the -webkit- prefix.
     STAGE 1 (top)               solid #4B2E83, no blur, fully opaque
     STAGE 2 (.is-scrolled)      ~82% purple + blur 12px + 1px white hairline
     STAGE 3 (.is-scrolled-deep) ~72% purple + blur 18px (visibly stronger)
   Applies to both variants (floating homepage + pinned inner pages). */
.site-header--editorial {
  transition: background-color 0.3s ease, -webkit-backdrop-filter 0.3s ease,
              backdrop-filter 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

/* TWO-STATE HEADER (client direction — unified glass):
   TRANSPARENT STATE — homepage at/near the top (intro + the whole video-watching
     period): COMPLETELY INVISIBLE bar; WHITE logo; light nav items. Untouched.
   GLASS STATE — scrolled past HEADER_FROST_AT (ui.js), and ALL inner pages from
     the top: a NEAR-TRANSPARENT watery tint (--glass-bg-header, tokens.css) with
     no blur and no inner gradient — per-glyph shadows carry the text. Nav
     items stay light; the LOGO cross-fades to the BLACK wordmark on scroll
     (client direction — see the .brand-logo rules).
   .is-scrolled-deep is kept in sync by JS for compatibility but renders
   identically to .is-scrolled; .is-intro-dark only suppresses the glass if the
   user scrolls mid-intro. */
.site-header--floating {
  background: transparent;                      /* STATES A + B — genuinely no bar */
  border-bottom: 1px solid transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.site-header--pinned,
.site-header--floating.is-scrolled,
.site-header--floating.is-scrolled-deep,
.site-header--pinned.is-scrolled,
.site-header--pinned.is-scrolled-deep {
  /* STATE 2 — FLAT TRANSLUCENT PURPLE (2026-08 deepen, client direction): one
     even, uniform tint across the whole bar — the deep brand purple #4B2E83 at
     72%, the MINIMUM that carries white nav text to AA over the lightest
     content it can float above (measured 4.74:1 composited on pure white)
     while still clearly reading as see-through. Same violet hue family as the
     old 0.14 "water" whisper (which measured 1.24:1 - glyph shadows were doing
     all the work). NO blur, NO gradient, and the old soft drop shadow is
     REMOVED per direction - only the hairline bottom edge remains. The token
     --glass-bg-header is deliberately NOT touched: the homepage doorway panels
     still share it; this deeper tint is scoped to the header alone. */
  /* RESTORED 2026-08 (client direction, reference image; recovered verbatim
     from commit bbc7f74): LIGHT FROSTED LAVENDER on the solid/scrolled state
     of EVERY page - homepage and inner pages now share one treatment (the
     purple rgba(75,46,131,0.72) state and the blur-less 0.50 lavender pass
     are both replaced). SOLID --lavender #F2EEF8 is the no-blur fallback
     (WeChat / old engines read a clean matte panel - a translucent tint
     WITHOUT blur lets hard edges ghost through, which the reference's soft
     show-through is not); the @supports block below layers the true frosted
     glass: 0.80 tint + 16px blur, both prefixes.
     ⚠️ CONTRAST (measured, reported, NOT gated - client's decision): white
     nav items ~1.1:1 on this pale panel; the black wordmark ~15:1. Item
     colours are scope-locked and unchanged. The homepage's transparent
     over-hero state and the .is-intro-dark suppressor are untouched and
     still outrank this by specificity/order. */
  background-color: #F2EEF8;
  border-bottom: var(--glass-border);
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
@supports ((-webkit-backdrop-filter: blur(2px)) or (backdrop-filter: blur(2px))) {
  .site-header--pinned,
  .site-header--floating.is-scrolled,
  .site-header--floating.is-scrolled-deep,
  .site-header--pinned.is-scrolled,
  .site-header--pinned.is-scrolled-deep {
    background-color: rgba(242, 238, 248, 0.80);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}
/* REPLACED 2026-08 - the short-lived homepage-only translucent 0.50 no-blur
   override; the unified frosted rule above now covers the homepage's scrolled
   state too. Retained for restore:
.site-header--floating.is-scrolled,
.site-header--floating.is-scrolled-deep {
  background-color: #F2EEF8;
  background-color: rgba(242, 238, 248, 0.5);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
*/
/* (2026-08: a short-lived unification rule here composited the pinned bar's
   tint over a constant WHITE underlay — it made every inner header identical
   but read as a SOLID bar, so it was reverted per client direction. Inner
   pages use the plain translucent --glass-bg-header tint from the state-2 rule
   above, identical CSS on every inner page; what shows through is the page
   beneath. The homepage (--floating) was never affected either way. */

/* ============ FROSTED GLASS - ALL PAGES (2026-08) ============================
   The homepage trial's scrolled-state glass, promoted SITE-WIDE per client
   authorisation (appearance values only - markup, heights, nav and behaviour
   untouched): the back-to-top button's own lavender rgb(199,166,241) carried
   up to the bar. Inner pages (.site-header--pinned) wear it from the start,
   exactly as they wore the previous 0.80 lavender; the homepage keeps its own
   states - transparent at top, this glass once .is-scrolled, and the
   .is-intro-dark suppressor (three classes) still outranks everything here.
   Three glass elements:
     1. TINT   rgba(199,166,241,0.30) - high transparency, lavender visible
     2. BLUR   11.5px, both prefixes, inside @supports; solid #C7A6F1 fallback
     3. EDGE   inset 1px white 0.40 top rim (inset shadow - no layout shift),
               1px white 0.22 bottom hairline, and a narrow white 0.14->0
               vertical gradient (depth in the material, fading by 60% of the
               bar height). */
.site-header--pinned,
.site-header--pinned.is-scrolled,
.site-header--pinned.is-scrolled-deep,
.site-header--floating.is-scrolled,
.site-header--floating.is-scrolled-deep {
  background-color: #C7A6F1;                     /* solid fallback for engines without blur/rgba layering */
  /* 2026-08 +15% STRENGTHENING (client direction) across all three glass
     components - tint colour/alpha deliberately UNCHANGED:
       gradient 0.12 -> 0.14, rim 0.35 -> 0.40, blur 10px -> 11.5px (under
       the 18px Safari cap). */
  background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0) 60%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.40);   /* lit glass rim along the top edge */
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
}
@supports ((-webkit-backdrop-filter: blur(2px)) or (backdrop-filter: blur(2px))) {
  .site-header--pinned,
  .site-header--pinned.is-scrolled,
  .site-header--pinned.is-scrolled-deep,
  .site-header--floating.is-scrolled,
  .site-header--floating.is-scrolled-deep {
    background-color: rgba(199, 166, 241, 0.30);
    -webkit-backdrop-filter: blur(11.5px);
    backdrop-filter: blur(11.5px);
  }
}

/* STATE A — intro active: the header stays COMPLETELY INVISIBLE (zero bar) over the
   dark opening; only the logo swap below reacts to this class. The .is-scrolled
   compounds keep it invisible even if the user scrolls mid-intro. */
.site-header--floating.is-intro-dark,
.site-header--floating.is-intro-dark.is-scrolled,
.site-header--floating.is-intro-dark.is-scrolled-deep {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-bottom-color: transparent;
  box-shadow: none;
}

/* STACKED LOGO PAIR (all pages share the markup): the BLACK-wordmark original is
   the default everywhere; the WHITE variant sits absolutely over it (same box —
   ZERO layout shift). The swap is SCROLL-DRIVEN, matched to the frost: while the
   homepage header is TRANSPARENT (:not(.is-scrolled) — the intro AND the whole
   time the video plays at the top, including the reduced-motion/blocked-autoplay
   poster case, where the top is equally dark) the WHITE logo shows; crossing
   HEADER_FROST_AT flips .is-scrolled, so the frost and the ~600ms white -> black
   cross-fade arrive together. Inner pages (--pinned) never match: black from the
   top. The BLACK logo keeps NO glow, halo, plate or shadow in any state; the
   WHITE twin carries a soft per-glyph drop-shadow (client direction after the
   hero top wash was removed — it replaces that strip as the ONLY legibility aid,
   hugging the alpha channel, no plate/tint over the video). */
.brand { position: relative; flex-shrink: 0; }
.brand-logo--white {
  /* The markup carries `hidden` as a STALE-CSS SAFETY NET: if this stylesheet ever
     fails to load (or an old cached copy without these rules is served), the white
     twin simply doesn't render — the two-logos-side-by-side failure is impossible
     at the markup level. When THIS stylesheet is live, display:block re-enables it
     (author rules beat the UA's [hidden] default) and the stack works as designed.
     ZERO SELF-SIZING (Safari overlap fix): the white twin is bound to the black
     logo's box on every edge — width/height 100%, no auto anything — so no engine
     can resolve it wider than the box the nav aligns against. Both files are
     exactly 1600x715, so object-fit:contain fills the box perfectly (no visible
     shrink); object-position keeps it pinned left like the black one. */
  display: block;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;   /* longhand, not `inset` (Safari <14.1) */
  width: 100%;
  height: 100%;
  max-width: none;                         /* the box, not the ratio cap, is the constraint here */
  object-fit: contain;
  object-position: left center;
  opacity: 0;
  /* Localized legibility aid (replaces the removed hero top wash): a tight dark
     edge + a faint lift following the logo's OWN alpha channel — the video around
     the mark stays untouched. REFINED with the nav text (client: premium, no
     visible halo — was 0.55 3px + 0.35 12px). Worst-case (pure-white frame) the
     composited glyph edge reads ≈5:1 against the white mark (graphic floor 3:1). */
  filter: drop-shadow(0 1px 2px rgba(20, 14, 40, 0.5)) drop-shadow(0 2px 6px rgba(20, 14, 40, 0.18));
}
.brand-logo--black,
.brand-logo--white { transition: opacity 0.6s ease; }   /* the transparent<->frosted logo cross-fade */
.site-header--floating:not(.is-scrolled) .brand-logo--black { opacity: 0; }
.site-header--floating:not(.is-scrolled) .brand-logo--white { opacity: 1; }
/* Mid-intro edge case: if the user scrolls DURING the intro, the header stays
   invisible (see the .is-intro-dark rules above) — keep the logo white with it. */
.site-header--floating.is-intro-dark .brand-logo--black { opacity: 0; }
.site-header--floating.is-intro-dark .brand-logo--white { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .brand-logo--black, .brand-logo--white { transition: none; }
}

/* WHITE items in BOTH states (transparent top + near-transparent water): the dark
   text/glyph shadows now apply everywhere — over the video they carry the top
   state, and on the watery bar they alone carry AA over the palest band the
   header can float over (the old inner top gradient is gone). */
@media (min-width: 1400px) {
  .site-header--floating .primary-nav > ul > li > a,
  .site-header--floating .nav-menu__toggle,
  .site-header--floating .lang-switcher__label,
  .site-header--pinned .primary-nav > ul > li > a,
  .site-header--pinned .nav-menu__toggle,
  .site-header--pinned .lang-switcher__label {
    /* REFINED (client: premium, no visible halo): one crisp low-opacity edge + a
       whisper of ambient lift — replaces the old heavy triple shadow
       (0.8 / 0.55 6px / 0.35 14px). AA floor: the 0.55 tight edge is as subtle as
       worst-case allows — composited on a pure-white frame the glyph edge reads
       ≈5.5:1 (≥4.5 AA); at 0.45 it drops to ≈3.9:1 and fails. */
    text-shadow: 0 1px 2px rgba(20, 14, 40, 0.55), 0 1px 8px rgba(20, 14, 40, 0.18);
  }
}
.site-header--floating .header-search__icon,
.site-header--floating .lang-switcher__globe,
.site-header--floating .header-signin__icon,
.site-header--pinned .header-search__icon,
.site-header--pinned .lang-switcher__globe,
.site-header--pinned .header-signin__icon {
  filter: drop-shadow(0 1px 2px rgba(20, 14, 40, 0.55));   /* refined with the nav text (was 0.65); graphics floor 3:1 holds at ≈3.9:1 worst-case */
}
.site-header--floating .nav-toggle-bar,
.site-header--pinned .nav-toggle-bar {
  box-shadow: 0 1px 2px rgba(20, 14, 40, 0.5);
}

/* GLASS STATE — WHITE items (same as the top state) on the near-transparent watery
   bar; the per-glyph shadows above carry AA (no gradient, no blur). */
.site-header--floating.is-scrolled .header-search,
.site-header--floating.is-scrolled .header-tools .lang-switcher__button,
.site-header--floating.is-scrolled .header-signin,
.site-header--pinned .header-search,
.site-header--pinned .header-tools .lang-switcher__button,
.site-header--pinned .header-signin { color: var(--white); }   /* .header-tools raises specificity so EN follows the glass state */
.site-header--floating.is-scrolled .nav-toggle-bar,
.site-header--pinned .nav-toggle-bar { background: var(--white); }
/* Active-page link: white in every state (transparent top + glass).
   TOP-LEVEL ONLY (> ul > li > a): the broader ".primary-nav a[aria-current]"
   also matched links INSIDE the dropdown panel and painted them white on the
   panel's white background — an invisible item on whichever page the nav marks
   as current (same class of bug the top-level colour rules already avoid). */
.site-header--floating .primary-nav > ul > li > a[aria-current="page"],
.site-header--pinned .primary-nav > ul > li > a[aria-current="page"] { color: var(--white); }

/* (Logo swap RESTORED per client direction: the scroll-driven white -> black
   cross-fade rules earlier in the sheet are authoritative again — white at the
   transparent top, BLACK on the glass, black-from-top on inner pages. Only the
   glass BACKGROUND kept the panels-matching treatment.) */

/* Smooth ~0.25s height/logo shrink, in step with the background change. The
   crest tracks --crest-h (height) and the wordmark tracks it via font-size. */
.site-header--editorial .header-inner { transition: padding-block 0.25s ease; }
/* Logo size is frozen on scroll — the crest/wordmark keep a constant --crest-h in
   every state, so no height animation (only the header padding + glass background
   transition on scroll). */

@media (min-width: 1400px) {
  /* GLASS STATE: desktop nav + utilities stay WHITE on the dark translucent glass
     (one treatment across both states). "Join the Movement" keeps its own pill. */
  .site-header--floating.is-scrolled .primary-nav > ul > li > a,
  .site-header--floating.is-scrolled .nav-menu__toggle,
  .site-header--pinned .primary-nav > ul > li > a,
  .site-header--pinned .nav-menu__toggle { color: var(--white); }
  .site-header--floating.is-scrolled .primary-nav > ul > li > a:hover,
  .site-header--floating.is-scrolled .nav-menu__toggle:hover,
  .site-header--pinned .primary-nav > ul > li > a:hover,
  .site-header--pinned .nav-menu__toggle:hover { opacity: 0.7; color: var(--white); }   /* Part A: label fade, no veil box */
  .site-header--floating.is-scrolled .lang-switcher__button,
  .site-header--pinned .lang-switcher__button { border-color: rgba(255, 255, 255, 0.55); }
  .site-header--floating.is-scrolled .header-divider,
  .site-header--pinned .header-divider { background: rgba(255, 255, 255, 0.4); }

  /* Settled header shrinks (crest + tighter padding) but keeps some top
     breathing room; the top->scroll compaction feel is preserved. */
  .site-header--floating.is-scrolled .header-inner,
  .site-header--pinned .header-inner { padding-block: 0.6rem; }
  /* Logo size frozen on scroll — no --crest-h change here (see below). */

  /* ---- DROPDOWN PANEL COLOUR LOCK (self-contained; must stay last) --------
     The dropdown is its own LIGHT surface (white panel, §6), so its text is
     DARK on every page and in BOTH header states. The header-state rules above
     correctly paint the BAR's items white over the video/glass — this lock
     stops any of them (now or later) leaking into the panel and producing a
     white-on-white menu. The [aria-current] twin is listed explicitly so it
     outranks the active-page rule by specificity, not just source order.
     Mobile is deliberately NOT included: inside the open hamburger the panel is
     solid plum and its links are white by design. */
  .site-header .primary-nav .nav-menu a,
  .site-header .primary-nav .nav-menu a[aria-current="page"] {
    color: var(--purple);                 /* #3A2A66 on white ≈ 11.7:1 — AAA */
  }
  .site-header .primary-nav .nav-menu a:hover,
  .site-header .primary-nav .nav-menu a[aria-current="page"]:hover {
    color: var(--purple-bright);          /* #6B4FA0 on lavender ≈ 5.6:1 — AA */
    opacity: 1;                           /* never inherit the bar's hover fade */
  }
}

@media (max-width: 1399.98px) {
  /* ~17% shorter settled header on mobile. The 44x44 utility icons floor the
     bar height once the logo shrinks under them, so the reduction comes from
     tighter padding — the icons stay full 44px tap targets. */
  .site-header--floating.is-scrolled .header-inner,
  .site-header--pinned .header-inner { padding-block: 0.55rem; }
  /* Logo size frozen on scroll — no --crest-h change here. */

  /* Opened hamburger menu (COOKIE-BANNER MATCH, GEM Aug 2026): the panel is the
     banner's lavender (#F2EEF8, set on .primary-nav.is-open in §6) and the nav
     text takes the banner's heading/body colour (--purple-deep). Scoped to the
     OPEN drawer only - the header's inline nav (>=1400px) has its own rules and
     is untouched. The Join button is EXCLUDED (its own purple/white styling
     stands); chevrons are pinned WHITE per client instruction below. The hover
     veil flips to the banner's dark 0.10 veil - the old white 0.10 (and white
     hover text) would be invisible on the light panel. */
  .site-header--editorial .primary-nav.is-open a:not(.header-join),
  .site-header--editorial .primary-nav.is-open .nav-menu__toggle { color: var(--purple-deep); }
  .site-header--editorial .primary-nav.is-open a:not(.header-join):hover,
  .site-header--editorial .primary-nav.is-open .nav-menu__toggle:hover { background: rgba(46, 33, 80, 0.10); color: var(--purple-deep); }
  .site-header--editorial .primary-nav.is-open a[aria-current="page"]:not(.header-join) { color: var(--purple-deep); }
  /* Chevrons stay WHITE (client decision) - they would otherwise inherit the
     new dark currentColor from their toggle. */
  .site-header--editorial .primary-nav.is-open .nav-menu__caret { color: var(--white); }
  /* The Join button previously took its white label from the drawer's old
     blanket `a` rule; excluded from the dark text above, it needs the white
     restored explicitly (solid purple button, white label - unchanged look). */
  .site-header--editorial .primary-nav.is-open a.header-join { color: var(--white); }
}

@media (prefers-reduced-motion: reduce) {
  .site-header--editorial .header-inner,
  .site-header--editorial .brand-crest,
  .site-header--editorial .brand-wordmark { transition: none; }
}

/* --- Experts page: card language aligned with the homepage ------------------
   Same resting shadow and hover depth as the homepage tiles/CTA boxes. */
.expert-tile { box-shadow: 0 2px 10px rgba(46, 33, 80, 0.08); }
.expert-tile:hover { box-shadow: 0 10px 24px rgba(46, 33, 80, 0.16); }
.expert-tile:focus-visible { box-shadow: 0 10px 24px rgba(46, 33, 80, 0.16); }
.board-card { box-shadow: 0 2px 10px rgba(46, 33, 80, 0.08); }
@media (prefers-reduced-motion: reduce) {
  .expert-tile { transition: border-color 0.15s ease, box-shadow 0.15s ease; }
  .expert-tile:hover { transform: none; }
  .expert-tile:focus-visible { transform: none; }
}

/* Mobile hero still (poster/CSS fallback only — reduced-motion, data-saver,
   or a failed video load): match the video's phone framing so the women AND
   the golden light stay in the 375px-portrait crop. */
@media (max-width: 759px) {
  .hero--editorial { background-position: 78% center; }
}

/* ===================================================================
   14. Relocated homepage content on inner pages
   The feature-card row ("Explore GEM", above the footer on our-story /
   experts / get-involved / support). (The Latest Insights band's rules
   were DELETED Aug 2026 with the sample section on the Publications
   page - the homepage still carries a [hidden] copy of that band's
   markup; restore the rules from git history before un-hiding it.)
   =================================================================== */

/* ===================================================================
   16. Safari 14 compatibility fallbacks
   Modern browsers support aspect-ratio and never enter this block, so
   Chrome/Firefox rendering is untouched. Safari 14 drops aspect-ratio;
   the two card types below hold ONLY absolutely-positioned children, so
   without a ratio they collapse to zero height — percentage padding
   recreates the same box (padding % resolves against width).
   =================================================================== */
@supports not (aspect-ratio: 1 / 1) {
  .feature-card--editorial { padding-bottom: 125%; }      /* Part B: 4:5 portrait (was 66.667% = 3:2) */
  .gateway-card { padding-bottom: 125%; }                 /* 4:5 */
  @media (min-width: 1100px) {
    .gateway-card { padding-bottom: 133.333%; }           /* 3:4 (desktop override) */
  }
}


/* ===================================================================
   Cookie consent banner (site-wide; built by ui.js on first visit only).
   Brand direction: soft LAVENDER card, rounded, light and quiet — not a
   cold legal popup. Fixed at the bottom (never a blocking modal), z=120:
   above the FABs (90) and header (100) until a choice is made. Buttons
   reuse the site button system: .btn--primary purple; .btn--ghost gets a
   WHITE fill here per the spec ("white background, outlined"); tertiary is
   a text link. position:fixed = zero layout shift. AA on lavender: heading
   purple-deep ~12.6:1, body/labels --text ~13:1, links purple-bright 5.6:1,
   legal line --text (not muted) for small-size safety.
   =================================================================== */
/* RESTYLED AGAIN 2026-08 (client direction): the full-width bottom bar is now a
   COMPACT CARD pinned to the BOTTOM-RIGHT corner, rounded.
   SOLID + LIGHTER 2026-08 (client decision): the translucent glass recipe is
   gone — transparency was what blocked the requested lightening (at 0.72 alpha
   the max AA-passing lighten was 2.7%). The card is now SOLID #816CA8: the
   original rgba(75,46,131) base lightened 30% toward white per channel
   (75+0.3*180=129, 46+0.3*209=108.7 -> 108 [floored: 109 rounds to 4.48:1,
   just under AA; 108 = 4.52:1 passes], 131+0.3*124=168.2 -> 168). Blur and its
   @supports wrapper removed entirely. Being solid, the card reads identically
   over any page ground. All white text/labels on #816CA8 = 4.52:1 AA; primary
   button stays white with purple-deep label. FOCUS RINGS on the card switched
   to WHITE (4.52:1) — gold measures 1.42:1 and the global --focus ring 2.73:1
   on this lighter ground, both invisible; prefs-panel inputs keep gold on
   their WHITE inset (3.18:1 non-text). position:fixed = zero layout shift;
   z=120 above FABs + header. */
.cookie-banner {
  position: fixed;
  right: clamp(12px, 2vw, 24px);
  bottom: clamp(12px, 2vw, 24px);
  left: auto;
  z-index: 120;
  /* 2026-08 further reduction, HEIGHT-FIRST: the wording is fixed and the body
     is pinned at the 14px consent floor, so NARROWING would grow the text
     block TALLER - width stays 300 by design and the cuts land on heights:
     tighter paddings/margins, smaller heading, 14px button labels with
     slimmer padding so both action buttons share ONE row (the old 16px pair
     wrapped to two). 44px hit floors everywhere are untouched. */
  width: min(300px, calc(100vw - 24px));
  /* 2026-08 DRAWER TREATMENT (client direction; supersedes the 0.65 no-blur
     pass, which itself replaced the solid #816CA8 + white-text card): the
     mobile drawer's exact recipe - SOLID #F2EEF8 no-blur fallback here, and
     the @supports block below layers rgba(242,238,248,0.80) + blur(18px),
     both prefixes, matching the drawer line for line. Text stayed
     --purple-deep in the earlier pass, so the old "no transparency passes
     with white text" constraint no longer applies: purple-deep measures
     13.4:1 composited over pure-white page content at 0.80. */
  background: #F2EEF8;
  border: 1px solid rgba(46, 33, 80, 0.18);   /* hairline flipped dark - the old white one vanishes on a light card */
  border-radius: 16px;
  box-shadow: 0 18px 44px -16px rgba(20, 12, 40, 0.55);
  padding: 0.5rem 0.65rem 0.45rem;   /* 2026-08 demotion pass: shaved again (was 0.6/0.75/0.55); heights govern, wording is fixed */
  opacity: 0;
  transform: translateY(16px);
  visibility: hidden;              /* not clickable before its entrance */
  transition: opacity 0.45s ease, transform 0.45s ease, visibility 0s linear 0.45s;
}
@supports ((-webkit-backdrop-filter: blur(2px)) or (backdrop-filter: blur(2px))) {
  .cookie-banner {
    background: rgba(242, 238, 248, 0.80);   /* --lavender at 0.80 + 18px blur = the drawer's frosted glass */
    -webkit-backdrop-filter: blur(18px);
    backdrop-filter: blur(18px);
  }
}
/* While the card is up, the corner FABs LIFT above it (ui.js sets the measured
   --cookie-bar-h and the body class; both clear on dismissal) — the card sits
   in the FAB corner, so the lift keeps back-to-top / chatbot tappable. */
body.has-cookie-bar .chatbot-fab { bottom: calc(var(--fab-inset) + var(--cookie-bar-h, 150px) + 24px); }
body.has-cookie-bar .to-top { bottom: calc(var(--fab-inset) + var(--fab-size) + var(--fab-gap) + var(--cookie-bar-h, 150px) + 24px); }
.cookie-banner.is-shown {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity 0.45s ease, transform 0.45s ease;
}
@media (prefers-reduced-motion: reduce) {
  .cookie-banner, .cookie-banner.is-shown { transition: none; transform: none; }
}
/* Dismiss X (2026-08): upper-right corner of the card. X = reject/dismiss,
   not consent - it carries data-cc="essential" so it behaves exactly like
   "Reject Non-Essential". 44x44 target, real button, gold focus ring. */
.cookie-banner__close {
  position: absolute;
  top: 4px;
  right: 4px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  background: none;
  border: 0;
  border-radius: 10px;
  color: var(--purple-deep);       /* 2026-08 translucent card: dark on light */
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}
/* 2026-08 hover CONTAINED (client direction): the old hover lit the whole
   44x44 hit tile - a slab far taller than the heading's text line, reading as
   a bleed onto it. The visible hover is now a 30px circle centred on the
   glyph (a ::before layer, painted under the x), so it stays within the
   control's own area; the 44x44 HIT AREA is the button box, unchanged. */
.cookie-banner__close::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 30px;
  height: 30px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: transparent;
}
.cookie-banner__close:hover::before { background: rgba(46, 33, 80, 0.10); }
.cookie-banner__close > span { position: relative; }   /* the x paints above the hover circle */
.cookie-banner__close:focus-visible { outline: 3px solid var(--purple-deep); outline-offset: 2px; }   /* 2026-08 translucent card: purple-deep ring ~14:1 (white measured 1.08:1 here) */
.cookie-banner__heading {
  margin: 0 0 0.25rem;
  padding-right: 2.6rem;                   /* clears the corner X */
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.85rem;                      /* 2026-08 demotion pass: 14 -> 13.6px (weight + serif keep the hierarchy; BODY copy holds its 14px consent floor) */
  color: var(--purple-deep);               /* 13.4:1 over the frosted card on white */
}
.cookie-banner__body {
  margin: 0;
  font-size: 0.875rem;                     /* 2026-08: 14px EXACTLY - the hard consent-copy floor; a true 2/3 scale would be 9.8px, floored here */
  line-height: 1.5;
  color: var(--purple-deep);               /* 14.2:1 over the translucent card on white */
}
.cookie-banner__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 0.35rem;                     /* 2026-08 demotion pass (was 0.45rem) */
}
.cookie-banner__actions .btn {
  display: inline-flex;
  align-items: center;
  position: relative;              /* anchors the 44px hit overlay below */
  min-height: 35px;                /* 2026-08: VISIBLE height 44 -> 35 (the 44px floor moved to the ::after hit overlay) */
  margin: 0 0.4rem 0.3rem 0;       /* margin, not flex gap (Safari <14.1) */
  padding: 0.3rem 0.6rem;          /* 2026-08 further reduction; with the 14px labels both buttons now fit one row */
  font-size: 0.875rem;             /* 14px labels (were 16px) */
}
/* 44px HIT FLOOR (2026-08): visible buttons are 35px tall - a centred
   transparent overlay carries the tap area without consuming layout space.
   Applies identically to BOTH consent actions (equal prominence held). */
.cookie-banner__actions .btn::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 44px;
  transform: translateY(-50%);
}
/* DEMOTED + EQUALISED 2026-08 (client direction): both consent actions now
   share ONE identical quiet treatment - transparent fill, the same hairline
   purple border, the same 13px label, the same padding - because giving
   Accept All a heavier fill than Reject Non-Essential is a dark pattern on a
   consent notice. Purple-deep labels 13.4:1 over the frosted card on white.
   44px hit floors untouched. */
.cookie-banner .btn--primary,
.cookie-banner .btn--ghost {
  background: transparent;
  color: var(--purple-deep);
  border: 1px solid rgba(46, 33, 80, 0.75);
  padding: 0.17rem 0.55rem;        /* 2026-08: vertical 4px -> 2.7px (one third off); horizontal UNCHANGED; label size UNCHANGED */
  font-size: 0.8125rem;            /* 13px labels (consent BODY copy stays at its own 14px floor; button labels are controls) */
}
.cookie-banner .btn--primary:hover,
.cookie-banner .btn--ghost:hover { background: rgba(46, 33, 80, 0.08); color: var(--purple-deep); }
/* (Superseded by the equalised pair above - retained for restore:
   PRIMARY solid white fill + GHOST outline.) */
/* 2026-08 translucent card pass (SUPERSEDED by the equalised pair above -
   PRIMARY's solid white fill made Accept All heavier than Reject):
.cookie-banner .btn--primary { background: var(--white); color: var(--purple-deep); border-color: var(--white); }
.cookie-banner .btn--primary:hover { background: var(--cream); color: var(--purple-deep); }
.cookie-banner .btn--ghost { background: transparent; color: var(--purple-deep); border-color: rgba(46, 33, 80, 0.75); }
.cookie-banner .btn--ghost:hover { background: rgba(46, 33, 80, 0.08); color: var(--purple-deep); }
*/
.cookie-banner__settings {
  background: none;
  border: 0;
  min-height: 44px;                /* tap target - UNCHANGED floor */
  padding: 0.3rem 0.3rem;          /* 2026-08 further reduction; min-height 44 governs */
  margin: 0 0 0.25rem;
  font: inherit;
  font-size: 0.8125rem;            /* 2026-08: 14 -> 13px, matching the demoted button labels */
  font-weight: 600;
  color: var(--purple-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.cookie-banner__settings:hover { color: var(--purple-bright); }
.cookie-banner__settings:focus-visible,
.cookie-banner__legal a:focus-visible,
.cookie-banner__actions .btn:focus-visible { outline: 3px solid var(--purple-deep); outline-offset: 2px; border-radius: 4px; }   /* 2026-08 translucent card: purple-deep rings ~14:1 (the old white rings measure 1.08:1 here) */
.cookie-banner__prefs input:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; border-radius: 4px; }   /* prefs inputs sit on the WHITE inset — gold 3.18:1 there */
.cookie-banner__legal {
  margin: 0.2rem 0 0;
  font-size: 0.75rem;              /* 12px acknowledgement line - HELD (consent-adjacent copy; not reduced further) */
  line-height: 1.4;
  color: var(--purple-deep);
}
.cookie-banner__legal a { color: var(--purple-deep); font-weight: 600; }
/* Prefs open as a WHITE inset panel — dark text inside, unchanged AA. */
.cookie-banner__prefs {
  margin: 0.6rem 0 0.2rem;
  padding: 0.6rem 0.75rem 0.7rem;   /* 2026-08 scaled */
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.12);
  border-radius: 12px;
}
.cookie-pref {
  display: flex;
  align-items: flex-start;
  margin: 0 0 0.55rem;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text);
  cursor: pointer;
}
.cookie-pref input {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 0.15rem 0.55rem 0 0;     /* margin, not flex gap */
  accent-color: var(--purple-bright);
}
.cookie-pref input:disabled + span { color: var(--text); }   /* Essential stays readable, not greyed */
.cookie-banner__save { margin-top: 0.2rem; }
/* PHONES: COMPACT BAR, NOT A PANEL (2026-08) ---------------------------------
   The floating card was 366x312 at 390px - a third of the screen - sitting at
   z-index 120 with pointer-events auto until answered, and it returns every
   browsing session. Hit-tests showed it swallowing taps meant for links and
   buttons beneath it, including "Verify code" on both login pages. Below 640px
   it becomes a short bar pinned to the bottom edge instead: same wording, same
   consent logic, same storage - only the presentation changes.
     - Full-bleed to the bottom edge, so it reads as chrome, not page content.
     - OPAQUE (no backdrop-filter, Safari-14-safe) with a solid top rule and a
       lifted shadow, so it can never be mistaken for part of the page.
     - The heading and the legal acknowledgement line are dropped from view at
       this width to keep the bar short; both policy links they carried
       (Cookie Policy, Privacy Policy) sit in the footer of all 41 pages, so
       nothing becomes unreachable. The consent BODY stays, clamped to two
       lines - the full sentence remains in the DOM for assistive technology.
     - Buttons keep their 44px hit overlay; only the visible box is compact. */
@media (max-width: 639.98px) {
  .cookie-banner {
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-width: none;
    padding: 0.5rem 0.7rem 0.55rem;
    border: 0;
    border-top: 2px solid var(--purple-deep);
    border-radius: 0;
    background: #F2EEF8;                 /* opaque - never translucent over content */
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: 0 -10px 28px rgba(20, 12, 40, 0.30);
    transform: translateY(100%);         /* slides up FROM the edge; .is-shown clears it */
  }
  .cookie-banner__heading { display: none; }
  .cookie-banner__legal { display: none; }
  .cookie-banner__close { top: 0; right: 2px; }
  .cookie-banner__body {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;               /* visually two lines; full text stays in the DOM */
    overflow: hidden;
    padding-right: 2.8rem;               /* clears the corner X */
    line-height: 1.4;
  }
  /* Controls stay INLINE at phone widths: full-width stacking was what made
     the old card 300px+ tall (three 44px rows). They wrap only if they must,
     and each keeps its invisible 44px hit overlay. */
  .cookie-banner__actions { margin-top: 0.3rem; }
  .cookie-banner__actions .btn {
    width: auto;
    margin: 0 0.35rem 0 0;
    justify-content: center;
  }
  .cookie-banner__settings { width: auto; text-align: left; }
}
/* Narrow phones: the three control labels cannot share one row at this width
   (the wording is fixed), so they wrap to two - the consent line drops to a
   single clamped line to keep the bar short. */
@media (max-width: 399.98px) {
  .cookie-banner__body { -webkit-line-clamp: 1; }
  .cookie-banner__actions { margin-top: 0.2rem; }
}

/* Warm line above the Share Your Story submit (client design doc) — the
   letter voice: Lora italic in brand purple, quiet, AA (~11.7:1 on the white
   form card). Generic class so future forms can reuse it. */
.form-warm {
  margin: 1.4rem 0 1.1rem;
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--purple);
}

/* ===================================================================
   Patient Stories redesign (2026-08) — two equal story slots + support bands.
   Page-scoped classes (only patient-stories.html carries them).
   =================================================================== */
/* Hero polish: a small reassurance line under the CTA. (The "How sharing
   works" link was removed 2026-08 by client direction — its rules retired.)
   KICKER SIZE: the hero kicker already inherits the shared .eyebrow
   --fs-kicker scale — measured pixel-identical to the homepage kickers
   (23px/38px/0.02em at desktop); pinned explicitly here so a future banner
   change can never shrink it out of step. */
.page-banner--stories .eyebrow {
  font-size: var(--fs-kicker);
  line-height: 1.65;
  letter-spacing: 0.02em;
}
.page-banner--stories .page-banner__reassure {
  margin: 0.5rem 0 0;
  font-size: 0.95rem;
  color: #EFEAF6;
  text-shadow: 0 1px 2px rgba(20, 14, 40, 0.6);
}
.page-banner--stories .page-banner__lock {
  width: 15px; height: 15px;
  margin-right: 0.45rem;
  vertical-align: -2px;
  filter: drop-shadow(0 1px 2px rgba(20, 14, 40, 0.6));
}

/* (The hero reassurance band was removed 2026-08 by client direction — its
   .stories-reassure rules went with the markup; restore both from history if
   the band ever returns.) */

/* THE PAIR — two slots, EQUAL size and dignity (no featured hierarchy):
   side by side from 860px, stacked below; stretch so both match heights.
   The opened Yifei letter still spans the full row (grid-column 1/-1). */
.stories-feed__list--pair { grid-template-columns: 1fr; align-items: stretch; }
/* 2026-08 strip-down: ONE story card (Yifei) — a centered comfortable column
   at every width, never a half-width orphan of the old pair grid. */
.stories-feed__list--single { grid-template-columns: 1fr; max-width: 680px; margin-left: auto; margin-right: auto; }
/* Pending-approval marker on the summary slot: visibly provisional, AA text. */
.story-entry__pending-tag {
  margin: 0 0 0.4rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--purple-deep);
  background: var(--lavender-light);
  border: 1px dashed var(--gold);
  border-radius: 999px;
  display: inline-block;
  padding: 0.15rem 0.6rem;
}
/* Yifei's closing reflections — standalone panel between the story card and the
   coda (2026-08; her heading + three bullets moved VERBATIM out of the letter).
   REUSES the site's established callout pattern (.chair__welcome / .form-note:
   gold left rule + rounded panel) on the story card's own letter-paper cream,
   at the same 680px measure as the card and coda — one vertical rhythm, no new
   visual language. The __by attribution is required content (a patient's words,
   not GEM guidance). AA on cream #FBF9F4: heading/attribution --purple 11.9:1,
   bullets --text 13.4:1. */
.story-reflections {
  /* 2026-08 rework: now a SIDEBAR TIPS BOX - smaller type and padding than the
     story card so it reads as supporting material; at >=1024px it occupies the
     right third beside the card (grid below), top-aligned; under 1024px it
     stacks below the card full-width (this base rule). */
  max-width: 680px;
  margin: clamp(1.5rem, 3.5vw, 2.25rem) auto 0;
  padding: 1rem 1.15rem;
  /* 2026-08 (client direction, reference panel): soft LIGHT-PURPLE tint -
     --lavender #F2EEF8 - clearly lighter than the mid purples, distinguishing
     the box from the cream story card beside it. Heading 10.78:1, bullets
     12.12:1 on the tint - AA kept. NOT drifted toward #9E7AC8 (rejected). */
  background: var(--lavender);
  border: 1px solid rgba(58, 42, 102, 0.10);
  border-left: 4px solid var(--gold);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 0.95rem;
  line-height: 1.65;
}
.story-reflections__title {
  margin: 0 0 0.75rem;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 1.08rem;
  line-height: 1.35;
  color: var(--purple);                  /* 11.9:1 on cream */
}
/* Sidebar layout: the container becomes a two-column grid - the 680px story
   column left, the tips box in the remaining right third, ALIGNED TO THE
   CARD'S TOP (align-self start; deliberately NOT sticky - when the letter
   expands to ~1,500 words the box stays quietly at the top of the column
   rather than following the reader down alongside her story). The coda stays
   under the story column. */
@media (min-width: 1024px) {
  .stories-feed .container {
    display: grid;
    grid-template-columns: minmax(0, 680px) minmax(240px, 1fr);
    column-gap: clamp(1.5rem, 3vw, 2.5rem);
    align-items: start;
  }
  .stories-feed__list--single { grid-column: 1; margin-left: 0; margin-right: 0; }
  .story-reflections { grid-column: 2; grid-row: 1; align-self: start; margin: 0; max-width: none; }
  .stories-feed__coda { grid-column: 1; margin-left: 0; margin-right: 0; }
}
.story-reflections p { margin: 0 0 1.05rem; }
.story-reflections > :last-child { margin-bottom: 0; }
.story-reflections__heading {
  margin: 0 0 1.1rem;
  font-family: var(--font-head);         /* the story's italic serif (.story-lede voice) */
  font-style: italic;
  font-size: 1.3rem;
  line-height: 1.7;
  color: var(--purple);
}
.story-reflections__by {                 /* attribution — matches .chair__welcome cite */
  display: block;
  margin-top: 0.9rem;
  font-style: normal;
  font-weight: 600;
  color: var(--purple);
}
/* ============ NEWS ARTICLE (2026-08, first article) ==========================
   Single centred reading column at a 68ch measure (measured 67 chars/line at
   1440). Figures are CONTAINED - the portrait hero renders at its native
   424px, never stretched. The clinical close-up sits behind a click-to-reveal
   (trauma-informed default for readers facing surgery). The pull-quote reuses
   the site's cream panel + gold rule + italic serif recipe. */
.article-date { margin: 0.5rem 0 0; font-size: 0.9rem; font-weight: 600; color: var(--gold-deep); }
/* Article hero alignment (2026-08, scoped to the News article page): the
   hero's inner container adopts the article body column's EXACT geometry -
   the same 62ch measure resolved at the same 1.1rem context, centred - so the
   kicker, headline, standfirst, date and every body paragraph share one left
   axis. LEFT-ALIGNED, deliberately not centred (the body is left-aligned text
   in a centred column; centring the hero would split the axis - the centred
   Our Story hero was a fix for that page's centred letter, not a house
   style). Each element keeps its own rem-based type size; the container
   font-size below only resolves the ch measure. Background, height and copy
   untouched. */
/* ============ NEWS ARTICLE - three-column editorial grid (2026-08) ==========
   Shared by the hero and the body so their columns align exactly:
     col 1  LEFT MARGIN   tools / kicker / date (quiet, small)
     col 2  CENTRE        the UNCHANGED 62ch reading measure (resolved at the
                          grid's 1.1rem context = the body's own size)
     col 3  RIGHT         the lead photograph, <=424px native (downscales in a
                          narrower track, never upscales)
   Below 1100px the grid collapses to one linear column in DOM order. */
.article-grid {
  max-width: 1360px;
  margin-inline: auto;
  padding-inline: 1.25rem;
  display: grid;
  grid-template-columns: minmax(130px, 170px) 62ch minmax(240px, 424px);   /* centre HARD at the 62ch measure - the image track flexes (downscale only) */
  column-gap: clamp(1.5rem, 3vw, 2.5rem);
  justify-content: center;
  font-size: 1.1rem;                   /* resolves the 62ch track to the body's own measure; every child sets its size in rem, so nothing inherits this */
}
.article-crumb {
  grid-column: 1 / -1;
  margin: 0 0 1.1rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.article-crumb__sep { margin: 0 0.35rem; color: rgba(187, 134, 63, 0.8); }
.article-grid__side { grid-column: 1; }
.article-grid__main { grid-column: 2; }
.article-grid--hero .eyebrow { margin-bottom: 0.4rem; }
.article-grid--hero .article-date { margin-top: 0.15rem; }
.page-banner--article h1 { max-width: none; }   /* the shared 22ch cap forced 3 lines; the column width now bounds the headline */
.article-grid__body { grid-column: 2; grid-row: 2; }
.article-grid > .article-grid__figure {   /* (0,2,0): outranks .article__fig's own 1.5rem top margin further down */
  grid-column: 3;
  grid-row: 2;
  align-self: start;                   /* top of the figure = top of the first paragraph */
  margin: 0;
}
.article-grid:not(.article-grid--hero) { grid-template-rows: 0 auto; }   /* row 1 unused in the body grid */
.article__fig-note { margin: 0.35rem 0 0; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
/* LEFT-MARGIN TOOLS (2026-08, mockup): quiet share group - small gold label,
   white hairline-bordered buttons, purple-bright focus rings. */
.article-grid__tools { grid-column: 1; grid-row: 2; align-self: start; }
.article-tools__head { margin: 0 0 0.45rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold-deep); }
.article-tools__btn {
  display: block;
  width: 100%;
  min-height: 44px;
  margin: 0 0 0.5rem;
  padding: 0.35rem 0.7rem;
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.25);
  border-radius: 8px;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--purple-deep);
  cursor: pointer;
}
.article-tools__btn:hover { background: var(--lavender-light); }
.article-tools__btn:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; }   /* NOT the raw --focus token */
.article-tools__status { margin: 0; min-height: 1.2em; font-size: 0.75rem; font-weight: 600; color: var(--gold-deep); }
/* ACCOUNTABILITY SLOT - ships [hidden] (empty by instruction); the rule +
   heading render only once GEM supplies the author content. */
.article__author { margin: 2rem 0 0; padding-top: 1rem; border-top: 1px solid rgba(187, 134, 63, 0.35); }   /* the site's standard gold hairline */
.article__author-head { margin: 0 0 0.4rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold-deep); }
@media (max-width: 1199.98px) {
  .article-grid__tools { margin: 2rem 0 0; max-width: 320px; }
}
@media (max-width: 1199.98px) {
  /* SINGLE LINEAR COLUMN below 1200 (the hard 62ch centre + both side
     minimums need ~1130px): hero already reads metadata -> headline; the
     body grid stacks image, then body, in DOM order. */
  .article-grid { display: block; max-width: calc(62ch + 2.5rem); }   /* the stacked column keeps the same reading measure (+ its own padding) */
  .article-grid > .article-grid__figure { margin: 0 0 1.5rem; }
  .article-grid__figure img { width: 100%; max-width: 424px; height: auto; }
  .article-grid--hero .article-grid__main { margin-top: 0.5rem; }
}
.article__col {
  max-width: 62ch;                     /* renders ~69 average prose chars/line at 1440 (ch is the '0' width; prose runs wider) - inside the 62-72 window */
  font-size: 1.1rem;
  line-height: 1.75;
  color: var(--text);
}
.article__col > p { margin: 0 0 1.15rem; }
.article__subhead {
  margin: 2rem 0 0.75rem;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 1.45rem;
  color: var(--purple);
}
.article__fig { margin: 1.5rem 0 1.75rem; }
.article__fig img { display: block; max-width: 100%; height: auto; border-radius: var(--radius); }
.article__fig--portrait img { width: 424px; max-width: 100%; }   /* native scale, contained - no upscaling */
.article__caption {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-muted);
}
.article__reveal { margin: 1.5rem 0 1.75rem; }
/* Disclosure CARD (2026-08, mockup): the bare button becomes a bordered block
   - the site's standard card recipe (white, hairline border, --radius; same
   treatment as the login card / tips box). Reveal behaviour, aria wiring and
   the 44px button are untouched. */
.article__reveal--card {
  padding: 1rem 1.15rem;
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.12);
  border-radius: var(--radius);
}
.article__reveal-head { margin: 0 0 0.1rem; font-family: var(--font-head); font-weight: 600; font-size: 1.05rem; color: var(--purple); }
.article__reveal-sub { margin: 0 0 0.35rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--gold-deep); }
.article__reveal--card .article__reveal-note { margin: 0 0 0.75rem; }
.article__reveal-btn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;                    /* tap floor */
  padding: 0.5rem 1.1rem;
  background: var(--lavender-light);
  border: 1px solid rgba(58, 42, 102, 0.25);
  border-radius: 10px;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--purple);                /* 11.5:1 on lavender-light */
  cursor: pointer;
}
.article__reveal-btn:hover { background: var(--lavender); }
.article__reveal-btn:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; }   /* NOT the raw --focus token */
.article__reveal-note { margin: 0.4rem 0 0; font-size: 0.85rem; color: var(--text-muted); }
.article__reveal .article__fig { margin-top: 1rem; }
.article__pull {
  margin: 3.5rem 0 2.75rem;            /* 2026-08 given more space (was 2.25rem/1.5rem = 36/24px -> 56/44px) */
  padding: 1.1rem 1.35rem;
  background: var(--cream);
  border: 1px solid rgba(58, 42, 102, 0.10);
  border-left: 4px solid var(--gold);
  border-radius: var(--radius);
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.25rem;
  line-height: 1.6;
  color: var(--purple);                /* 11.9:1 on cream */
}
.article__back { margin: 2rem 0 0; }
.article__back a { color: var(--purple-bright); font-weight: 600; text-underline-offset: 3px; }

/* News page rhythm (2026-08): more air below the hero hairline so the lead
   breathes, less trailing space before the footer so the page ends
   deliberately. Scoped to the News listing section only. */
/* Bottom padding (2026-08 polish): no override - the bottom falls back to
   the base .section rhythm (clamp(2.5rem, 6vw, 4.5rem) = 72px desktop, 40px
   mobile), the same rhythm every content page uses. Only the top stays
   custom (space under the banner). */
.section--news { padding-top: 88px; }
@media (max-width: 759.98px) {
  .section--news { padding-top: 56px; }
}

/* Quiet sign-in context line under Share-your-story CTAs (2026-08 site-wide
   login rule). Small, muted, secondary - --text-muted measures 6.9:1 on the
   white/cream/light-banner grounds it sits over. */
.cta-note { margin: 0.45rem 0 0; font-size: 0.8rem; color: var(--text-muted); }

/* ============ News index - EDITORIAL ROWS (2026-08, replaces the featured
   lead + compact list; those styles below are INERT - no markup uses them -
   and retained as the restore path) =========================================
   Desktop: [ meta 150px | text 1fr | image 200px ], thin gold hairline
   between rows. Existing tokens only: Lora serif headline (--font-head) in
   --purple, small uppercase gold-deep label, muted date, warm standfirst,
   the standard rgba(187,134,63,0.35) rule. The 424x524 image DOWNSCALES to
   its 200px track - never upscaled; width/height attrs reserve the box. */
.news-rows { max-width: 1000px; }
.news-row {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) 200px;
  column-gap: clamp(0.85rem, 1.7vw, 1.65rem);   /* 2026-08 polish: ~2/3 of the old clamp(1.25rem,2.5vw,2.5rem) - meta + headline read as one unit */
  padding: 1.75rem 0;
  /* Closing rule (2026-08 polish): EVERY row carries its own bottom rule,
     matching the page-banner's border above (2px gold @0.55) - rows stack
     with a single rule between them (no top rules), and the last row closes
     the page instead of floating. Replaces the old 1px @0.35 between-row
     hairline (`.news-row + .news-row` border-top). */
  border-bottom: 2px solid rgba(187, 134, 63, 0.55);
}
/* Cap-height alignment (2026-08 polish): the category's CAP TOP sits ~2px
   lower than the headline's when both boxes share a top edge (Lora 1.45rem
   @1.3 puts its cap ~7.1px down; Inter 0.72rem @1.6 puts its ~5.0px down) -
   this 2px nudge makes the CAP tops align optically. Desktop only: the
   mobile stack resets it (meta is its own full-width line there). */
.news-row__meta { min-width: 0; padding-top: 0.125rem; }
.news-row__cat { margin: 0 0 0.3rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold-deep); }
.news-row__date { margin: 0; font-size: 0.8rem; font-weight: 600; color: var(--text-muted); }
.news-row__text { min-width: 0; }
.news-row__title { margin: 0 0 0.5rem; font-family: var(--font-head); font-weight: 600; font-size: 1.45rem; line-height: 1.3; }
.news-row__title a { color: var(--purple); text-decoration: none; }
.news-row__title a:hover { color: var(--purple-bright); }
.news-row__title a:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 3px; border-radius: 4px; }   /* NOT the raw --focus token */
.news-row__standfirst { margin: 0; font-size: 0.98rem; line-height: 1.55; color: var(--text-warm); }
/* "Read article →" - the ACCESSIBLE deep gold (--gold-deep, 5.45:1 on the
   white page), never the lighter --gold. Same destination as the headline. */
/* Rhythm (2026-08 polish): the 44px link box vertically CENTRES its ~24px
   text line, adding ~10px of built-in visual space above the label - the
   negative margin compensates, so the VISUAL gap above "Read article" lands
   ~5px, smaller than the 8px headline-to-summary gap (hierarchy restored).
   The 44px hit target itself is untouched. Mobile resets to 0 (its own rule
   below). */
.news-row__more { margin: -0.3rem 0 0; }
.news-row__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--gold-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.news-row__link:hover { color: var(--purple-bright); }
.news-row__link:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; border-radius: 4px; }   /* NOT the raw --focus token */
/* Landscape crop (2026-08 polish): the TEXT column drives row height, the
   image NEVER does. Desktop: the media box is position:relative with no
   intrinsic height and the img absolute-fills it, so the row is sized by the
   text alone and the image is centre-cropped (object-fit) to exactly that
   height - measured 200x126 with today's copy; a strict in-flow 4:3 box
   (200x150) was tried first and still overran the text by 24px, which the
   spec's "never" forbids. The img attrs carry 4:3 (424x318) so the pre-CSS
   reserved box is landscape (no layout shift). Mobile keeps the in-flow
   4:3 crop (96x72) beside the headline - static positioning restored in the
   mobile block below. Longhand offsets, not `inset` (Safari <14.1). */
.news-row__media { margin: 0; position: relative; min-height: 0; }
.news-row__media img { display: block; position: absolute; top: 0; right: 0; bottom: 0; width: 100%; max-width: 200px; height: 100%; object-fit: cover; object-position: center; border-radius: 8px; }
/* NO-IMAGE VARIANT (exists ahead of need - today's single article has an
   image): add news-row--no-image to the <article> and OMIT .news-row__media
   entirely. The text may run into the freed span - its own line lengths keep
   the right margin as intentional whitespace - and NO empty frame, grey box,
   or placeholder image ever renders. */
.news-row--no-image .news-row__text { grid-column: 2 / -1; }
/* MOBILE STACK (<768px): category left + date right on one line; headline
   beside a small image on the right; standfirst full width beneath.
   display:contents lifts the text wrapper's children into the row grid so
   the headline and standfirst can occupy different areas. */
@media (max-width: 767.98px) {
  .news-row {
    grid-template-columns: minmax(0, 1fr) 96px;
    grid-template-areas:
      "meta  meta"
      "title media"
      "sf    sf"
      "more  more";
    row-gap: 0.55rem;
    column-gap: 1rem;
    padding: 1.4rem 0;
  }
  .news-row__meta { grid-area: meta; display: flex; justify-content: space-between; align-items: baseline; padding-top: 0; }   /* cap-align nudge is desktop-only */
  .news-row__meta .news-row__cat { margin: 0; }
  .news-row__text { display: contents; }
  .news-row__title { grid-area: title; margin: 0; font-size: 1.15rem; }
  .news-row__media { grid-area: media; position: static; }
  .news-row__media img { position: static; height: auto; aspect-ratio: 4 / 3; max-width: 96px; }   /* in-flow 4:3 (96x72) beside the headline */
  .news-row__standfirst { grid-area: sf; }
  .news-row__more { grid-area: more; margin: 0; }
  /* No-image rows on mobile: the headline takes the full width - no reserved
     96px image column, no empty frame. */
  .news-row--no-image {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "meta"
      "title"
      "sf"
      "more";
  }
  .news-row--no-image .news-row__text { grid-column: auto; display: contents; }
}

/* News - FEATURED lead article (2026-08 editorial rework, replaces the card):
   content sits directly on the page - no border, background or shadow. Image
   left at its NATIVE 424px width (424x524 source - never upscaled), text
   right; a gold hairline (the site's standard 1px rgba(187,134,63,0.35)
   treatment) closes the block and separates it from the list beneath. */
.news-featured {
  border-bottom: 1px solid rgba(187, 134, 63, 0.35);   /* same hairline as the CTA→footer + footer-legal dividers */
  padding-bottom: 2.5rem;
}
.news-featured__link {
  display: flex;
  /* 2026-08: flex-start -> center. The 400px portrait image is ~494px tall
     against ~217px of text; top-aligning left ~278px of dead space UNDER the
     text. Centring keeps the text column sized to its content (no stretch)
     and splits the remainder evenly above/below, so the row reads as a
     deliberate editorial lockup instead of trailing off. Full elimination
     would require cropping the image or shrinking it below the 380-420px
     bound - reported, not done. */
  align-items: center;
  gap: 2.5rem;
  text-decoration: none;
  color: var(--text);
}
.news-featured__link:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 3px; border-radius: 4px; }   /* NOT the raw --focus token */
.news-featured__link:hover .news-featured__title { color: var(--purple-bright); }
.news-featured__img {
  flex: 0 0 auto;
  width: 400px;                        /* 2026-08 reduced (was 424 native): below native width - downscaled, never upscaled, renders sharp; the freed 24px goes to the text column so the headline leads the row */
  max-width: 100%;
  height: auto;
  border-radius: 8px;
}
.news-featured__body { display: block; min-width: 0; }   /* 2026-08: the 0.35rem top-align optical nudge dropped - the row centres now */
.news-featured__kicker { display: block; margin: 0 0 0.6rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold-deep); }
.news-featured__title { display: block; margin: 0 0 0.75rem; font-family: var(--font-head); font-weight: 600; font-size: clamp(1.5rem, 2.6vw, 2rem); line-height: 1.22; color: var(--purple); }
.news-featured__standfirst { display: block; margin: 0 0 0.9rem; font-size: 1.1rem; line-height: 1.6; color: var(--text-warm); max-width: 52ch; }
.news-featured__date { display: block; margin: 0; font-size: 0.82rem; font-weight: 600; color: var(--text-muted); }
@media (max-width: 899.98px) {
  /* Stack: image above the text at full column width - but CAPPED at its
     424px native width so it is never upscaled. */
  .news-featured__link { display: block; }
  .news-featured__img { width: 100%; max-width: 424px; margin: 0 0 1.25rem; }
}

/* News list - compact rows for OLDER articles beneath the featured lead
   (2026-08 rework of the former card row: no border-box, no shadow - a quiet
   hairline-separated index). One <li class="news-item"> per article, newest
   first: small thumbnail, kicker, headline, date. EMPTY today by design -
   an empty <ul> renders nothing (see the maintenance comment in news.html). */
.news-list { list-style: none; margin: 2.25rem 0 0; padding: 0; max-width: 780px; }
.news-list:empty { display: none; }    /* no placeholder rows while only the featured article exists */
.news-item + .news-item { border-top: 1px solid rgba(187, 134, 63, 0.35); }   /* same gold hairline as the featured divider */
.news-item__link {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1.1rem 0;
  min-height: 44px;
  text-decoration: none;
  color: var(--text);
}
.news-item__link:hover .news-item__title { color: var(--purple-bright); }
.news-item__link:focus-visible { outline: 3px solid var(--purple-bright); outline-offset: 2px; border-radius: 4px; }   /* NOT the raw --focus token */
.news-item__thumb {
  flex: 0 0 auto;
  width: 72px;
  height: 89px;                        /* the 424x524 portrait ratio, downscaled - never stretched */
  object-fit: cover;
  border-radius: 6px;
}
.news-item__body { display: block; min-width: 0; }
.news-item__kicker { display: block; margin: 0 0 0.25rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold-deep); }
.news-item__title { display: block; margin: 0 0 0.3rem; font-family: var(--font-head); font-weight: 600; font-size: 1.1rem; line-height: 1.3; color: var(--purple); }
.news-item__date { display: block; margin: 0; font-size: 0.82rem; font-weight: 600; color: var(--text-muted); }

/* Quiet coda under the lone story card - LEFT-ALIGNED to the card edge
   (2026-08): same 680px centered measure as the card list, so the coda's
   left edge sits exactly on the card's left edge. */
.stories-feed__coda {
  margin: clamp(1.5rem, 3.5vw, 2.25rem) auto 0;
  max-width: 680px;
  text-align: left;
  font-family: var(--font-head);
  font-style: italic;
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--purple);
}
@media (min-width: 860px) {
  .stories-feed__list--pair { grid-template-columns: repeat(2, 1fr); }
}

/* SLOT 1 — subtle letter/paper feel behind the REAL story only: warm paper
   gradient + faint ruled lines (pure CSS, no image), soft gold edge, and a
   large ghosted quotation mark (mockup) in the corner. Light, elegant, fully
   readable (text contrast unchanged on the pale ground). */
.story-entry--paper {
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.6) 0%, rgba(255, 255, 255, 0) 40%),
    repeating-linear-gradient(0deg, rgba(58, 42, 102, 0.03) 0 1px, transparent 1px 28px),
    linear-gradient(180deg, #FDFBF6 0%, #F7F1E6 100%);
  border-color: rgba(187, 134, 63, 0.3);
}
.story-entry--paper::after {
  content: "\201C";
  position: absolute;
  top: -0.5rem;
  right: 1.25rem;
  font-family: var(--font-head);
  font-size: clamp(6rem, 12vw, 9rem);
  line-height: 1.4;
  color: rgba(58, 42, 102, 0.07);       /* ghosted — decorative only */
  pointer-events: none;
}
.story-entry__quote {
  margin: 1.1rem 0 0;
  font-family: var(--font-head);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.35rem, 2.6vw, 1.8rem);
  line-height: 1.4;
  color: var(--purple);                  /* ~9:1 on the paper ground */
}
.js .story-entry.is-open .story-entry__quote { display: none; }   /* the opened letter begins with the same line */

/* SLOT 2 — honest invitation panel: clean and warm, deliberately NOT paper
   (that is reserved for real stories). Content vertically centred so the two
   equal slots read as designed peers. */
.story-entry--invite {
  justify-content: center;
  background: linear-gradient(180deg, var(--white) 0%, #F6F2FB 100%);
  border-top: 4px solid var(--gold);
  text-align: left;
}
.story-entry__tag--invite { color: var(--gold-deep); }   /* 5.4:1 on the light panel */
.story-invite__head { display: flex; align-items: center; }
.story-invite__badge {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  margin-right: 0.7rem;                  /* margin, not flex gap */
  border-radius: 50%;
  background: var(--lavender-light);
  border: 1px solid rgba(58, 42, 102, 0.2);
  color: var(--purple);
}
.story-invite__badge svg { width: 22px; height: 22px; }
.story-invite__head .story-entry__tag { margin-bottom: 0; }
.story-invite__headline {
  margin: 1rem 0 0;
  font-family: var(--font-head);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(1.25rem, 2.4vw, 1.6rem);
  line-height: 1.35;
  color: var(--purple-deep);
}
/* Subtitle folded in from the page's old standalone closing line (2026-08).
   HIERARCHY CLARIFIED (client direction): four distinct levels — kicker
   (small caps) -> heading (display italic 600) -> THIS deck/standfirst
   (clearly larger than body, italic 500) -> body. Wording unchanged. */
.story-invite__subtitle {
  margin: 0.6rem 0 0;
  font-family: var(--font-head);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.15rem, 2.2vw, 1.35rem);   /* deck scale — clearly above the 1rem body (was 1.02rem, body-sized) */
  line-height: 1.5;
  color: var(--purple);                  /* ~9:1 on the light panel */
}
.story-invite__support { margin: 1rem 0 0; font-size: 1rem; line-height: 1.6; color: var(--text-warm); }
.story-invite__cta { margin: 1.4rem 0 0; }
.story-invite__consent { margin: 0.9rem 0 0; font-size: 0.95rem; }
.story-invite__consent a { color: var(--purple-bright); font-weight: 600; text-underline-offset: 3px; }
.story-invite__lock { width: 14px; height: 14px; margin-right: 0.4rem; vertical-align: -2px; color: var(--purple-mid); }

/* Band 2 — "Your story, your choices": an OPEN row (de-boxed 2026-08 by
   client direction — border/shadow/panel background removed so it blends
   into the page ground). Kicker + three divided columns, icon left of text. */
.stories-choices { background: var(--white); padding-block: clamp(1.5rem, 3.5vw, 2.5rem); }
.stories-choices__card {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}
.stories-choices__kicker {
  margin: 0 0 1rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--gold-deep);               /* 5.4:1 on white = AA */
}
.stories-choices__row {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  grid-template-columns: 1fr;
}
@media (min-width: 760px) { .stories-choices__row { grid-template-columns: repeat(3, 1fr); } }
.stories-choice {
  display: flex;
  align-items: flex-start;
  text-align: left;
  padding: 0.7rem 0;
}
@media (min-width: 760px) {
  .stories-choice { padding: 0.35rem clamp(0.9rem, 2vw, 1.5rem); }
  .stories-choice:first-child { padding-left: 0; }
  .stories-choice + .stories-choice { border-left: 1px solid rgba(58, 42, 102, 0.14); }
}
@media (max-width: 759.98px) {
  .stories-choice + .stories-choice { border-top: 1px solid rgba(58, 42, 102, 0.1); }
}
.stories-choice__icon {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  margin-right: 0.9rem;                  /* margin, not flex gap */
  border-radius: 50%;
  background: var(--lavender-light);
  border: 1px solid rgba(58, 42, 102, 0.18);
  color: var(--purple);
}
.stories-choice__icon svg { width: 24px; height: 24px; }
.stories-choice__text { display: flex; flex-direction: column; min-width: 0; }
.stories-choice__title { font-family: var(--font-head); font-weight: 600; font-size: 1.08rem; line-height: 1.3; color: var(--purple-deep); }
.stories-choice__sub { margin-top: 0.35rem; font-size: 0.95rem; line-height: 1.5; color: var(--text-warm); }

/* Band 3 — "Your experience matters" (restyled 2026-08 per mockup): a
   FULL-BLEED soft-lavender band (background on the full-width section; the
   content stays in the centred container), sitting FLUSH against the footer.
   The inner card is de-boxed — envelope art | copy | actions sit directly on
   the lavender. AA on --lavender-light: heading purple-deep ~12.6:1, body
   --text ~13:1, primary button self-contained; the gold-outline button gets
   a WHITE fill here so its ring keeps UI contrast (gold on lavender alone is
   ~2.8:1). */
.stories-closing {
  background: var(--lavender-light);
  padding-block: clamp(1.75rem, 4vw, 3rem);
  margin-bottom: 0;                      /* flush to the footer — no gap band */
}
.stories-closing__card {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}
/* (.stories-closing .btn--gold white-fill rule retired 2026-08 — the
   secondary "See the questions first" button was removed.) */
.stories-closing__art {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 48px; height: 48px;             /* matches the "Your story, your choices" icon circles (was 64px) */
  margin-right: 0.9rem;                  /* matches the choices' icon-to-text gap; margin, not flex gap */
  border-radius: 50%;
  background: var(--white);              /* the section's intended equivalent of the choices' lavender-light discs — lavender-light would vanish on this lavender band */
  border: 1px solid rgba(58, 42, 102, 0.18);   /* matches the choices' border weight */
  color: var(--purple);
}
.stories-closing__art svg { width: 24px; height: 24px; }   /* glyph scaled with the disc (matches the choices' 24px), grid-centred */
.stories-closing__copy { flex: 1 1 300px; min-width: 0; margin: 0.4rem 0; }
.stories-closing__heading {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: clamp(1.35rem, 2.6vw, 1.8rem);
  color: var(--purple-deep);
}
.stories-closing__line { margin: 0.45rem 0 0; max-width: 60ch; font-size: 1rem; line-height: 1.6; color: var(--text); }
.stories-closing__actions { display: flex; flex-wrap: wrap; align-items: center; margin-left: auto; padding-left: 0.5rem; }
/* No trailing right margin (a two-button-era leftover that parked the lone
   button 9.6px off the shared column edge): its RIGHT edge now lands exactly
   on the same content boundary as the icon row and footer. */
.stories-closing__actions .btn { margin: 0.4rem 0 0.4rem 0; }
@media (max-width: 759.98px) {
  .stories-closing__actions { margin-left: 0; padding-left: 0; width: 100%; }
}
/* (.stories-closing__growing retired 2026-08 — the line now lives inside the
   invitation panel as .story-invite__subtitle.) */
/* ---- ARROW TEXT-LINKS, shared (2026-08): ONE continuous underline through
   label AND arrow. The anchors are inline-flex (for the 44px tap box), and
   text-decoration cannot draw a single line across flex items - the arrow
   span + its margin gap broke the underline. Fix: the label + arrow sit in
   ONE inner .arrowlink-text span (a single flex item); the underline lives on
   it and propagates continuously through its inline children, including the
   arrow and the space before it. Instances: footer "Join the Movement" (all
   37 pages), homepage "Explore More Evidence", homepage "Meet Our
   Professionals". Hover/focus states unchanged (color lives on the anchor). */
.site-footer .footer-cta__btn,
.fusion__more-link,
.meet-experts__link,
.fusion__founder-link { text-decoration: none; }
/* FIX 2026-08: text-decoration is painted only under inline boxes, so it
   SKIPPED the arrow span's 0.4rem margin - the line broke between text and
   arrow. A border-bottom on the wrapper spans its whole box (text + gap +
   arrow) as ONE continuous line, and follows hover color via currentColor. */
.arrowlink-text {
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
}
.arrowlink-text > span { margin-left: 0.4rem; }   /* label-arrow via margin (Safari <14.1) */

/* ============ LOGIN CHOOSER (2026-08, demo-mode flow) ============
   The header person icon now shows on DESKTOP too (the editorial header used
   to hide it entirely) and opens a small two-item popover: Patient login /
   Professional login. Icon-only in the utility cluster (same grammar as the
   search + globe icons); the popover is a white card matching the nav
   dropdown panels. 44px targets throughout. */
.login-menu { position: relative; display: inline-flex; }
.site-header--editorial .header-signin {
  display: inline-flex;                /* overrides the 3381 hide - the icon is back, as the chooser toggle */
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}
.site-header--editorial .header-signin__icon { display: inline-block; width: 18px; height: 18px; }
.site-header--editorial .header-signin__label { display: none; }   /* icon-only, like search/globe */
.login-menu__list {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 130;
  min-width: 210px;
  margin: 0;
  padding: 0.4rem;
  list-style: none;
  background: var(--white);
  border: 1px solid rgba(58, 42, 102, 0.14);
  border-radius: 12px;
  box-shadow: 0 12px 32px -10px rgba(46, 33, 80, 0.4);
}
.login-menu__item {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.55rem 0.8rem;
  border-radius: 8px;
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--purple);
  text-decoration: none;
}
.login-menu__item:hover { background: var(--lavender-light); color: var(--purple-deep); }
.login-menu__item:focus-visible { outline: 3px solid var(--focus); outline-offset: -2px; }

/* ============ HERO STATIC-IMAGE FALLBACK (2026-08) ============
   ui.js adds .hero--fallback when the video cannot play (play() rejected,
   'error' fired, the 1.8s silent-failure check tripped - WeChat's no-op -
   or the no-video/reduced-motion path). The dark-first underlay then paints
   the fallback PHOTO under a deep-purple scrim, the video is hidden, and the
   headline/CTA render in their final state - an intentional photo hero, never
   a broken intro. Scrim is heaviest across the upper text zone so the WHITE
   headline holds AA over any part of the image. WebP assets (supported by
   current WeChat/iOS/Android); a desktop JPEG was not supplied, so engines
   without WebP keep the solid dark layer - dark, legible, never broken. */
.hero--fallback .hero__video { display: none !important; }
.hero--fallback .hero__opening { display: none !important; }
.hero--fallback .hero__dark {
  background-color: #2E2150;
  /* 2026-08: the fallback's own dark wash is gone - the still gets the SAME
     text-anchored scrim as the video (.hero::after applies over this layer),
     so the fallback photograph plays clear outside the text pool too. */
  background-image: url("../img/hero/hero-fallback.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
@media (max-width: 700px) {
  .hero--fallback .hero__dark {
    background-image:
    /* 2026-08: own dark wash removed - the shared text-anchored scrim
       (.hero::after) is the only treatment, same as the video path. */
      url("../img/hero/hero-fallback-mobile.webp");
    /* 2026-08 focal-point shift (MOBILE ONLY - desktop keeps the base rule's
       center): the portrait crop shows only ~21% of this 1280x720 frame, and
       the group of women on the path sits at 60-69% of the image width - just
       past the right edge of a centred crop, so phones saw only the ridge.
       69% centres the figures in the visible slice (54.5%-75.4% at 375px);
       100% is the pan limit (cover cannot expose an empty edge). */
    background-position: 69% center;
  }
}

/* ============ STICKY FOOTER (2026-08, site-wide) ============
   Short pages (standardized empty pages, legal pages, 404) left a white
   body strip below the footer when content + footer < viewport. Standard
   flex column on <body>: the MAIN area absorbs the spare height, the footer
   lands on the viewport bottom edge; long pages are untouched (flex-grow
   only distributes SURPLUS space - it never shrinks or stretches the footer,
   whose own height/padding/layout are unchanged). CSS-only: every page is
   body > [skip-link, header, main, footer, fixed FABs] - no wrapper needed.
   dvh where supported keeps iOS URL-bar math honest; vh is the fallback. */
body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body > main { flex: 1 0 auto; width: 100%; }
body > .site-header,
body > .site-footer { flex-shrink: 0; }