/* ==========================================================================
   MEDYRA — Design System
   Deep navy + gold, taken from the MEDYRA brand mark. Editorial serif display.
   Authored by hand. No framework. Logical properties throughout for RTL.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Brand — navy ramp, taken from the MEDYRA identity */
  --navy-950: #060D1C;
  --navy-900: #0A1730;
  --navy-800: #112445;
  --navy-700: #1A3160;
  --navy-600: #24417A;
  --navy-500: #3A5DA0;
  --navy-200: #B6C5E0;
  --navy-100: #DDE5F2;
  --navy-50:  #EFF3FA;

  /* Neutrals — warm ivory canvas */
  --ivory:    #F7F9FC;
  --ivory-2:  #EEF2F8;
  --white:    #FFFFFF;
  --line:     #DCE3ED;
  --line-2:   #E9EEF5;

  /* Ink */
  --ink:      #0D1B2E;  /* headings, body                       ~15.8:1 on ivory */
  --ink-2:    #33445F;  /* strong secondary                      ~9.4:1  */
  --ink-3:    #5A6880;  /* secondary body — passes AA at 4.5:1   ~5.2:1  */

  /* Accents */
  --gold:      #8C6518;  /* AA-safe gold for small text on light ground */
  --gold-lite: #D4AF37;  /* decorative rules, icons (graphics 3:1) */
  --gold-soft: #F3E6C4;

  /* Semantic */
  --success:   #14684E;
  --danger:    #B3261E;
  --danger-bg: #FDECEA;
  --warning:   #8A5A00;

  /* Surfaces */
  --surface:      var(--white);
  --surface-sunk: var(--ivory-2);
  --on-dark:      #E7EDF7;
  --on-dark-mute: #A9B8D2;

  /* Type */
  --font-display: "Fraunces", "Iowan Old Style", Georgia, "Times New Roman", serif;
  /* IBM Plex Sans carries Latin, Latin-ext and Cyrillic, and has a matching
     Arabic sibling — so EN / FR / RU / AR all render from one type family
     rather than a patchwork of unrelated fonts. */
  --font-body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-arabic: "IBM Plex Sans Arabic", var(--font-body);

  --fs-hero:    clamp(2.9rem, 1.5rem + 5.6vw, 6.25rem);
  --fs-display: clamp(2.75rem, 1.55rem + 4.6vw, 5.25rem);
  --fs-h1:      clamp(2.25rem, 1.55rem + 2.9vw, 3.9rem);
  --fs-h2:      clamp(1.9rem,  1.45rem + 2.05vw, 3rem);
  --fs-h3:      clamp(1.35rem, 1.16rem + 0.85vw, 1.85rem);
  --fs-h4:      clamp(1.1rem,  1.02rem + 0.36vw, 1.3rem);
  --fs-lead:    clamp(1.075rem, 1.01rem + 0.34vw, 1.3rem);
  --fs-body:    1.0625rem;   /* 17px — comfortable, avoids iOS zoom */
  --fs-sm:      0.9375rem;
  --fs-xs:      0.8125rem;
  --fs-eyebrow: 0.75rem;

  /* Spacing — 4pt rhythm */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;  --sp-3: 0.75rem; --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;    --sp-7: 3rem;    --sp-8: 4rem;
  --sp-9: 6rem;     --sp-10: 8rem;

  --section-y: clamp(4.5rem, 3rem + 7vw, 9rem);
  --gutter:    clamp(1.25rem, 0.6rem + 2.6vw, 3rem);
  --maxw:      75rem;   /* 1200px */
  --maxw-wide: 84rem;
  --measure:   68ch;

  /* Radii */
  --r-sm: 6px;  --r-md: 10px;  --r-lg: 16px;  --r-xl: 24px;  --r-pill: 999px;

  /* Elevation — consistent scale, never ad-hoc */
  --e-1: 0 1px 2px rgba(9, 40, 36, .05), 0 1px 3px rgba(9, 40, 36, .04);
  --e-2: 0 2px 4px rgba(9, 40, 36, .05), 0 6px 16px -6px rgba(9, 40, 36, .10);
  --e-3: 0 4px 8px rgba(9, 40, 36, .05), 0 18px 40px -14px rgba(9, 40, 36, .18);
  --e-4: 0 8px 16px rgba(9, 40, 36, .06), 0 32px 64px -24px rgba(9, 40, 36, .28);

  /* Motion */
  --dur-1: 140ms;  --dur-2: 220ms;  --dur-3: 320ms;  --dur-4: 620ms;
  --ease-out:   cubic-bezier(.22, .61, .36, 1);
  --ease-in:    cubic-bezier(.55, .06, .68, .19);
  --ease-soft:  cubic-bezier(.32, .72, .28, 1);

  /* Layers */
  --z-base: 0; --z-raised: 10; --z-sticky: 40; --z-nav: 60; --z-drawer: 80;
  --z-overlay: 90; --z-toast: 100;

  /* Chrome height — the utility bar + nav that sit above the hero. Tokenised
     because the hero sizes itself against them (100svh minus this), so the
     two can never drift apart: change a header height here and the hero's
     first-viewport fit follows automatically. */
  --topbar-h:       34px;
  --nav-h:          72px;
  --nav-h-scrolled: 60px;
  --chrome-h: calc(var(--topbar-h) + var(--nav-h));
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-block-start: 6.5rem; /* clears the sticky header on anchor jumps */
  /* No overflow on the root. `body { overflow-x: hidden }` below propagates to
     the viewport, which is the conventional, well-supported way to suppress
     sideways overflow — and it leaves the root free of a scroll container, so
     position: sticky on the header keeps working. An earlier
     `overflow-x: clip` here was a non-standard belt-and-braces that is no
     longer needed now the off-axis reveal transforms are fixed. */
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--ink);
  background: var(--ivory);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  font-feature-settings: "kern" 1;
}
body[dir="rtl"], [lang="ar"] body, body[lang="ar"] { font-family: var(--font-arabic); }

img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.015em;
  font-variation-settings: "SOFT" 0, "WONK" 0;
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); line-height: 1.18; }
h4 { font-size: var(--fs-h4); font-family: var(--font-body); font-weight: 600; letter-spacing: 0; line-height: 1.35; }
p  { text-wrap: pretty; }

::selection { background: var(--navy-700); color: #fff; }

/* Visible, consistent focus. Never removed. */
:focus-visible {
  outline: 3px solid var(--navy-500);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.on-dark :focus-visible { outline-color: #E2C173; }

.skip-link {
  position: absolute; inset-inline-start: var(--sp-4); inset-block-start: -100px;
  z-index: var(--z-toast);
  background: var(--navy-800); color: #fff;
  padding: var(--sp-3) var(--sp-5); border-radius: var(--r-md);
  font-weight: 600; text-decoration: none;
  transition: inset-block-start var(--dur-2) var(--ease-out);
}
.skip-link:focus { inset-block-start: var(--sp-4); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-wide { max-width: var(--maxw-wide); }
.wrap-narrow { max-width: 46rem; }

.section { padding-block: var(--section-y); position: relative; }
.section--tight { padding-block: clamp(3rem, 2rem + 4vw, 5.5rem); }
.section--sunk { background: var(--ivory-2); }
.section--white { background: var(--white); }
.section--dark { background: var(--navy-900); color: var(--on-dark); }
.section--dark h1, .section--dark h2, .section--dark h3 { color: #fff; }

.grid { display: grid; gap: var(--sp-5); }
.g-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.g-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.g-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 980px) { .g-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 860px) { .g-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .g-2, .g-3, .g-4 { grid-template-columns: minmax(0, 1fr); } }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(2rem, 1rem + 5vw, 5rem);
  align-items: center;
}
.split--7-5 { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.split--5-7 { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
@media (max-width: 900px) {
  .split, .split--7-5, .split--5-7 { grid-template-columns: minmax(0, 1fr); }
}

.stack > * + * { margin-block-start: var(--sp-4); }
.stack-lg > * + * { margin-block-start: var(--sp-6); }
.center { text-align: center; margin-inline: auto; }
.measure { max-width: var(--measure); }
.measure-sm { max-width: 52ch; }

/* --------------------------------------------------------------------------
   4. Typographic components
   -------------------------------------------------------------------------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--navy-600); margin-block-end: var(--sp-4);
}
.eyebrow::before {
  content: ""; inline-size: 28px; block-size: 1px;
  background: var(--gold-lite); flex: none;
}
.section--dark .eyebrow { color: #9FB6DE; }
.section--dark .eyebrow::before { background: var(--gold-lite); }

.display { font-size: var(--fs-display); line-height: 1.02; letter-spacing: -0.03em; }
.lead { font-size: var(--fs-lead); line-height: 1.6; color: var(--ink-2); max-width: var(--measure); }
.section--dark .lead { color: var(--on-dark-mute); }
.muted { color: var(--ink-3); }
.small { font-size: var(--fs-sm); }
.xs { font-size: var(--fs-xs); }
.serif-accent { font-family: var(--font-display); font-style: italic; font-weight: 300; }
.tnum { font-variant-numeric: tabular-nums; }

.prose p { color: var(--ink-2); max-width: var(--measure); }
.prose > * + * { margin-block-start: var(--sp-4); }
.prose h3 { margin-block-start: var(--sp-7); }
.prose ul, .prose ol { padding-inline-start: 1.25em; color: var(--ink-2); }
.prose li + li { margin-block-start: var(--sp-2); }
.prose li::marker { color: var(--navy-500); }
.prose strong { color: var(--ink); font-weight: 600; }

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--navy-700);
  --btn-fg: #fff;
  --btn-bd: var(--navy-700);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-3);
  min-block-size: 48px;               /* ≥44px touch target */
  padding: var(--sp-3) var(--sp-6);
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  border-radius: var(--r-pill);
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: 0.005em;
  text-decoration: none; cursor: pointer;
  touch-action: manipulation;
  transition: background-color var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out),
              transform var(--dur-1) var(--ease-out);
}
.btn:hover { background: var(--navy-600); border-color: var(--navy-600); box-shadow: var(--e-2); }
.btn:active { transform: scale(.975); }
.btn svg { flex: none; }
.btn .btn-arrow { transition: transform var(--dur-2) var(--ease-out); }
.btn:hover .btn-arrow { transform: translateX(3px); }
[dir="rtl"] .btn:hover .btn-arrow { transform: translateX(-3px); }

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--navy-700); --btn-bd: var(--line); }
.btn--ghost:hover { background: var(--navy-50); border-color: var(--navy-200); box-shadow: none; }
.btn--light { --btn-bg: #fff; --btn-fg: var(--navy-800); --btn-bd: #fff; }
.btn--light:hover { background: var(--navy-50); border-color: var(--navy-50); }
.btn--outline-light { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: rgba(255,255,255,.42); }
.btn--outline-light:hover { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.7); }
/* Brass — the luxury accent. 7.4:1 against its own dark label, so it carries
   the primary action on the dark hero without dropping below AA. */
.btn--gold {
  --btn-bg: linear-gradient(135deg, #F4E09B 0%, #D9B65C 32%, #C9A227 62%, #A67C1B 100%);
  --btn-fg: #060D1C;
  --btn-bd: transparent;
}
.btn--gold:hover {
  background: linear-gradient(135deg, #F9EAB4 0%, #E3C673 32%, #D4AF37 62%, #B98D24 100%);
  border-color: transparent;
  box-shadow: 0 10px 32px -10px rgba(212,175,55,.60);
}
.btn--lg { min-block-size: 56px; padding-inline: var(--sp-7); font-size: var(--fs-body); }
.btn--block { display: flex; inline-size: 100%; }

.btn[disabled], .btn[aria-disabled="true"] {
  opacity: .45; cursor: not-allowed; pointer-events: none;
}
.btn.is-loading { pointer-events: none; }
.btn.is-loading .btn-label { opacity: .6; }
.spinner {
  inline-size: 18px; block-size: 18px; flex: none;
  border: 2px solid currentColor; border-block-start-color: transparent;
  border-radius: 50%; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.link-arrow {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--navy-700); font-weight: 600; font-size: var(--fs-sm);
  text-decoration: none;
  padding-block: var(--sp-2);       /* enlarges the hit area */
  border-block-end: 1px solid transparent;
  transition: border-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.link-arrow:hover { border-block-end-color: currentColor; }
.link-arrow svg { transition: transform var(--dur-2) var(--ease-out); }
.link-arrow:hover svg { transform: translateX(3px); }
[dir="rtl"] .link-arrow svg { transform: scaleX(-1); }
[dir="rtl"] .link-arrow:hover svg { transform: scaleX(-1) translateX(3px); }
.section--dark .link-arrow { color: #9FB6DE; }

/* --------------------------------------------------------------------------
   6. Header / navigation
   -------------------------------------------------------------------------- */
.topbar {
  background: var(--navy-950); color: var(--on-dark-mute);
  font-size: var(--fs-xs);
  border-block-end: 1px solid rgba(255,255,255,.07);
}
.topbar-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); min-block-size: var(--topbar-h); flex-wrap: wrap;
}
.topbar a { color: var(--on-dark); text-decoration: none; }
.topbar a:hover { text-decoration: underline; }
.topbar-facts { display: flex; align-items: center; gap: var(--sp-5); }
@media (max-width: 720px) { .topbar-facts { display: none; } }

.header {
  position: sticky; inset-block-start: 0; z-index: var(--z-nav);
  background: rgba(247, 249, 252, .82);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-block-end: 1px solid transparent;
  transition: background-color var(--dur-3) var(--ease-out),
              border-color var(--dur-3) var(--ease-out),
              box-shadow var(--dur-3) var(--ease-out);
}
.header.is-scrolled {
  background: rgba(247, 249, 252, .95);
  border-block-end-color: var(--line);
  box-shadow: 0 1px 24px -12px rgba(10,23,48,.35);
}
.nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5); min-block-size: var(--nav-h);
  transition: min-block-size var(--dur-3) var(--ease-out);
}
.header.is-scrolled .nav { min-block-size: var(--nav-h-scrolled); }

.brand {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  text-decoration: none; flex: none;
  min-block-size: 44px;   /* the mark is 38px; the link must still be tappable */
}
.brand-mark { inline-size: 44px; block-size: 44px; flex: none; }
.brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.brand-name { font-family: var(--font-display); font-size: 1.235rem; font-weight: 500; letter-spacing: -0.02em; color: var(--ink); }
.brand-sub { font-size: 0.625rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-3); font-weight: 600; }

.nav-links { display: flex; align-items: center; gap: var(--sp-1); list-style: none; padding: 0; }
.nav-link {
  display: inline-flex; align-items: center; min-block-size: 44px;
  padding-inline: var(--sp-4); border-radius: var(--r-pill);
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2); text-decoration: none;
  position: relative; white-space: nowrap;
  transition: color var(--dur-2) var(--ease-out), background-color var(--dur-2) var(--ease-out);
}
.nav-link:hover { color: var(--navy-700); background: var(--navy-50); }
.nav-link[aria-current="page"] { color: var(--navy-700); font-weight: 600; }
.nav-link[aria-current="page"]::after {
  content: ""; position: absolute; inset-block-end: 6px;
  inset-inline: var(--sp-4); block-size: 2px; border-radius: 2px;
  background: var(--gold-lite);
}

/* "Patients" — a hover-triggered submenu holding Patient Journey and
   Patient Stories, styled as a plain button so it never behaves like a
   dead link of its own. Reuses .nav-link for the trigger's look, so any
   change to nav-link styling (colour, overlay mode, single-line rule)
   applies here automatically instead of needing a parallel rule. */
.nav-drop { position: relative; }
.nav-drop-btn {
  background: none; border: 0; cursor: pointer; font: inherit; gap: var(--sp-2);
}
.nav-drop-btn .chev { transition: transform var(--dur-2) var(--ease-out); flex: none; }
.nav-drop-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.nav-drop-menu {
  position: absolute; inset-block-start: 100%; inset-inline-start: 0;
  min-inline-size: 12rem; padding: var(--sp-2);
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--e-3);
  list-style: none; margin: 0; margin-block-start: 8px; z-index: var(--z-drawer);
  opacity: 0; transform: translateY(-6px) scale(.98); transform-origin: top;
  visibility: hidden; pointer-events: none;
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out), visibility var(--dur-2);
}
.nav-drop-menu a {
  display: flex; align-items: center; min-block-size: 44px; padding-inline: var(--sp-3);
  border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2);
  text-decoration: none; white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.nav-drop-menu a:hover, .nav-drop-menu a:focus-visible { background: var(--navy-50); color: var(--navy-700); }
.nav-drop-menu a[aria-current="page"] { color: var(--navy-700); font-weight: 600; }
/* Hover for mouse users, :focus-within for keyboard tabbing, .is-open for
   the touch/click fallback JS adds — the same three-way pattern used
   nowhere else on this site because nothing else needed true hover-to-open
   before now; .switch (language/currency) is deliberately click-only. */
.nav-drop:hover .nav-drop-menu,
.nav-drop:focus-within .nav-drop-menu,
.nav-drop.is-open .nav-drop-menu {
  opacity: 1; transform: none; visibility: visible; pointer-events: auto;
}

/* Overlay mode: the header sits directly above a dark hero, so it wears the
   hero's own top colour until the user scrolls, then reverts to ivory glass. */
.header--overlay:not(.is-scrolled) {
  background: var(--navy-950);
  backdrop-filter: none; -webkit-backdrop-filter: none;
  border-block-end-color: rgba(255,255,255,.07);
}
.header--overlay:not(.is-scrolled) .brand-name { color: #fff; }
.header--overlay:not(.is-scrolled) .brand-sub  { color: rgba(231,237,247,.52); }
.header--overlay:not(.is-scrolled) .nav-link,
.header--overlay:not(.is-scrolled) .nav-drop-btn,
.header--overlay:not(.is-scrolled) .switch-btn { color: rgba(231,237,247,.80); }
.header--overlay:not(.is-scrolled) .nav-link:hover,
.header--overlay:not(.is-scrolled) .nav-drop-btn:hover,
.header--overlay:not(.is-scrolled) .switch-btn:hover { color: #fff; background: rgba(255,255,255,.09); }
.header--overlay:not(.is-scrolled) .nav-link[aria-current="page"] { color: #fff; }
.header--overlay:not(.is-scrolled) .burger { color: #fff; }
.header--overlay:not(.is-scrolled) .burger:hover { background: rgba(255,255,255,.09); }
.header--overlay:not(.is-scrolled) .nav-actions > .btn {
  --btn-bg: linear-gradient(135deg, #F4E09B 0%, #D9B65C 32%, #C9A227 62%, #A67C1B 100%);
  --btn-fg: #060D1C;
  --btn-bd: transparent;
}
.header--overlay:not(.is-scrolled) .nav-actions > .btn:hover {
  background: linear-gradient(135deg, #F9EAB4 0%, #E3C673 32%, #D4AF37 62%, #B98D24 100%);
  border-color: transparent;
}

.nav-actions { display: flex; align-items: center; gap: var(--sp-3); }
.nav-actions > .btn { white-space: nowrap; }
@media (max-width: 1080px) { .nav-links, .nav-actions .btn { display: none; } }

/* Language + currency switchers — now footer-only (moved out of the header
   nav-actions entirely). The .switch/.switch-btn/.switch-menu component
   itself, and the JS/i18n wiring that drives it, are unchanged; only the
   footer-scoped overrides two blocks down are new. */
.switch {
  position: relative; display: inline-flex; align-items: center;
}
.switch-btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: 44px; padding-inline: var(--sp-3);
  border-radius: var(--r-pill); font-size: var(--fs-sm); font-weight: 600;
  color: var(--ink-2);
  transition: background-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.switch-btn:hover { background: var(--navy-50); color: var(--navy-700); }
.switch-btn .chev { transition: transform var(--dur-2) var(--ease-out); }
.switch-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.switch-menu {
  position: absolute; inset-block-start: calc(100% + 8px); inset-inline-end: 0;
  min-inline-size: 11rem; padding: var(--sp-2);
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--e-3);
  list-style: none; margin: 0; z-index: var(--z-drawer);
  opacity: 0; transform: translateY(-6px) scale(.98); transform-origin: top;
  visibility: hidden; pointer-events: none;
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out), visibility var(--dur-2);
}
.switch.is-open .switch-menu { opacity: 1; transform: none; visibility: visible; pointer-events: auto; }
.switch-menu button {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  inline-size: 100%; min-block-size: 44px; padding-inline: var(--sp-3);
  border-radius: var(--r-sm); font-size: var(--fs-sm); text-align: start;
  transition: background-color var(--dur-1) var(--ease-out);
}
.switch-menu button:hover { background: var(--navy-50); }
.switch-menu button[aria-checked="true"] { color: var(--navy-700); font-weight: 600; }
.switch-menu button[aria-checked="true"]::after { content: "✓"; color: var(--navy-600); }
.switch-menu .opt-sub { color: var(--ink-3); font-size: var(--fs-xs); font-weight: 400; }

/* Floating WhatsApp button — fixed to the viewport, not the header, so it
   stays reachable the entire time a visitor is on the page, independent of
   scroll position or which section is showing. Sits below the header/drawer
   in the stacking order (--z-sticky, not --z-nav/--z-drawer) so the mobile
   drawer's full-screen scrim still covers it correctly while open. */
.whatsapp-fab {
  position: fixed;
  inset-block-end: clamp(1rem, 3vw, 1.75rem);
  inset-inline-end: clamp(1rem, 3vw, 1.75rem);
  z-index: var(--z-sticky);
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 56px; block-size: 56px;
  border-radius: 50%;
  background: #25D366;
  color: #fff;
  box-shadow: 0 6px 20px rgba(10,23,48,.32);
  transition: transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.whatsapp-fab:hover { transform: scale(1.08); box-shadow: 0 10px 26px rgba(10,23,48,.38); }
.whatsapp-fab:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.whatsapp-fab svg { inline-size: 30px; block-size: 30px; }
@media (max-width: 480px) {
  .whatsapp-fab { inline-size: 50px; block-size: 50px; }
  .whatsapp-fab svg { inline-size: 26px; block-size: 26px; }
}
@media (prefers-reduced-motion: reduce) {
  .whatsapp-fab:hover { transform: none; }
}

/* Mobile drawer */
.burger {
  display: none; align-items: center; justify-content: center;
  inline-size: 48px; block-size: 48px; border-radius: var(--r-pill);
  color: var(--ink);
  transition: background-color var(--dur-2) var(--ease-out);
}
.burger:hover { background: var(--navy-50); }
@media (max-width: 1080px) { .burger { display: inline-flex; } }

.drawer-scrim {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  background: rgba(6, 30, 28, .55);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-3) var(--ease-out), visibility var(--dur-3);
}
.drawer-scrim.is-open { opacity: 1; visibility: visible; }

.drawer {
  position: fixed; inset-block: 0; inset-inline-end: 0; z-index: var(--z-toast);
  inline-size: min(24rem, 88vw);
  background: var(--ivory);
  box-shadow: var(--e-4);
  display: flex; flex-direction: column;
  padding: var(--sp-5) var(--sp-5) max(var(--sp-6), env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(102%);
  visibility: hidden;
  transition: transform var(--dur-4) var(--ease-soft), visibility var(--dur-4);
}
[dir="rtl"] .drawer { transform: translateX(-102%); }
.drawer.is-open { transform: none; visibility: visible; }
.drawer-head { display: flex; align-items: center; justify-content: space-between; margin-block-end: var(--sp-6); }
.drawer-links { list-style: none; padding: 0; display: flex; flex-direction: column; }
.drawer-links a {
  display: flex; align-items: center; justify-content: space-between;
  min-block-size: 56px; padding-inline: var(--sp-2);
  font-family: var(--font-display); font-size: 1.35rem;
  text-decoration: none; color: var(--ink);
  border-block-end: 1px solid var(--line-2);
  transition: color var(--dur-2) var(--ease-out), padding-inline-start var(--dur-2) var(--ease-out);
}
.drawer-links a:hover { color: var(--navy-700); padding-inline-start: var(--sp-4); }
.drawer-links a[aria-current="page"] { color: var(--navy-700); }

/* "Patients" — an expandable group inside the drawer, styled to match the
   surrounding .drawer-links rows (same row height, divider, type scale) so
   it doesn't read as a bolted-on component. Driven entirely by
   aria-expanded, toggled in initHeader(); the grid-rows trick animates
   height open/closed without ever reading scrollHeight in JS. */
.drawer-group-btn {
  display: flex; align-items: center; justify-content: space-between;
  inline-size: 100%; min-block-size: 56px; padding-inline: var(--sp-2);
  font-family: var(--font-display); font-size: 1.35rem; font-weight: 400; text-align: start;
  color: var(--ink); background: none; border: 0; border-block-end: 1px solid var(--line-2);
  cursor: pointer;
  transition: color var(--dur-2) var(--ease-out);
}
.drawer-group-btn:hover { color: var(--navy-700); }
.drawer-group-btn .chev { transition: transform var(--dur-2) var(--ease-out); flex: none; }
.drawer-group-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.drawer-group-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-3) var(--ease-out); }
.drawer-group-btn[aria-expanded="true"] + .drawer-group-panel { grid-template-rows: 1fr; }
.drawer-group-panel > div { overflow: hidden; }
.drawer-group-panel a {
  display: flex; align-items: center;
  min-block-size: 48px; padding-inline: var(--sp-5);
  font-size: 1.05rem; color: var(--ink-3); text-decoration: none;
  border-block-end: 1px solid var(--line-2);
  transition: color var(--dur-2) var(--ease-out), padding-inline-start var(--dur-2) var(--ease-out);
}
.drawer-group-panel a:hover { color: var(--navy-700); padding-inline-start: var(--sp-6); }
.drawer-group-panel a[aria-current="page"] { color: var(--navy-700); font-weight: 600; }

.drawer-foot { margin-block-start: auto; padding-block-start: var(--sp-6); display: grid; gap: var(--sp-3); }

/* Language / currency chips inside the drawer */
.drawer-opts { display: grid; gap: var(--sp-2); margin-block: var(--sp-6) var(--sp-5); }
.drawer-opts + .drawer-opts { margin-block-start: 0; }
.opt-label { font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); font-weight: 600; }
.opt {
  display: inline-flex; align-items: center; justify-content: center;
  min-block-size: 44px; min-inline-size: 56px; padding-inline: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--white); font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2);
  text-decoration: none;   /* also used as an anchor for the speciality jump-nav */
  transition: background-color var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.opt:hover { border-color: var(--navy-200); background: var(--navy-50); }
.opt[aria-checked="true"] { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }

/* --------------------------------------------------------------------------
   7. Hero — dark editorial
   The topbar, the header in overlay mode and this section share --navy-950 at
   their meeting edges, so the top of the page reads as one continuous mass
   rather than three stacked bands.
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  color: var(--on-dark);
  /* Kept as a safety net beneath the media layer: if the poster or video
     fails to load for any reason, this still reads as an intentional dark
     hero rather than a broken gap. */
  background: linear-gradient(168deg, var(--navy-950) 0%, var(--navy-900) 46%, #14294E 100%);
  padding-block: clamp(1.75rem, 1rem + 2.6vw, 3.25rem) clamp(1.25rem, 1rem + 1.4vw, 2rem);
  /* Sized against the chrome above it rather than a fixed pixel height: the
     hero fills exactly what's left of the first viewport, so the headline,
     lead and CTA all land above the fold on a 768px laptop without the
     composition turning into a letterbox strip on a tall monitor. svh (not
     vh) so mobile browser UI collapsing doesn't jolt the layout; the vh line
     above it is the fallback for engines without svh. */
  min-block-size: calc(100vh - var(--chrome-h));
  min-block-size: calc(100svh - var(--chrome-h));
  display: grid;
  align-items: center;
}
@media (max-width: 940px) {
  /* Mobile never loads the video (see initHeroVideo in site.js), and without
     the side image panel the content is shorter — a fixed tall minimum would
     open the page on an oversized, mostly-empty hero. */
  .hero { min-block-size: auto; }
}

/* The single flow child of the grid — lets `align-items: center` on .hero
   vertically centre the whole copy+assure stack without needing flexbox
   distribution logic across two separate blocks. */
.hero-inner { position: relative; z-index: 1; }

/* ---- Background media (poster + progressive-enhancement video) -----------
   Sits further back than every existing atmosphere layer below (hero-bg at
   -3, grain at -2, lines at -1) so all of that keeps layering on top of the
   footage exactly as it did on top of the flat gradient before. */
/* --hero-progress is written by initHeroParallax() in site.js: 0 while the
   hero is fully in view, rising toward 1 as it scrolls away. Driving the
   drift from a single scalar keeps the video and the header's own scrolled
   transition on the same clock, so the two read as one coordinated move
   rather than two effects that happen to fire near each other.

   The layer is pre-scaled 1.08 so the upward drift never exposes an edge,
   and the drift itself is a compositor-only translate3d — object-position
   is deliberately NOT animated, since changing it repaints every video
   frame and was what made the old hero drop frames on real hardware. The
   scale is what makes the framing "shift subtly" without that cost. */
.hero-media {
  position: absolute; inset: 0; z-index: -6; overflow: hidden;
  transform: translate3d(0, calc(var(--hero-progress, 0) * -7%), 0) scale(1.08);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .hero-media { transform: none; will-change: auto; }
}
.hero-media-poster, .hero-media-video {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%; object-fit: cover;
}
/* hero-poster.jpg is pre-cropped to the text-free consultation band of the
   source photo (see README §6), so it's already centred on the subjects —
   plain center is correct here. */
.hero-media-poster {
  object-position: center;
}
/* hero-medyra-1080.mp4 keeps the doctor right-of-centre with the on-wall
   logo card in the far corner; biasing left keeps her in frame on narrow
   crops instead of centring on the gap between her and the logo. Verified
   against the real footage at the actual rendered hero height. */
.hero-media-video {
  object-position: 38% center;
  opacity: 0;
  transition: opacity 1200ms var(--ease-out);
}
.hero-media-video.is-playing { opacity: 1; }

/* The overlay this whole feature was requested for: a navy scrim so white/
   gold text and the flight animation stay legible over moving footage. Same
   gradient direction as .hero's own background so the two read as one
   surface rather than a photo with a filter slapped on it. */
.hero-media-overlay {
  position: absolute; inset: 0; z-index: -5;
  background: linear-gradient(168deg,
    rgba(6,13,28,.90) 0%, rgba(10,23,48,.74) 46%, rgba(20,41,78,.58) 100%);
}

/* Layered atmosphere: a warm high glow, a cool low one, the meridian arcs,
   and a very fine grain so the large flat area has some material to it. */
.hero-bg {
  position: absolute; inset: 0; z-index: -3;
  background:
    radial-gradient(100% 70% at 82% 2%, rgba(58,93,160,.30), transparent 62%),
    radial-gradient(80% 60% at 6% 96%, rgba(201,153,47,.16), transparent 64%);
}
.hero-grain {
  position: absolute; inset: 0; z-index: -2; opacity: .045; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}
.hero-lines {
  position: absolute; inset-block-start: -18%; inset-inline-end: -16%;
  inline-size: min(60rem, 96vw); z-index: -1;
  opacity: .22; pointer-events: none;
  filter: invert(1) brightness(1.7);   /* the arcs were drawn for a light ground */
}

/* ---- Diagonal flight path --------------------------------------------------
   Echoes the aircraft in the MEDYRA mark. The track is a zero-height rail
   rotated to the hero's diagonal, and the plane translates along its own X
   axis — so its nose always points exactly where it is travelling, at any
   viewport aspect ratio. Sits at z-index -1, behind all hero content. */
.hero-flight {
  position: absolute; inset: 0; z-index: 1;
  overflow: hidden; pointer-events: none;
}
[dir="rtl"] .hero-flight { transform: scaleX(-1); }   /* mirror, don't re-angle */

/* The rail starts at the dead centre of the hero and climbs out to the
   top-right. Anchoring it here keeps the plane clear of the CTA buttons in
   the lower left, and lets it read as departing from the middle of the frame
   rather than sliding in from an edge. */
.hero-flight-track {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  inline-size: 100%;
  block-size: 0;
  transform: rotate(-34deg);
  transform-origin: 0 50%;
}
/* A phone hero is far taller than it is wide, so a 34° climb barely rises.
   Steepen it, and lengthen the rail to guarantee it still clears the edge. */
@media (max-width: 940px) {
  /* Stacked full-width CTAs sit near mid-height on a phone, so a launch at
     50% would put the plane right on top of them — the exact thing this
     layout is meant to avoid. Start above them instead. */
  .hero-flight-track { inset-block-start: 34%; inline-size: 130%; transform: rotate(-42deg); }
}

.hero-plane {
  position: absolute; inset-block-start: -13px; inset-inline-start: 0;
  inline-size: 100%;                 /* so translateX% is rail-relative */
  animation: flyOut 22s cubic-bezier(.34, 0, .5, 1) infinite;
  will-change: transform;
}
/* Scale lives on an inner wrapper so it can't compose with the rail
   translation. The plane grows as it climbs — it reads as approaching from
   the far distance rather than simply sliding across. */
.hero-plane-body {
  /* inline-flex, NOT flex: `display: flex` blockifies the span to the full
     width of the rail, which drags transform-origin: 100% out to the far
     right and throws the scale hundreds of pixels off course. It has to
     shrink-wrap so the origin lands on the aircraft's nose.
     The negative start margin pulls the trail behind the nose, so the
     aircraft itself — not the tail of its vapour trail — is what sits on the
     rail's origin at the centre of the hero. */
  --trail-len: clamp(120px, 20vw, 320px);
  display: inline-flex; align-items: center;
  margin-inline-start: calc(-1 * var(--trail-len));
  transform-origin: 100% 50%;
  opacity: 0;
  animation: planeApproach 22s cubic-bezier(.34, 0, .5, 1) infinite;
  will-change: transform, opacity;
}
.hero-plane-trail {
  flex: none; block-size: 2px; border-radius: 2px;
  inline-size: var(--trail-len);
  background: linear-gradient(90deg,
    rgba(212,175,55,0) 0%, rgba(212,175,55,.45) 46%, rgba(249,236,190,1) 100%);
}
.hero-plane-icon {
  flex: none; margin-inline-start: 3px;
  inline-size: clamp(28px, 2.8vw, 42px); block-size: auto;
  color: #F9ECBE;
  filter: drop-shadow(0 0 14px rgba(212,175,55,.75));
}
/* The rail is one hero-width long, and clearing the right edge from the centre
   costs (0.5 / cos 34°) ≈ 0.60 of it — so ending the travel at 68% means the
   aircraft is on screen for almost the whole flight phase rather than leaving
   in the first few seconds. Travel spans 85% of a 22s loop, which holds the
   same ~50px/s pace as a 30s loop while cutting the dead time after it exits. */
@keyframes flyOut {
  0%   { transform: translateX(0%); }
  85%  { transform: translateX(68%); }
  100% { transform: translateX(68%); }
}
@keyframes planeApproach {
  0%   { opacity: 0;   transform: scale(.45); }
  7%   { opacity: .95; }
  72%  { opacity: .95; transform: scale(1); }
  85%  { opacity: 0;   transform: scale(1.04); }
  100% { opacity: 0;   transform: scale(1.04); }
}

.hero .eyebrow { color: #A9C0E6; }
.hero .eyebrow::before { background: var(--gold-lite); }

/* No longer constrained by a grid column now that the side image panel is
   gone — without a cap, the display type would stretch edge-to-edge on a
   wide desktop viewport. */
.hero-copy { max-inline-size: 50rem; }

/* Headline: each line rides up out of its own mask. */
/* Width-driven like every other display size on the site, but additionally
   capped against viewport *height*: this headline runs to three lines, so on
   a 768px laptop the width-only clamp alone produced ~300px of type and
   pushed the CTA below the fold. 10.2vh keeps all three lines proportionate
   to the space actually available. Wide-and-tall screens are unaffected —
   there the width clamp is still the smaller of the two. */
.hero-title {
  font-size: min(var(--fs-hero), 10.2vh);
  line-height: 0.99;
  letter-spacing: -0.038em;
  color: #fff;
  font-weight: 300;
}
.hero-title .line {
  display: block;
  overflow: hidden;
  padding-block-end: .1em;      /* descenders clear the mask edge */
  margin-block-end: -.1em;
}
.hero-title .line > span {
  display: block;
  transform: translate3d(0, 108%, 0);
  transition: transform 1150ms var(--ease-soft);
  transition-delay: var(--line-delay, 0ms);
  will-change: transform;
}
.hero-title.is-in .line > span { transform: none; }
.hero-title em {
  font-style: italic;
  font-weight: 300;
  color: var(--gold-lite);
}

.hero-lead {
  margin-block-start: clamp(1.1rem, 0.8rem + 0.9vw, 1.6rem);
  /* 38rem lands around 60 characters — still inside the comfortable measure,
     but one line shorter than the old 34rem, which is ~42px of first-viewport
     height back for free without touching the copy itself. */
  max-width: 38rem;
  color: var(--on-dark-mute);
  font-size: clamp(1.075rem, 1rem + 0.42vw, 1.28rem);
}
.hero-cta {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  margin-block-start: clamp(1.4rem, 1rem + 1.1vw, 2rem);
}
/* On narrow screens a wrapped button label reads as a mistake. Full-width
   stacked buttons are deliberate-looking and easier to hit — but --btn-lg's
   48px inline padding has to come down too, or the label still wraps. */
@media (max-width: 560px) {
  .hero-cta { gap: var(--sp-3); }
  .hero-cta .btn { flex: 1 0 100%; padding-inline: var(--sp-5); }
}

/* Service band — hairlines, not ticks. */
.hero-assure {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0; list-style: none; padding: 0;
  margin-block-start: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  padding-block-start: clamp(1rem, 0.75rem + 1vw, 1.5rem);
  border-block-start: 1px solid rgba(255,255,255,.14);
}
/* Two columns are held all the way down to 360px — stacking all four rows
   adds ~150px of height on a phone for no readability gain. */
@media (max-width: 860px) { .hero-assure { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5) var(--sp-4); } }
@media (max-width: 360px) { .hero-assure { grid-template-columns: minmax(0, 1fr); } }
.hero-assure li {
  padding-inline: 0 var(--sp-5);
  border-inline-end: 1px solid rgba(255,255,255,.11);
}
.hero-assure li:last-child { border-inline-end: 0; padding-inline-end: 0; }
@media (max-width: 860px) {
  .hero-assure li:nth-child(2n) { border-inline-end: 0; padding-inline-end: 0; }
  .hero-assure li:nth-child(2n+1) { padding-inline-end: var(--sp-4); }
}
@media (max-width: 360px) {
  .hero-assure li { border-inline-end: 0; padding-inline-end: 0; }
}
.hero-assure-k {
  display: block; font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--gold-lite);
  margin-block-end: var(--sp-2);
}
.hero-assure-v { display: block; font-size: var(--fs-sm); color: #DDE5F2; line-height: 1.45; }

/* A normal-flow badge under the CTAs — not floated over the video. It used
   to carry the same glass/blur treatment as the old photo-frame version,
   but that meant continuously blurring a live, playing video every frame
   for as long as this badge is on screen — i.e. for the entire time a
   visitor sits on the hero. Combined with the header's own backdrop-filter
   and the scroll-driven parallax/reveal work, that was heavy enough to
   drop frames on real hardware, visible as a brief blank/white flash mid-
   scroll. A solid, slightly darker panel reads almost identically at this
   size and costs nothing to composite. */
.hero-credential {
  display: inline-flex; align-items: center; gap: var(--sp-4);
  max-inline-size: min(26rem, 100%);
  margin-block-start: clamp(1.1rem, 0.8rem + 1vw, 1.5rem);
  padding: var(--sp-3) var(--sp-5);
  background: rgba(8,18,38,.82);
  border: 1px solid rgba(201,153,47,.30);
  border-radius: var(--r-lg);
}
.hero-credential-num {
  font-family: var(--font-display); font-size: clamp(1.75rem, 1.4rem + 1.1vw, 2.35rem);
  line-height: 1; color: #fff; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.hero-credential-txt { font-size: var(--fs-xs); color: #CBD8EC; line-height: 1.5; }

/* Scroll cue */
.hero-scroll {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-block-start: clamp(1.1rem, 0.8rem + 1.2vw, 1.75rem);
  font-size: var(--fs-xs); letter-spacing: .16em; text-transform: uppercase;
  color: rgba(203,216,236,.68);   /* keeps the cue above 4.5:1 once alpha is composited */
}
.hero-scroll-line {
  position: relative; inline-size: 56px; block-size: 1px; flex: none;
  background: rgba(255,255,255,.18); overflow: hidden;
}
.hero-scroll-line::after {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0;
  inline-size: 40%; background: var(--gold-lite);
  animation: scrollCue 2.6s var(--ease-soft) infinite;
}
@keyframes scrollCue {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(250%); }
  100% { transform: translateX(250%); }
}
[dir="rtl"] .hero-scroll-line::after { animation-direction: reverse; }
/* Placed after the base rule on purpose — same specificity, so source order
   decides. The cue only earns its space on desktop. */
@media (max-width: 940px) { .hero-scroll { display: none; } }

/* Short-viewport desktop, in two stages. The width-based clamps above are
   already at their small end on these screens, so the remaining savings
   have to come from *height*-specific trims rather than shrinking type
   further. Both are scoped to min-width 941px so none of it touches the
   mobile layout, which is content-driven and has its own breakpoints.

   Stage 1 — 1440×900 / 1600×900 class laptops: tighten the rhythm only.
   The scroll cue stays; there's still room for it to read as deliberate. */
@media (min-width: 941px) and (max-height: 920px) {
  .hero { padding-block: 1.75rem 1.5rem; }
  .hero-credential { margin-block-start: 1rem; }
  .hero-assure { margin-block-start: 1.25rem; padding-block-start: 1rem; }
}
/* Stage 2 — 1366×768 and shorter. The cue now goes too: the assure band
   peeking past the fold is already the affordance it was standing in for,
   so dropping it removes a redundancy rather than losing a signal. */
@media (min-width: 941px) and (max-height: 820px) {
  .hero { padding-block: 1.5rem 1.25rem; }
  .hero-scroll { display: none; }
  .hero-credential { margin-block-start: 0.9rem; }
  .hero-assure { margin-block-start: 1.1rem; padding-block-start: 0.9rem; }
}

/* --------------------------------------------------------------------------
   8. Accreditation marquee
   -------------------------------------------------------------------------- */
.marquee {
  --marquee-dur: 46s;
  position: relative; overflow: hidden;
  padding-block: var(--sp-5);
  border-block: 1px solid var(--line);
  background: var(--white);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-track { display: flex; inline-size: max-content; animation: marquee var(--marquee-dur) linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding-inline: clamp(1.25rem, 2.4vw, 2.5rem);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-3);
  white-space: nowrap;
}
.marquee-item svg { color: var(--navy-500); flex: none; }
@keyframes marquee { to { transform: translateX(-50%); } }
[dir="rtl"] .marquee-track { animation-direction: reverse; }

/* --------------------------------------------------------------------------
   9. Cards
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  transition: transform var(--dur-3) var(--ease-out),
              box-shadow var(--dur-3) var(--ease-out),
              border-color var(--dur-3) var(--ease-out);
}
/* The whole card is one anchor, and text-decoration propagates from an
   ancestor to everything inside it — so the UA underline lands on the
   description and the meta row too. Clear it here, then put a deliberate
   rule back under the heading alone. */
.card--link { text-decoration: none; }
.card--link h3 {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: var(--navy-200);
  transition: text-decoration-color var(--dur-2) var(--ease-out);
}
.card--link:hover h3,
.card--link:focus-visible h3 { text-decoration-color: var(--gold-lite); }

.card--link:hover, .card--link:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--e-3);
  border-color: var(--navy-200);
}

/* ---- Boundary highlight (value section only) -------------------------------
   The doubled ring (border plus a 1px outset shadow) reads as a crisp 2px gold
   boundary without changing the box size, so nothing reflows. There is no lift
   and no pointer cursor: these are informational, not links.
   Scope matters — this is intentionally limited to .value-row / .value-feature
   so the treatment cards and every other card keep their original hover. */
@media (hover: hover) {
  /* Scoped by the .value-cards wrapper, NOT by bare .card — otherwise this
     leaks onto the treatment cards and every other card on the site. */
  .value-cards .card:hover {
    border-color: rgba(201,162,39,.55);
    box-shadow: 0 0 0 1px rgba(201,162,39,.30),
                0 14px 34px -20px rgba(10,23,48,.45);
  }
  .value-cards .card:hover .card-icon {
    background: var(--navy-700);
    color: #F7E7AE;
  }
}

/* ---- Pointer spotlight -----------------------------------------------------
   --mx/--my are written by site.js on pointermove (fine pointers only). They
   default to the centre, so with JS off or on touch the card still lights up
   evenly rather than looking broken. Applied only to cards that are actually
   links — lighting a static card would promise a click that isn't there. */
.card--link, .post-card { --mx: 50%; --my: 50%; isolation: isolate; }

.card--link::before,
.post-card::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; pointer-events: none; opacity: 0;
  background: radial-gradient(320px circle at var(--mx) var(--my),
              rgba(201,153,47,.16), rgba(201,153,47,.05) 44%, transparent 70%);
  transition: opacity var(--dur-3) var(--ease-out);
}
.card--link:hover::before, .card--link:focus-within::before,
.post-card:hover::before,  .post-card:focus-within::before { opacity: 1; }

/* Gold hairline that burns brightest nearest the cursor. The two-layer mask
   punches out the middle so only the 1px frame paints. */
@supports ((-webkit-mask-composite: xor) or (mask-composite: exclude)) {
  .card--link::after,
  .post-card::after {
    content: ""; position: absolute; inset: 0; z-index: 1;
    border-radius: inherit; pointer-events: none; opacity: 0;
    padding: 1px;
    background: radial-gradient(240px circle at var(--mx) var(--my),
                rgba(201,153,47,.85), rgba(201,153,47,.25) 40%, transparent 64%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
    transition: opacity var(--dur-3) var(--ease-out);
  }
  .card--link:hover::after, .card--link:focus-within::after,
  .post-card:hover::after,  .post-card:focus-within::after { opacity: 1; }
}

/* Touch devices have no real hover — don't leave a glow stuck on after a tap. */
@media (hover: none) {
  .card--link::before, .card--link::after,
  .post-card::before,  .post-card::after { display: none; }
}
.card-icon {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 52px; block-size: 52px; border-radius: 14px;
  background: var(--navy-50); color: var(--navy-700);
  margin-block-end: var(--sp-5);
  transition: background-color var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
}
.card--link:hover .card-icon { background: var(--navy-700); color: #fff; }
.card h3 {
  margin-block-end: var(--sp-3);
  font-size: clamp(1.2rem, 1.08rem + 0.42vw, 1.45rem);
  line-height: 1.22;
}
.card p { color: var(--ink-3); font-size: var(--fs-sm); }
.card-stretch::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }

.card-meta {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  margin-block-start: var(--sp-5); padding-block-start: var(--sp-4);
  border-block-start: 1px solid var(--line-2);
  font-size: var(--fs-xs); color: var(--ink-3);
}
.card-meta strong { color: var(--navy-700); font-weight: 600; }

.tag {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 4px var(--sp-3); border-radius: var(--r-pill);
  background: var(--navy-50); color: var(--navy-700);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .01em;
}
.tag--gold { background: var(--gold-soft); color: #6B4E12; }
.tag--neutral { background: var(--ivory-2); color: var(--ink-3); }

/* --------------------------------------------------------------------------
   10. Stats
   -------------------------------------------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-6); }
@media (max-width: 860px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-6) var(--sp-5); } }
.stat-num {
  font-family: var(--font-display); font-size: clamp(2.4rem, 1.7rem + 2.4vw, 3.6rem);
  line-height: 1; letter-spacing: -0.03em; color: #fff;
  font-variant-numeric: tabular-nums;
}
.stat-label { margin-block-start: var(--sp-3); font-size: var(--fs-sm); color: var(--on-dark-mute); }
.section--dark .stat-rule { inline-size: 32px; block-size: 2px; background: var(--gold-lite); margin-block-end: var(--sp-4); }

/* --------------------------------------------------------------------------
   11. Journey / steps
   -------------------------------------------------------------------------- */
.steps { position: relative; display: grid; gap: var(--sp-6); }
.steps::before {
  content: ""; position: absolute; inset-block: 28px 28px;
  inset-inline-start: 27px; inline-size: 2px;
  background: linear-gradient(var(--navy-200), var(--line));
}
@media (max-width: 640px) { .steps::before { inset-inline-start: 23px; } }

.step { position: relative; display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: var(--sp-5); align-items: start; }
@media (max-width: 640px) { .step { grid-template-columns: 48px minmax(0, 1fr); gap: var(--sp-4); } }
.step-num {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  inline-size: 56px; block-size: 56px; border-radius: 50%;
  background: var(--white); border: 2px solid var(--navy-200);
  font-family: var(--font-display); font-size: 1.2rem; color: var(--navy-700);
  transition: background-color var(--dur-3) var(--ease-out), border-color var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
}
@media (max-width: 640px) { .step-num { inline-size: 48px; block-size: 48px; font-size: 1.05rem; } }
.step.is-in .step-num { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.step-body { padding-block-start: var(--sp-2); }
.step-body h3 { font-size: var(--fs-h4); font-family: var(--font-display); font-weight: 400; letter-spacing: -0.01em; }
.step-body p { color: var(--ink-3); margin-block-start: var(--sp-2); max-width: 52ch; font-size: var(--fs-sm); }

/* -----------------------------------------------------------------------
   11b. Journey thread — homepage "how it works" only.
   Scoped to .steps--thread specifically (not the bare .steps this shares
   its markup with) because journey.html's own timelines reuse .steps/.step
   for entirely different content. Everything below must stay inert there,
   so nothing in this block ever targets bare .steps or bare .step-num.

   Two layers sharing one geometry: a muted track (::before, the full path
   ahead) and a gold fill (::after, ground already covered). The fill's
   height is a pure CSS scaleY driven by --journey-progress — a custom
   property JS sets once per scroll tick in initJourneyThread() — so
   growing the thread costs a transform, never a layout reread. Both fade
   out over their last stretch via mask-image rather than stopping dead at
   step 07's circle: the 90 days of follow-up is open-ended, not a hard
   finish line, and the thread says so before you've read a word of it.
   ----------------------------------------------------------------------- */
.steps--thread::before, .steps--thread::after {
  content: ""; position: absolute; inset-block: 28px 28px;
  inset-inline-start: 27px; inline-size: 2px; border-radius: 2px;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 85%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 85%, transparent 100%);
}
.steps--thread::before { background: var(--line); }
.steps--thread::after {
  background: linear-gradient(to bottom, #E3C673 0%, #C9A227 55%, #A67C1B 100%);
  transform-origin: top; transform: scaleY(var(--journey-progress, 0));
}
@media (max-width: 640px) { .steps--thread::before, .steps--thread::after { inset-inline-start: 23px; } }

.steps--thread .step-num {
  box-shadow: 0 0 0 0 rgba(201,153,47,0);
  transition: background-color var(--dur-3) var(--ease-out), border-color var(--dur-3) var(--ease-out),
              color var(--dur-3) var(--ease-out), box-shadow var(--dur-4) var(--ease-out);
}
/* .is-reached tracks the live thread position (bidirectional — it lets go
   again if you scroll back up), layered on top of .is-in's one-way entrance
   fill: a soft gold halo marking "the thread has reached this checkpoint,"
   distinct from "this checkpoint has been seen once." */
.steps--thread .step.is-reached .step-num { border-color: var(--gold-lite); box-shadow: 0 0 0 4px rgba(201,153,47,.16), 0 0 16px -3px rgba(201,153,47,.6); }

/* --------------------------------------------------------------------------
   12. Cost comparison bars + estimator
   -------------------------------------------------------------------------- */
.compare-row {
  display: grid; grid-template-columns: 8.5rem minmax(0, 1fr) 7rem;
  gap: var(--sp-4); align-items: center;
  padding-block: var(--sp-3);
}
@media (max-width: 700px) {
  .compare-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "label price" "bar bar"; gap: var(--sp-2) var(--sp-3); }
  .compare-label { grid-area: label; } .compare-track { grid-area: bar; } .compare-price { grid-area: price; text-align: end; }
}
.compare-label { font-size: var(--fs-sm); font-weight: 600; display: flex; align-items: center; gap: var(--sp-3); }
.compare-track { block-size: 30px; border-radius: var(--r-sm); background: var(--ivory-2); overflow: hidden; }
.compare-fill {
  block-size: 100%; border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--navy-600), var(--navy-500));
  transform: scaleX(0); transform-origin: left center;
  transition: transform 900ms var(--ease-soft);
}
[dir="rtl"] .compare-fill { transform-origin: right center; }
.compare-fill--muted { background: linear-gradient(90deg, #A7B0C2, #C4CBD8); }
.compare-price { font-weight: 700; font-variant-numeric: tabular-nums; font-size: var(--fs-sm); }

.estimator {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-xl); box-shadow: var(--e-3);
  overflow: hidden;
}
.estimator-head { padding: var(--sp-6); border-block-end: 1px solid var(--line-2); background: var(--ivory); }
.estimator-body { padding: var(--sp-6); display: grid; gap: var(--sp-6); }
.estimator-controls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
@media (max-width: 620px) { .estimator-controls { grid-template-columns: minmax(0, 1fr); } }
.estimator-result {
  background: var(--navy-900); color: var(--on-dark);
  border-radius: var(--r-lg); padding: var(--sp-6);
}
.estimator-saving {
  font-family: var(--font-display); font-size: clamp(2.2rem, 1.6rem + 2.4vw, 3.4rem);
  line-height: 1; color: #fff; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   13. Forms
   -------------------------------------------------------------------------- */
.field { display: block; }
.field + .field { margin-block-start: var(--sp-5); }
.field-label {
  display: flex; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 600; margin-block-end: var(--sp-2);
}
.field-req { color: var(--danger); font-weight: 700; }
.field-opt { color: var(--ink-3); font-weight: 400; font-size: var(--fs-xs); }

.input, .select, .textarea {
  inline-size: 100%; min-block-size: 50px;          /* ≥44px touch */
  padding: var(--sp-3) var(--sp-4);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: 1rem;                                   /* ≥16px: no iOS auto-zoom */
  color: var(--ink);
  transition: border-color var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
.textarea { min-block-size: 8rem; resize: vertical; line-height: 1.6; }
.input::placeholder, .textarea::placeholder { color: #8A97AC; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--navy-200); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--navy-600);
  box-shadow: 0 0 0 3px rgba(58,93,160,.18);
}
.select {
  appearance: none; cursor: pointer;
  padding-inline-end: var(--sp-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%235C6E68' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-4) center;
}
[dir="rtl"] .select { background-position: left var(--sp-4) center; }

.field-help { margin-block-start: var(--sp-2); font-size: var(--fs-xs); color: var(--ink-3); }
.field-error {
  display: none; align-items: center; gap: var(--sp-2);
  margin-block-start: var(--sp-2); font-size: var(--fs-xs);
  color: var(--danger); font-weight: 500;
}
.field.has-error .field-error { display: flex; }
.field.has-error .input, .field.has-error .select, .field.has-error .textarea {
  border-color: var(--danger); background: var(--danger-bg);
}

.check {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  min-block-size: 44px; padding-block: var(--sp-2);
  cursor: pointer; font-size: var(--fs-sm); color: var(--ink-2);
}
.check input { inline-size: 20px; block-size: 20px; margin-block-start: 2px; flex: none; accent-color: var(--navy-700); cursor: pointer; }

.chip-set { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip { position: relative; }
.chip input { position: absolute; opacity: 0; inline-size: 100%; block-size: 100%; cursor: pointer; }
.chip span {
  display: inline-flex; align-items: center; min-block-size: 44px;
  padding-inline: var(--sp-4); border-radius: var(--r-pill);
  border: 1px solid var(--line); background: var(--white);
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2);
  transition: all var(--dur-2) var(--ease-out);
}
.chip input:hover + span { border-color: var(--navy-200); background: var(--navy-50); }
.chip input:checked + span { background: var(--navy-700); border-color: var(--navy-700); color: #fff; }
.chip input:focus-visible + span { outline: 3px solid var(--navy-500); outline-offset: 3px; }

.form-status {
  display: none; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-4); border-radius: var(--r-md);
  font-size: var(--fs-sm); margin-block-end: var(--sp-5);
}
.form-status.is-visible { display: flex; }
.form-status--error { background: var(--danger-bg); color: #7A1C16; border: 1px solid #F2C4BF; }
.form-status--ok { background: #E7F4F0; color: #0B4438; border: 1px solid #B9DED2; }
.form-status a { color: inherit; }

/* --------------------------------------------------------------------------
   14. Accordion (FAQ)
   -------------------------------------------------------------------------- */
.acc-item { border-block-end: 1px solid var(--line); }
.acc-btn {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  inline-size: 100%; min-block-size: 64px; padding-block: var(--sp-4);
  text-align: start; font-size: var(--fs-h4); font-weight: 600; color: var(--ink);
  transition: color var(--dur-2) var(--ease-out);
}
.acc-btn:hover { color: var(--navy-700); }
.acc-sign { flex: none; inline-size: 32px; block-size: 32px; display: grid; place-items: center; color: var(--navy-600); }
.acc-sign svg { transition: transform var(--dur-3) var(--ease-out); }
.acc-btn[aria-expanded="true"] .acc-sign svg { transform: rotate(45deg); }

/* Panels are open by default so the FAQ content is present and readable
   with JavaScript disabled; site.js adds .is-enhanced and drives block-size
   inline from there. This is why we don't use the `grid-template-rows:
   0fr -> 1fr` trick: that one collapses every panel in CSS, so with
   scripting off the answers are invisible to readers and to crawlers. */
.acc-panel { overflow: hidden; }
[data-accordion].is-enhanced .acc-panel {
  transition: block-size var(--dur-4) var(--ease-soft);
}
.acc-panel p { color: var(--ink-3); font-size: var(--fs-sm); padding-block-end: var(--sp-5); max-width: var(--measure); }

/* --------------------------------------------------------------------------
   15. Testimonials
   -------------------------------------------------------------------------- */
.quote-card {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--sp-6);
  display: flex; flex-direction: column; gap: var(--sp-5);
  block-size: 100%;
}
.quote-mark { color: var(--gold-lite); flex: none; }
.quote-text { font-family: var(--font-display); font-size: 1.2rem; line-height: 1.45; color: var(--ink); letter-spacing: -0.012em; }
.quote-foot { margin-block-start: auto; display: flex; align-items: center; gap: var(--sp-3); }
.avatar {
  inline-size: 48px; block-size: 48px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: 1.05rem; color: #fff;
  background: linear-gradient(140deg, var(--navy-600), var(--navy-800));
}
.avatar--b { background: linear-gradient(140deg, #C9992F, #6B4E12); }
.avatar--c { background: linear-gradient(140deg, #3A5DA0, #14294E); }
.avatar--d { background: linear-gradient(140deg, #3F7A63, #1D4835); }
.avatar--lg { inline-size: 68px; block-size: 68px; font-size: 1.35rem; }

/* Doctor / consultant card */
.doc-head { display: flex; align-items: center; gap: var(--sp-4); margin-block-end: var(--sp-5); }
.doc-name { font-family: var(--font-display); font-size: 1.25rem; line-height: 1.2; letter-spacing: -0.015em; }
.doc-role { font-size: var(--fs-xs); color: var(--navy-700); font-weight: 600; letter-spacing: .04em; text-transform: uppercase; margin-block-start: 4px; }
.doc-stats { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--sp-4); margin-block-start: var(--sp-5); padding-block-start: var(--sp-5); border-block-start: 1px solid var(--line-2); }
.doc-stat-num { font-family: var(--font-display); font-size: 1.5rem; color: var(--navy-700); line-height: 1; font-variant-numeric: tabular-nums; }
.doc-stat-lbl { font-size: var(--fs-xs); color: var(--ink-3); margin-block-start: 6px; }

/* Hospital feature row */
.hosp { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(1.5rem, 1rem + 3vw, 3.5rem); align-items: center; }
.hosp:nth-child(even) .hosp-media { order: 2; }
@media (max-width: 860px) { .hosp, .hosp:nth-child(even) .hosp-media { grid-template-columns: minmax(0,1fr); order: 0; } }
.hosp + .hosp { margin-block-start: var(--sp-8); padding-block-start: var(--sp-8); border-block-start: 1px solid var(--line); }
.badge-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-block-start: var(--sp-4); }
.quote-name { font-weight: 600; font-size: var(--fs-sm); }
.quote-where { font-size: var(--fs-xs); color: var(--ink-3); display: flex; align-items: center; gap: var(--sp-2); }
.flag {
  inline-size: 20px; block-size: 14px; border-radius: 2px; flex: none;
  border: 1px solid rgba(0,0,0,.08);
}

/* --------------------------------------------------------------------------
   16. Media / article
   -------------------------------------------------------------------------- */
.figure {
  border-radius: var(--r-lg); overflow: hidden;
  background: var(--ivory-2); box-shadow: var(--e-2);
  aspect-ratio: 4 / 3;
}
.figure svg, .figure img { inline-size: 100%; block-size: 100%; object-fit: cover; }
.figure--tall { aspect-ratio: 3 / 4; }
.figure--wide { aspect-ratio: 16 / 9; }

.post-card {
  display: flex; flex-direction: column; block-size: 100%;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-lg); overflow: hidden;
  transition: transform var(--dur-3) var(--ease-out), box-shadow var(--dur-3) var(--ease-out);
}
.post-card:hover, .post-card:focus-within { transform: translateY(-4px); box-shadow: var(--e-3); }
.post-thumb { aspect-ratio: 16 / 10; background: var(--ivory-2); overflow: hidden; }
.post-thumb svg, .post-thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; transition: transform var(--dur-4) var(--ease-out); }
.post-card:hover .post-thumb svg, .post-card:hover .post-thumb img { transform: scale(1.04); }
.post-body { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-3); flex: 1; }
.post-body h3 { font-size: 1.25rem; }
.post-body a { text-decoration: none; }
.post-foot { margin-block-start: auto; padding-block-start: var(--sp-4); border-block-start: 1px solid var(--line-2); }

/* --------------------------------------------------------------------------
   17. Tables
   -------------------------------------------------------------------------- */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--white); }
table.data { inline-size: 100%; border-collapse: collapse; min-inline-size: 40rem; font-size: var(--fs-sm); }
table.data th, table.data td { padding: var(--sp-4) var(--sp-5); text-align: start; border-block-end: 1px solid var(--line-2); }
table.data thead th { background: var(--ivory); font-weight: 600; font-size: var(--fs-xs); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
table.data tbody tr:last-child td { border-block-end: 0; }
table.data tbody tr { transition: background-color var(--dur-1) var(--ease-out); }
table.data tbody tr:hover { background: var(--navy-50); }
table.data td.num { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
table.data .save { color: var(--success); font-weight: 700; }

/* --------------------------------------------------------------------------
   18. CTA band + footer
   -------------------------------------------------------------------------- */
.cta-band { position: relative; overflow: hidden; background: var(--navy-800); color: var(--on-dark); }
.cta-band::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(70% 120% at 82% 0%, rgba(58,93,160,.45), transparent 62%);
}
.cta-band > * { position: relative; }

.footer { background: var(--navy-950); color: var(--on-dark-mute); padding-block: var(--sp-9) var(--sp-6); font-size: var(--fs-sm); }
.footer-grid { display: grid; grid-template-columns: 1.3fr repeat(4, 1fr); gap: var(--sp-7) var(--sp-6); }
@media (max-width: 900px) { .footer-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: minmax(0,1fr); } }
.footer h4 { color: #fff; font-size: var(--fs-xs); letter-spacing: .16em; text-transform: uppercase; margin-block-end: var(--sp-4); }
.footer ul { list-style: none; padding: 0; display: grid; gap: var(--sp-1); }
.footer a { color: var(--on-dark-mute); text-decoration: none; display: inline-flex; align-items: center; min-block-size: 36px; transition: color var(--dur-2) var(--ease-out); }
.footer a:hover { color: #fff; }
.footer .brand-name { color: #fff; }
.footer .brand-sub { color: var(--on-dark-mute); }

/* Language + currency, relocated here from the header. Same .switch
   component, same JS, same IDs — only the surrounding context changed, so
   it needs its own light-on-dark colouring (the default .switch-btn assumes
   a light header background) and its menu opens upward instead of down,
   since down would run the dropdown off the bottom of the page. */
.footer .switch { display: block; margin-block-end: var(--sp-2); }
.footer .switch-btn {
  color: var(--on-dark-mute); padding-inline: 0; min-block-size: 36px;
}
.footer .switch-btn:hover { color: #fff; background: none; }
.footer .switch-menu {
  inset-block-start: auto; inset-block-end: calc(100% + 8px); inset-inline-start: 0; inset-inline-end: auto;
  transform-origin: bottom; transform: translateY(6px) scale(.98);
}
.footer .switch.is-open .switch-menu { transform: none; }
.footer-bottom {
  margin-block-start: var(--sp-8); padding-block-start: var(--sp-5);
  border-block-start: 1px solid rgba(255,255,255,.10);
  display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: space-between;
  font-size: var(--fs-xs);
}
.footer-legal { max-width: 60ch; color: #8FA0BE; line-height: 1.6; }

/* --------------------------------------------------------------------------
   19. Page header (interior pages)
   -------------------------------------------------------------------------- */
.pagehead { position: relative; overflow: hidden; background: var(--navy-900); color: var(--on-dark); padding-block: clamp(3.5rem, 2.5rem + 4vw, 6rem) clamp(3rem, 2.5rem + 3.5vw, 5rem); }
.pagehead::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(60% 110% at 88% 6%, rgba(58,93,160,.42), transparent 60%);
}
.pagehead > * { position: relative; }
.pagehead h1 { color: #fff; }
.pagehead .lead { color: var(--on-dark-mute); }
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); list-style: none; padding: 0; margin-block-end: var(--sp-5); font-size: var(--fs-xs); }
.crumbs a { color: var(--on-dark-mute); text-decoration: none; }
.crumbs a:hover { color: #fff; text-decoration: underline; }
.crumbs li[aria-current] { color: #fff; }
.crumbs .sep { color: rgba(255,255,255,.35); }

/* --------------------------------------------------------------------------
   20. Motion engine
   -------------------------------------------------------------------------- */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  /* Deliberately no will-change. There are ~60 of these on the homepage, and
     hinting them all promotes ~60 compositor layers before a single one has
     entered the viewport — enough to lock up a mid-range machine. A one-shot
     opacity/transform transition composites fine without the hint. */
}
[data-reveal="fade"]  { transform: none; }
[data-reveal="left"]  { transform: translate3d(-28px, 0, 0); }
[data-reveal="right"] { transform: translate3d(28px, 0, 0); }
[data-reveal="scale"] { transform: scale(.96); }

/* Every [data-reveal] / [data-clip] element on the site depends on
   IntersectionObserver + site.js finishing execution to ever reach
   opacity:1 / an unclipped state — that's ~60 elements per page, hidden by
   default. A slow device, a slow/blocked site.js fetch, or a stale cached
   copy left content permanently invisible on a real visitor's browser: the
   hero rendered (see below), then the very next section was a blank white
   gap, because everything in it was still sitting at opacity:0 waiting for
   JS that had already run (or errored) before the page was even visible.
   These animations replay the identical motion in pure CSS, so every
   reveal fires on its own regardless of JS timing; the JS-driven .is-in
   class (and its stagger delays, still assigned via the same --reveal-delay
   / --line-delay custom properties) layers on top as a no-op once these
   have already finished, or provides the delay value these read if JS does
   run in time. Below-the-fold content no longer waits for scroll to
   reveal itself — reliability wins over the scroll-triggered stagger. */
@media (prefers-reduced-motion: no-preference) {
  [data-reveal] {
    animation: heroRevealFade var(--dur-4) var(--ease-out) both;
    animation-delay: var(--reveal-delay, 0ms);
  }
  [data-reveal]:not([data-reveal="fade"]) {
    animation-name: heroRevealRise;
  }
  .hero-title .line > span {
    animation: heroLineRise 1150ms var(--ease-soft) both;
    animation-delay: var(--line-delay, 0ms);
  }
  [data-clip] > img, [data-clip] > svg {
    animation: clipReveal 1000ms var(--ease-soft) both;
    animation-delay: var(--reveal-delay, 0ms);
  }
}
@keyframes heroRevealFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes heroRevealRise {
  from { opacity: 0; transform: translate3d(0, 22px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes heroLineRise {
  from { transform: translate3d(0, 108%, 0); }
  to   { transform: none; }
}
@keyframes clipReveal {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* Below the tablet breakpoint a horizontal slide both reads poorly and
   pushes the pre-reveal element past the viewport edge, widening the
   document. Degrade to the vertical reveal on narrow screens. */
@media (max-width: 860px) {
  [data-reveal="left"], [data-reveal="right"] { transform: translate3d(0, 22px, 0); }
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* Clip reveal for hero/feature imagery.
   The clip lives on the child, never on the observed element itself:
   Chrome factors clip-path into IntersectionObserver, so a fully clipped
   target reports zero intersection and would never fire its own reveal. */
[data-clip] > img,
[data-clip] > svg {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1000ms var(--ease-soft);
}
[data-clip].is-in > img,
[data-clip].is-in > svg { clip-path: inset(0 0 0 0); }

.parallax { will-change: transform; }

/* Global honour of reduced-motion — everything above degrades to instant. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .hero-title .line > span { transform: none !important; }
  [data-clip] > img, [data-clip] > svg { clip-path: none !important; }
  .marquee-track { animation: none; transform: none; }
  .compare-fill { transition: none; }
}

/* --------------------------------------------------------------------------
   21. Utilities
   -------------------------------------------------------------------------- */
.flow-sm > * + * { margin-block-start: var(--sp-3); }
.mt-4 { margin-block-start: var(--sp-4); }
.mt-5 { margin-block-start: var(--sp-5); }
.mt-6 { margin-block-start: var(--sp-6); }
.mt-7 { margin-block-start: var(--sp-7); }
.mb-6 { margin-block-end: var(--sp-6); }
.mb-7 { margin-block-end: var(--sp-7); }
.flex { display: flex; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.wrap-flex { flex-wrap: wrap; }
.gap-3 { gap: var(--sp-3); }
.gap-4 { gap: var(--sp-4); }
.gap-5 { gap: var(--sp-5); }
.full { inline-size: 100%; }
.rel { position: relative; }
.hide-sm { display: initial; }
@media (max-width: 640px) { .hide-sm { display: none; } }

.section-head { max-width: 44rem; margin-block-end: clamp(2.5rem, 1.5rem + 3vw, 4rem); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head--center .eyebrow { justify-content: center; }
.section-head p { margin-block-start: var(--sp-4); }

.divider { block-size: 1px; background: var(--line); border: 0; }

/* --------------------------------------------------------------------------
   22. RTL / Arabic typography
   Lives last on purpose: these are directional overrides and must outrank the
   component rules above them at equal specificity.
   -------------------------------------------------------------------------- */

/* Fraunces carries no Arabic glyphs, so display type in RTL would otherwise
   drop to whatever system serif the OS happens to pick. Arabic has no
   serif/sans distinction to trade on anyway — hierarchy comes from size and
   weight instead. Tight tracking and italics are both reset: they damage a
   connected script. */
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3, [dir="rtl"] h4,
[dir="rtl"] .hero h1, [dir="rtl"] .display,
[dir="rtl"] .brand-name, [dir="rtl"] .quote-text, [dir="rtl"] .stat-num,
[dir="rtl"] .doc-name, [dir="rtl"] .estimator-saving, [dir="rtl"] .hero-badge-num,
[dir="rtl"] .step-num, [dir="rtl"] .drawer-links a, [dir="rtl"] .serif-accent,
[dir="rtl"] .acc-btn, [dir="rtl"] .step-body h3, [dir="rtl"] .post-body h3 {
  font-family: var(--font-arabic);
  letter-spacing: 0;
  font-style: normal;
}
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3,
[dir="rtl"] .hero h1, [dir="rtl"] .display,
[dir="rtl"] .quote-text, [dir="rtl"] .doc-name {
  font-weight: 600;
  line-height: 1.35;   /* Arabic ascenders and marks need more leading */
}
[dir="rtl"] .hero h1 em, [dir="rtl"] .serif-accent {
  font-style: normal; font-weight: 400; color: var(--navy-700);
}
/* The eyebrow rule is decorative and reads as a stray dash before RTL text. */
[dir="rtl"] .eyebrow { letter-spacing: 0.06em; }

/* Print: strip chrome, keep content legible */
@media print {
  .header, .topbar, .drawer, .drawer-scrim, .marquee, .cta-band { display: none !important; }
  body { background: #fff; color: #000; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
}


/* ==========================================================================
   12. Homepage 2026 refresh
   Added in the 2026-08 homepage revision. Ordered last on purpose: several
   rules here refine earlier ones in this sheet (.hero-credential,
   .hero-assure, .nav-drop-menu) and rely on source order rather than on
   specificity escalation, so nothing above needed editing to accommodate
   them. Everything is additive.

   Covers: the top-bar call glyph, the hover-safe Patients dropdown, the
   hero credential panel and assure band, the Why MEDYRA "Switchboard", and
   the MEDYRA Global Care Network globe.
   ========================================================================== */
/* ---------------------------------------------------------------------------
   1 — TOP BAR
   The number and its glyph become one link, so the icon is part of the tap
   target rather than a decoration sitting next to it. The glyph is held at
   62% of the inherited colour: present enough to read as "call", quiet enough
   that the 13px number stays the loudest thing in a 34px bar.
   --------------------------------------------------------------------------- */
.topbar-call {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  white-space: nowrap;
}
.topbar-call-icon {
  flex: none; opacity: .62;
  transform: translateY(-.5px);   /* optical centring against the lining figures */
  transition: opacity var(--dur-2) var(--ease-out);
}
.topbar-call:hover .topbar-call-icon,
.topbar-call:focus-visible .topbar-call-icon { opacity: 1; }
/* The underline belongs to the number, not to the glyph. */
.topbar-call:hover { text-decoration: none; }
.topbar-call:hover span { text-decoration: underline; }

/* ---------------------------------------------------------------------------
   2 — PATIENTS DROPDOWN, HOVER-SAFE
   The production menu opens on :hover and is offset 8px below the button.
   That 8px is real dead space: the pointer leaves .nav-drop on its way to the
   first item, :hover drops, and the menu closes under the cursor.

   Two fixes, both needed:
   a) A bridge — a transparent ::before spanning the gap, part of the menu's
      own box, so the pointer never leaves the hover region. Bridging with
      padding instead would move the menu; bridging with margin would not
      capture the pointer at all.
   b) A close delay in home.js for the diagonal case — travelling to the
      SECOND item takes the pointer briefly outside both boxes. CSS alone
      cannot express "wait 220ms before believing this exit".
   The panel's own look is untouched.
   --------------------------------------------------------------------------- */
.nav-drop-menu::before {
  content: "";
  position: absolute;
  inset-inline: -8px;              /* a little wider than the panel, for diagonals */
  inset-block-start: -14px;        /* covers the 8px offset and then some */
  block-size: 16px;
  /* Deliberately transparent, never a visible element. */
}
/* Bridge and panel are only live while the menu is actually open — otherwise
   an invisible 16px strip would sit under the navigation swallowing pointer
   events for every other link. */
.nav-drop-menu { pointer-events: none; }
.nav-drop:hover > .nav-drop-menu,
.nav-drop:focus-within > .nav-drop-menu,
.nav-drop.is-open > .nav-drop-menu,
.nav-drop.is-hover-safe > .nav-drop-menu { pointer-events: auto; }

/* The JS-held open state. Matches the production open rule exactly so the
   panel cannot look different depending on which mechanism opened it. */
.nav-drop.is-hover-safe > .nav-drop-menu {
  opacity: 1; transform: none; visibility: visible;
}
/* Keep the chevron in step with the JS-held state. */
.nav-drop.is-hover-safe > .nav-drop-btn .chev { transform: rotate(180deg); }

/* ---------------------------------------------------------------------------
   3 — HERO CREDENTIAL (4,200+)
   Was a left-aligned inline-flex row: big number, then text beside it. Centred
   here as a stacked block so the figure sits over its own caption and the
   panel reads as one deliberate object under the buttons.

   inline-size: fit-content keeps the panel hugging its content — a full-width
   box with centred text inside would look like a mistake at desktop width.
   The panel itself is then centred against the CTA row above it rather than
   against the whole hero column, which is what makes it read as belonging to
   the buttons.
   --------------------------------------------------------------------------- */
.hero-credential {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-2);
  text-align: center;
  /* One committed width rather than a floor and a ceiling around content that
     then sized itself independently. Everything inside now measures against
     this, so the container and its contents are the same design decision.

     Taken down by a quarter from 26rem. Both dimensions are stated because
     the production rule caps this at max-inline-size: min(26rem, 100%), which
     was the value actually in force — setting inline-size alone would have
     left that cap deciding the width. Everything inside is scaled on the same
     factor below, so the panel reduces as one object rather than becoming a
     smaller box around the same contents.

     margin-inline: auto is untouched, so the centre line does not move. */
  inline-size: min(19.5rem, 100%);
  max-inline-size: min(19.5rem, 100%);
  margin-inline: auto;
  padding: 1.125rem 1.5rem;      /* was 24px 32px — 0.75× */
  gap: 0;
  /* Owns the stacking context for the shimmer ring below. */
  position: relative;
}
.hero-credential-num {
  line-height: 1;
  /* 0.76× the previous clamp, tracking the box rather than staying put and
     crowding it. */
  font-size: clamp(1.5rem, 1.15rem + 1.2vw, 2.1rem);
}
/* The rule is what actually makes the panel read as designed to its width: it
   spans the full inner measure, with the figure's own gold picked up at both
   ends and falling away toward the centre. */
.hero-credential-rule {
  display: flex; inline-size: 100%; align-items: center;
  margin-block: 0.5rem;          /* was 12px — 0.67×, keeping the stack tight */
}
.hero-credential-rule i {
  flex: 1; block-size: 1px; display: block;
  background: linear-gradient(90deg, rgba(201,153,47,.55), rgba(201,153,47,0));
}
.hero-credential-rule i:last-child { transform: scaleX(-1); }

/* --- the travelling highlight ---------------------------------------------
   One point of light moving round the perimeter, not a border that glows.

   The ring is a conic gradient that is almost entirely transparent: a single
   bright arc of about 30 degrees with a long, soft tail behind it, and
   nothing at all around the rest of the sweep. Rotating the gradient's own
   angle carries that arc round the box. Because it is a *gradient* rather
   than a shape, the highlight has no ends — it fades in and out of existence,
   which is what keeps it from reading as a dash chasing itself.

   Confined to a hairline by the standard two-layer mask: the element is
   painted, then everything except its 1px padding band is masked away. That
   leaves the box's real background and its existing gold border completely
   untouched underneath — this only adds light on top.

   The angle is a registered custom property because plain custom properties
   are not interpolable and would step, not sweep. Where @property is
   unsupported the var() falls back to 0deg: the ring renders as one static,
   very faint glint at the top edge and simply does not travel. Nothing
   breaks, and nothing looks half-finished.

   Speed is deliberately slow — a full circuit takes eight seconds. Fast
   enough to notice on a second look, slow enough that it never competes with
   the CTA directly above it. */
@property --cred-ang {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.hero-credential::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;                    /* the ring's thickness, and nothing more */
  background: conic-gradient(from var(--cred-ang, 0deg),
    rgba(244,227,168,0)    0deg,
    rgba(244,227,168,0)    232deg,
    rgba(244,227,168,.10) 286deg,
    rgba(233,206,131,.42) 322deg,
    rgba(255,246,214,.92) 342deg,
    rgba(244,227,168,.18) 352deg,
    rgba(244,227,168,0)   360deg);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
  animation: credShimmer 8s linear infinite;
}
@keyframes credShimmer { to { --cred-ang: 360deg; } }
/* Full measure, not a 26ch column centred inside a 30rem box.
   Stepped up from --fs-xs (13px) to 15px: the caption was sized for the narrow
   panel it used to live in and looked undernourished at this width. Held at
   15px rather than pushed further because the line count is what governs the
   panel's height — the box itself must not change, and 15px is the largest
   size that still sets this sentence in two lines across the 350px measure. */
.hero-credential-txt {
  max-inline-size: none; inline-size: 100%;
  /* Down with the box, but on a shallower factor than the rest: 0.8× rather
     than 0.75×, which lands at 12px. A straight quarter would have put this
     at 11.25px, below anything else on the site and below the point where a
     caption over a photographic hero stays comfortable. It still reads as
     smaller relative to a smaller panel. */
  font-size: 0.75rem; line-height: 1.4;
  text-wrap: pretty;
}

/* The CTA row is centred with it, otherwise a centred panel under a
   left-aligned pair of buttons looks accidental rather than composed. */
.hero-cta { justify-content: center; }
.hero-scroll { justify-content: center; }

/* The headline and lead stay left-aligned on desktop — centring a 3-line
   display headline and a 4-line paragraph would cost real readability. The
   centred block starts at the CTA and runs down, which reads as a deliberate
   change of register rather than an inconsistency. */
.hero-copy .hero-cta,
.hero-copy .hero-credential { align-self: center; }
.hero-copy { display: flex; flex-direction: column; }
.hero-copy > .eyebrow,
.hero-copy > .hero-title,
.hero-copy > .hero-lead { align-self: flex-start; }

@media (max-width: 860px) {
  /* On a phone everything in the hero column is already centre-weighted, so
     the whole block is centred and the composition resolves. */
  .hero-copy > .eyebrow,
  .hero-copy > .hero-title,
  .hero-copy > .hero-lead { align-self: stretch; text-align: center; }
  .hero-lead { margin-inline: auto; }
  .hero-credential { inline-size: 100%; }
}

/* ---------------------------------------------------------------------------
   4 — THE FOUR ASSURE ITEMS
   Centred as a composition rather than by dropping text-align on each cell:
   - the label, the value and the divider all share one axis per cell;
   - the dividers become fixed-height hairlines centred vertically, so four
     unequal blocks of text still sit on one visual line;
   - cells get symmetric inline padding, otherwise centred text inside a cell
     with padding on one side only drifts off the true centre.
   --------------------------------------------------------------------------- */
.hero-assure { align-items: stretch; }
.hero-assure li {
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  padding-inline: var(--sp-4);
  border-inline-end: 0;            /* replaced by the centred hairline below */
  position: relative;
}
/* A hairline that is centred on the cell's own height instead of running the
   full height of the tallest cell — the difference is what stops the row
   looking like a table. */
.hero-assure li:not(:last-child)::after {
  content: "";
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: 50%;
  transform: translateY(-50%);
  block-size: 2.25rem;
  inline-size: 1px;
  background: rgba(255,255,255,.14);
}
.hero-assure-k { margin-block-end: var(--sp-2); }
/* Capped so the four values wrap into similar shapes rather than one cell
   running to a single long line while its neighbour runs to three. */
.hero-assure-v { max-inline-size: 22ch; text-wrap: balance; }

@media (max-width: 860px) {
  /* Two columns: only the odd cells carry a divider, and the row gap needs to
     grow now that the text is centred and the cells are no longer flush. */
  .hero-assure { gap: var(--sp-6) var(--sp-4); }
  .hero-assure li { padding-inline: var(--sp-2); }
  .hero-assure li:nth-child(2n)::after { content: none; }
}
@media (max-width: 360px) {
  .hero-assure li::after { content: none !important; }
  .hero-assure li { padding-inline: 0; }
}

/* ---------------------------------------------------------------------------
   6 — THE SWITCHBOARD
   --------------------------------------------------------------------------- */
.switchboard {
  /* --t is the single state scalar: 0 = uncoordinated, 1 = coordinated.
     Everything visual in this section is a function of it, set once per frame
     by home.js. */
  --t: 0;
  --sb-cold: #93A3BC;
  --sb-warm: var(--gold-lite);
  overflow: clip;   /* the scattered state reaches slightly past the grid */
}

.sb-grid {
  display: grid;
  /* The stage takes the larger share: the wire band needs real horizontal run
     or the fan collapses into ten near-vertical lines. */
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.14fr);
  gap: clamp(2rem, 1rem + 4vw, 5rem);
  /* REFINEMENT 3 — the stage stretches to the height the copy column sets, so
     row 10 lands level with the bottom of the "Show it uncoordinated" control
     instead of stopping two-thirds of the way up. The two halves of the
     section now close on the same line. */
  align-items: stretch;
}
.sb-copy { align-self: start; }
@media (max-width: 1000px) {
  .sb-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-7); }
}

/* --- left column ---------------------------------------------------------- */
.sb-copy { position: sticky; inset-block-start: 7rem; }
@media (max-width: 1000px) { .sb-copy { position: static; } }

.sb-copy .lead { margin-block-start: var(--sp-4); max-inline-size: 46ch; }

/* REFINEMENT 2 — editorial emphasis, built from the existing scale.
   The promise takes the display face at full h2 size; the qualifier drops to
   0.46em, loses the serif, and is preceded by a short gold rule. No colour
   fill, no underline, no highlight — the hierarchy does the work. */
.sb-h { display: flex; flex-direction: column; gap: var(--sp-3); }
.sb-h-lead {
  position: relative; display: inline-block;
  /* Shrink to the words. As a flex item this would otherwise stretch to the
     column, and the accent beneath it would run on past the last letter into
     empty space. */
  align-self: flex-start;
  font-size: 1.06em;          /* against the inherited h2 size, not a new one */
  letter-spacing: -.032em;
  line-height: 1.02;
  /* A warm bloom behind the words rather than a plate under them. It is barely
     there — enough that the phrase sits in its own light without anything
     reading as a shape. */
  isolation: isolate;
}
.sb-h-lead::before {
  content: "";
  position: absolute; z-index: -1;
  inset: -30% -24% -34%;
  /* Carried across the whole phrase rather than pooling under part of it. A
     single radial centred at 42% left the end of the words outside the light,
     which is what made the treatment read as partial. Two overlapping
     ellipses — one wide and flat across the full width, one softer above the
     x-height — hold an even wash from the first letter to the comma without
     ever resolving into a shape with an edge. */
  background:
    radial-gradient(66% 46% at 50% 58%,
      rgba(212,175,55,.17) 0%, rgba(212,175,55,.13) 34%,
      rgba(212,175,55,.07) 58%, rgba(212,175,55,.02) 78%, transparent 100%),
    radial-gradient(82% 66% at 50% 44%,
      rgba(233,201,105,.09) 0%, rgba(212,175,55,.045) 48%,
      rgba(212,175,55,.012) 74%, transparent 100%);
  opacity: 0; transform: scale(.96);
  transition: opacity 900ms var(--ease-out) 260ms, transform 900ms var(--ease-out) 260ms;
}
.sb-h.is-in .sb-h-lead::before,
[data-reveal].is-in .sb-h-lead::before { opacity: 1; transform: none; }

.sb-h-words { position: relative; z-index: 1; }
.sb-h-sub {
  display: flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-body);
  font-size: .46em; font-weight: 400; letter-spacing: -.005em;
  line-height: 1.35; color: var(--ink-3);
}
.sb-h-sub i {
  flex: none; inline-size: 2.25rem; block-size: 1px;
  background: var(--gold-lite);
}
@media (max-width: 560px) {
  .sb-h-sub { font-size: .52em; }
  .sb-h-sub i { inline-size: 1.5rem; }
}

/* The count. Tabular figures so 10 and 1 occupy the same box and the caption
   beside them never shifts as the number changes. */
.sb-tally {
  display: flex; align-items: baseline; gap: var(--sp-4);
  margin-block-start: clamp(1.75rem, 1rem + 2vw, 2.75rem);
  padding-block-start: var(--sp-5);
  border-block-start: 1px solid var(--line);
}
.sb-tally-num {
  font-family: var(--font-display);
  font-size: clamp(3rem, 2rem + 3.4vw, 4.75rem);
  font-weight: 300; line-height: .85; letter-spacing: -.045em;
  font-variant-numeric: tabular-nums;
  min-inline-size: 1.6ch; text-align: end;
  color: color-mix(in srgb, var(--ink) calc((1 - var(--t)) * 100%), var(--gold));
  transition: color var(--dur-3) linear;
}
.sb-tally-copy { display: flex; flex-direction: column; gap: 2px; }
.sb-tally-copy b {
  font-size: var(--fs-body); font-weight: 600; color: var(--ink);
  letter-spacing: -.01em;
}
.sb-tally-copy span { font-size: var(--fs-sm); color: var(--ink-3); }

/* The detail well. Fixed minimum height so hovering across the list never
   reflows the left column — the single most common way a panel like this
   ends up feeling cheap. */
.sb-detail {
  margin-block-start: var(--sp-5);
  padding: var(--sp-5);
  min-block-size: 9.5rem;
  background: var(--ivory);
  border: 1px solid var(--line-2);
  border-inline-start: 2px solid var(--gold-lite);
  border-radius: var(--r-md);
}
.sb-detail-eyebrow {
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--gold);
  margin-block-end: var(--sp-2);
}
.sb-detail-body { font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.6; }
.sb-detail.is-swapping .sb-detail-eyebrow,
.sb-detail.is-swapping .sb-detail-body { opacity: 0; }
.sb-detail-eyebrow, .sb-detail-body { transition: opacity 120ms linear; }
@media (max-width: 1000px) { .sb-detail { display: none; } }

/* A reader-facing control: replays the argument in either
   direction without needing to scroll away and back. */
.sb-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  margin-block-start: var(--sp-5);
  min-block-size: 44px; padding-inline: var(--sp-4);
  background: none; border: 1px solid var(--line); border-radius: var(--r-pill);
  font: inherit; font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2);
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease-out),
              background-color var(--dur-2) var(--ease-out),
              color var(--dur-2) var(--ease-out);
}
.sb-toggle:hover { border-color: var(--navy-200); background: var(--ivory); color: var(--ink); }
.sb-toggle-dot {
  inline-size: 7px; block-size: 7px; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--sb-cold) calc((1 - var(--t)) * 100%), var(--gold-lite));
}

/* --- right column: the stage --------------------------------------------- */
.sb-stage { position: relative; display: flex; flex-direction: column; }

.sb-wires {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%;
  z-index: 0; pointer-events: none;
  overflow: visible;
}

/* Threads. One path per touchpoint; geometry is rewritten per frame by JS,
   colour and weight are left to CSS so they can key off --t and off the
   hover state without JS touching style attributes. */
.sb-thread {
  fill: none;
  stroke: color-mix(in srgb, var(--sb-cold) calc((1 - var(--t)) * 100%), var(--sb-warm));
  stroke-width: calc(1px + var(--t) * .1px);
  stroke-linecap: round;
  opacity: calc(.34 + var(--t) * .34);
  transition: opacity var(--dur-2) var(--ease-out), stroke-width var(--dur-2) var(--ease-out);
}
.sb-stage.has-active .sb-thread { opacity: .12; }
.sb-stage.has-active .sb-thread.is-active {
  opacity: 1; stroke: var(--gold-lite); stroke-width: 2px;
}

/* The trunk — you to the coordinator. It does not exist in the uncoordinated
   state, so it is drawn as a dash that runs in as --t rises. */
.sb-trunk {
  fill: none; stroke: var(--gold-lite);
  stroke-width: 2.5px; stroke-linecap: round;
  opacity: var(--t);
}

/* Node discs */
.sb-node-dot {
  fill: color-mix(in srgb, var(--sb-cold) calc((1 - var(--t)) * 100%), var(--gold-lite));
  transition: fill var(--dur-2) linear;
}
.sb-node-ring { fill: none; stroke: var(--gold-lite); stroke-width: 1; opacity: 0; }
.sb-thread.is-active + .sb-node-ring { opacity: .55; }

/* "You" and the coordinator core */
.sb-anchor-label {
  font-family: var(--font-body); font-size: 10px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; fill: var(--ink-3);
}
.sb-core-label { fill: var(--gold); opacity: var(--t); }
.sb-you-dot { fill: var(--navy-700); }
.sb-core-disc {
  fill: var(--white); stroke: var(--gold-lite); stroke-width: 1.5;
  opacity: var(--t);
}
.sb-core-mark { fill: var(--gold-lite); opacity: var(--t); }
/* A single resting pulse on the core once it exists — a coordinator who is
   awake, not a decorative animation. Off under reduced motion. */
.sb-core-halo {
  fill: none; stroke: var(--gold-lite); stroke-width: 1;
  opacity: 0; transform-origin: center; transform-box: fill-box;
  animation: sbHalo 3.8s var(--ease-soft) infinite;
}
@keyframes sbHalo {
  0%   { opacity: 0; transform: scale(.9); }
  22%  { opacity: calc(.34 * var(--t)); }
  100% { opacity: 0; transform: scale(1.75); }
}

/* --- the list ------------------------------------------------------------- */
.sb-list {
  position: relative; z-index: 1;
  list-style: none; margin: 0; padding: 0;
  /* Cleared for the wire band on the left. The band is where the trunk, the
     core and the fan live; the list never overlaps it. */
  margin-inline-start: clamp(9rem, 5rem + 14vw, 19rem);
  /* The ten rows spread across whatever height the copy column sets, with the
     gap acting as a floor so they can never be pushed closer than this even
     if the left column is unusually short. */
  flex: 1;
  display: flex; flex-direction: column; justify-content: space-between;
  gap: var(--sp-2);
  min-block-size: 27rem;
}
@media (max-width: 1000px) { .sb-list { margin-inline-start: clamp(5rem, 3rem + 9vw, 9rem); } }
/* 5rem is the floor: below about 70px of band the fan has no horizontal run
   left and the ten threads collapse into a single vertical line. */
@media (max-width: 560px)  { .sb-list { margin-inline-start: 5rem; } }

.sb-item {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--sp-3);
  align-items: baseline;
  /* Roomier on both axes than the first pass: the rows were reading as a
     dense table rather than ten distinct touchpoints. */
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-md);
  /* The scatter. --sx/--sy are set per item by JS; they are scaled by (1 - t)
     so the rows literally travel into register as the section resolves. */
  transform: translate3d(calc(var(--sx, 0px) * (1 - var(--t))),
                         calc(var(--sy, 0px) * (1 - var(--t))), 0);
  transition: background-color var(--dur-2) var(--ease-out);
}
/* Spacing is the flex gap now, so the rows can distribute. */

.sb-item-i {
  font-family: var(--font-display);
  font-size: var(--fs-xs); font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--sb-cold) calc((1 - var(--t)) * 100%), var(--gold));
  opacity: calc(.35 + var(--t) * .65);
}
.sb-item-t {
  font-size: var(--fs-body); font-weight: 500; line-height: 1.35;
  letter-spacing: -.011em;
  color: color-mix(in srgb, var(--ink-3) calc((1 - var(--t)) * 100%), var(--ink));
  text-wrap: balance;
}
.sb-item-note { grid-column: 2; }

/* Desktop: the note lives in the left-hand well, not in the row. */
@media (min-width: 1001px) {
  .sb-item-note { display: none; }
  .sb-item:hover,
  .sb-item.is-active { background: var(--ivory); cursor: default; }
  .sb-item:hover .sb-item-t,
  .sb-item.is-active .sb-item-t { color: var(--navy-700); }
}

/* Phones and tablets: no hover to rely on, so the row opens in place. One at
   a time, so the section never becomes ten paragraphs stacked. */
@media (max-width: 1000px) {
  .sb-item { cursor: pointer; }
  .sb-item-note {
    font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.6;
    display: grid; grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows var(--dur-3) var(--ease-out),
                opacity var(--dur-2) linear,
                margin-block-start var(--dur-3) var(--ease-out);
  }
  /* A grid row set to 0fr still honours its item's automatic minimum size, so
     it will NOT collapse around a bare text node — the row just resolves to
     the text's height. The clip has to sit on a real child element, which is
     what home.js wraps each note's text in. */
  .sb-item-note > * { overflow: hidden; }
  .sb-item.is-active .sb-item-note { margin-block-start: var(--sp-2); }
  .sb-item.is-active { background: var(--ivory); }
  .sb-item.is-active .sb-item-note { grid-template-rows: 1fr; opacity: 1; }
}

/* Focus follows the production convention rather than inventing a new one. */
.sb-item:focus-visible {
  outline: 2px solid var(--navy-600); outline-offset: 2px;
}
/* ---------------------------------------------------------------------------
   3–13 — THE MEDYRA GLOBAL CARE NETWORK
   --------------------------------------------------------------------------- */

/* --- atmosphere -----------------------------------------------------------
   No section--dark and no rule. The navy is the middle of a gradient that
   begins at the white of the section above and returns to the ivory of the
   one below, so there is no row of pixels anywhere that reads as an edge.
   The bloom behind the globe is what sells it as air rather than paint. */
.meridian {
  position: relative;
  isolation: isolate;
  overflow: clip;
  color: var(--on-dark);
  padding-block: clamp(5rem, 3rem + 8vw, 10rem);
}
.mn-sky {
  position: absolute; inset: 0; z-index: -2;
  /* The transitions are CURVED, not stacked.

     A vertical linear ramp between two very different luminances always
     produces a horizontal band — every pixel on a given row is the same
     colour, so the eye finds the row where it changes fastest and reads that
     as a line. Lengthening the ramp softens it but never removes it; the
     previous version's pale blue-grey band near the foot of the section was
     exactly that, and it read as a white fade across the page.

     So the ends are radial instead. The white above settles in on a wide arc
     centred beyond the top edge, and the ivory below rises on an arc centred
     beyond the bottom — light arriving over a horizon rather than a rule drawn
     across one. No row of pixels shares a single value anywhere, so there is
     no line for the eye to find. The short linear caps only guarantee the
     first and last few pixels match the sections either side exactly, so the
     joins themselves are seamless. */
  background:
    /* exact colour match at the very top and bottom edges */
    linear-gradient(180deg, #FFFFFF 0%, rgba(255,255,255,.86) 3%, rgba(255,255,255,0) 11%),
    linear-gradient(0deg, var(--ivory) 0%, rgba(247,249,252,.86) 2.5%, rgba(247,249,252,0) 9%),
    /* the arcs */
    radial-gradient(150% 34% at 50% -4%,
      rgba(255,255,255,.97) 0%, rgba(226,233,245,.80) 24%,
      rgba(126,155,210,.42) 52%, rgba(24,48,95,.12) 74%, transparent 88%),
    radial-gradient(160% 30% at 50% 104%,
      rgba(247,249,252,.97) 0%, rgba(222,230,243,.78) 22%,
      rgba(118,148,205,.38) 50%, rgba(20,42,88,.12) 74%, transparent 88%),
    /* the body */
    linear-gradient(180deg, #0B1932 0%, #050B18 48%, #060E1F 100%);
}
/* Two blooms at different scales: a cool one for the volume of sky, a warm
   one seated where the globe sits, so the sphere appears to be lighting the
   space it is in rather than floating on top of it. */
.mn-bloom {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(46% 34% at 50% 54%, rgba(58,93,160,.30), transparent 72%),
    radial-gradient(24% 18% at 44% 46%, rgba(212,175,55,.10), transparent 76%);
}
.mn-wrap { position: relative; z-index: 1; }

.mn-eyebrow {
  font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase;
  color: rgba(214,226,244,.82);
  /* No mark of any kind before it — the production .eyebrow carries a ::before
     dot, which is explicitly not wanted here. */
}
.mn-eyebrow::before { content: none; }
.mn-title {
  font-family: var(--font-display);
  /* Size held; authority comes from weight. Fraunces is loaded at 300–600, so
     this is a real cut rather than a synthesised bold, and 500 against the
     300 it was is the step that reads as deliberate without turning the
     display face heavy. The tracking closes slightly to match. */
  font-size: clamp(2.2rem, 1.5rem + 3vw, 4rem);
  font-weight: 500; letter-spacing: -.038em; line-height: 1.02;
  color: #fff;
  margin-block-start: var(--sp-3);
  max-inline-size: 18ch;
}

/* --- stage ---------------------------------------------------------------- */
.mn-stage {
  position: relative;
  margin-block-start: clamp(1.5rem, 1rem + 3vw, 3.5rem);
  block-size: clamp(30rem, 22rem + 26vw, 44rem);
  touch-action: none;   /* the canvas owns the drag */
}
.mn-canvas {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%;
  display: block;
  cursor: grab;
}
.mn-canvas.is-dragging { cursor: grabbing; }

.mn-hint {
  position: absolute; inset-inline-start: 50%; inset-block-end: 0;
  transform: translateX(-50%);
  font-size: var(--fs-xs); letter-spacing: .2em; text-transform: uppercase;
  color: rgba(203,216,236,.42);
  pointer-events: none;
  transition: opacity var(--dur-4) var(--ease-out);
}
.mn-stage.is-engaged .mn-hint { opacity: 0; }

/* --- the readout ----------------------------------------------------------
   Positioned by JS at the country's own projected coordinates and carried
   along as the sphere turns, so it is attached to the place rather than
   floating near it. No box: a hairline, a name, a line of context. */
.mn-read {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  z-index: 3; pointer-events: none;
  padding-inline-start: var(--sp-4);
  border-inline-start: 1px solid rgba(212,175,55,.55);
  opacity: 0; transform: translate(-50%, 0) translateY(4px);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
  white-space: nowrap;
}
.mn-read.is-on { opacity: 1; transform: translate(-50%, 0); }
.mn-read-name {
  display: block;
  font-family: var(--font-display); font-size: 1.25rem; font-weight: 400;
  letter-spacing: -.02em; color: #fff;
}
.mn-read-meta {
  display: block; margin-block-start: 3px;
  font-size: var(--fs-xs); font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--gold-lite);
}

/* --- the four figures -----------------------------------------------------
   Absolutely placed around the sphere on desktop and moved by JS on their own
   parallax depths; the canvas draws a hairline from each to the rim, so they
   are anchored to the globe rather than arranged near it. */
.mn-facts {
  position: absolute; inset: 0; z-index: 2;
  list-style: none; margin: 0; padding: 0;
  pointer-events: none;
}
.mn-fact {
  position: absolute;
  pointer-events: auto;
  transition: opacity var(--dur-3) var(--ease-out);
}
.mn-fact[data-pos="tl"] { inset-block-start: 4%;  inset-inline-start: 0; text-align: start; }
.mn-fact[data-pos="tr"] { inset-block-start: 4%;  inset-inline-end: 0;   text-align: end; }
.mn-fact[data-pos="bl"] { inset-block-end: 12%;   inset-inline-start: 0; text-align: start; }
.mn-fact[data-pos="br"] { inset-block-end: 12%;   inset-inline-end: 0;   text-align: end; }

.mn-fact-n {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 1.4rem + 1.7vw, 2.9rem);
  font-weight: 300; line-height: 1; letter-spacing: -.04em;
  color: #fff; font-variant-numeric: tabular-nums;
}
.mn-fact-l {
  display: block; margin-block-start: var(--sp-2);
  font-size: var(--fs-xs); font-weight: 500;
  letter-spacing: .15em; text-transform: uppercase;
  color: rgba(203,216,236,.66);
  max-inline-size: 15ch;
}
.mn-fact[data-pos="tr"] .mn-fact-l,
.mn-fact[data-pos="br"] .mn-fact-l { margin-inline-start: auto; }

/* The one figure that does something. It is a button, so it is reachable by
   keyboard and announces its state; it just does not look like one. */
.mn-fact--live button {
  font: inherit; color: inherit; text-align: inherit;
  background: none; border: 0; padding: 0; cursor: pointer;
  display: block;
}
.mn-fact-cue {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-block-start: var(--sp-3);
  font-size: 11px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--gold-lite);
  opacity: .75;
  transition: opacity var(--dur-2) var(--ease-out);
}
.mn-fact-cue::before {
  content: ""; inline-size: 6px; block-size: 6px; border-radius: 50%;
  background: currentColor; flex: none;
  box-shadow: 0 0 0 0 rgba(212,175,55,.5);
  animation: mnPulse 2.8s var(--ease-soft) infinite;
}
@keyframes mnPulse {
  0%   { box-shadow: 0 0 0 0 rgba(212,175,55,.45); }
  70%  { box-shadow: 0 0 0 9px rgba(212,175,55,0); }
  100% { box-shadow: 0 0 0 0 rgba(212,175,55,0); }
}
.mn-fact--live button:hover .mn-fact-cue,
.mn-fact--live button:focus-visible .mn-fact-cue { opacity: 1; }
.mn-fact--live button[aria-pressed="true"] .mn-fact-cue { color: #fff; }
.mn-fact--live button[aria-pressed="true"] .mn-fact-cue::before { animation: none; }
.mn-fact--live button:focus-visible { outline: 2px solid var(--gold-lite); outline-offset: 6px; border-radius: var(--r-sm); }

/* --- tablet and phone ----------------------------------------------------
   The globe keeps the full width and the figures come out of the margins and
   sit under it in two rows. Nothing is scaled down to fit; the composition
   changes shape. */
@media (max-width: 860px) {
  .mn-stage { block-size: auto; }
  .mn-canvas {
    position: relative; inset: auto;
    block-size: clamp(20rem, 14rem + 34vw, 27rem);
  }
  .mn-facts {
    position: static; display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-6) var(--sp-5);
    margin-block-start: var(--sp-7);
  }
  .mn-fact {
    position: static !important;
    text-align: start !important;
    transform: none !important;
  }
  .mn-fact-l { max-inline-size: none; margin-inline-start: 0 !important; }
  .mn-hint { position: static; transform: none; text-align: center; margin-block-start: var(--sp-4); }
  .mn-read { font-size: .9em; }
}

/* The same figures and the same served list in plain markup, for assistive
   tech and for a JS-off render. */
.mn-sr {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------------------
   REDUCED MOTION
   The resolve is the argument, so freezing at --t: 0 would leave a reader who
   asked for less motion looking at the *problem* with no answer. Reduced
   motion therefore ships the resolved state outright — coordinated, warm,
   fully legible — and simply removes the travel between the two.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .switchboard { --t: 1; }
  .sb-item { transform: none; transition: none; }
  .sb-core-halo { animation: none; }
  .sb-thread, .sb-tally-num, .sb-node-dot, .sb-item-i, .sb-item-t { transition: none; }

  /* The light is present rather than arriving. */
  .sb-h-lead::before { transition: none; opacity: 1; transform: none; }

  /* The highlight stops travelling and rests on the top edge. The panel keeps
     its gold hairline; it simply no longer moves. */
  .hero-credential::after { animation: none; }

  /* The globe holds still: no idle drift, no inertia after a drag, no pulse.
     Dragging still works — that is the visitor moving it, not the page moving
     itself — and the network reveal appears complete rather than sweeping. */
  .mn-fact-cue::before { animation: none; }
  .mn-read { transition: none; }
}


/* ==========================================================================
   13. Homepage 2026-08 revision
   Appended last on purpose: every rule below refines one above it and
   relies on source order rather than specificity escalation, so nothing
   earlier in this file needed editing to accommodate it.
   ========================================================================== */
/* ===========================================================================
   MEDYRA — homepage, 2026-08 revision
   ISOLATED. Loaded after the production site.css and never instead of it.
   Everything here is additive: no production selector is edited, only
   extended. Tokens, spacing and type all come from the real design system.

   DESKTOP-ONLY ITERATION. Nothing below introduces a breakpoint, and the
   production responsive rules are left to do exactly what they already do.
   The single @media block is the pre-existing reduced-motion guard.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   9 & 10 — LANGUAGE AND CURRENCY SELECTORS

   The two controls were built from different parts: language listed a name
   with a small code trailing it, currency listed a code with a small name
   trailing it. Same component, opposite reading order, so they never looked
   related even though they sit side by side.

   Both are now one shape — a fixed-width marker, then the name — so the
   markers form a single column down each menu and the eye can run the list.
   Language keeps the globe glyph on its trigger, which is the symbol it
   already owned; currency takes the monetary sign in the same position.
   The data-lang / data-currency attributes are untouched, so site.js and
   i18n.js keep working exactly as before — this is presentation only.
   --------------------------------------------------------------------------- */
.switch-menu--tokens .opt-token {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 2.25rem; min-block-size: 1.5rem;
  padding-inline: .25rem;
  border-radius: var(--r-sm);
  background: var(--ivory-2);
  border: 1px solid var(--line-2);
  font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .06em;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  transition: background-color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.switch-menu--tokens .opt-token--sym { font-size: var(--fs-sm); letter-spacing: 0; }
.switch-menu--tokens .opt-token--rtl {
  direction: rtl; unicode-bidi: isolate;
  font-size: var(--fs-xs); letter-spacing: 0;
}
.switch-menu--tokens .opt-name {
  flex: 1 1 auto; min-inline-size: 0;
  text-align: start; color: var(--ink-2);
}
.switch-menu--tokens .opt-name i {
  font-style: normal;
  color: var(--ink-3); font-size: var(--fs-xs); font-weight: 400;
  margin-inline-start: .35em;
}
.switch-menu--tokens button { justify-content: flex-start; gap: var(--sp-3); }
.switch-menu--tokens button[aria-checked="true"] .opt-token {
  background: var(--gold-soft);
  border-color: rgba(201,153,47,.45);
  color: var(--gold);
}
.switch-menu--tokens button[aria-checked="true"] .opt-name { color: var(--navy-700); }
.switch-menu--tokens button[aria-checked="true"]::after { margin-inline-start: auto; }
.footer .switch-menu--tokens .opt-token { background: var(--ivory); }

.switch-sym {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 18px; block-size: 18px;
  font-size: 15px; font-weight: 600; line-height: 1;
  opacity: .9;
}

/* ---------------------------------------------------------------------------
   TREATMENT CARDS — LIFT, NOT SHADOW

   The previous pass raised the card and deepened its shadow. The shadow did
   most of the talking, which is why the movement read as a glow rather than
   as a card rising: at ten pixels against a 300px card, travel alone is below
   the threshold where the eye registers height.

   So the lift is carried by three things that agree with each other instead
   of one that has to shout:

     the card travels 14px and the shadow moves DOWN as it goes, so the gap
     between card and page opens the way a real one would;

     the border turns gold and a hairline of gold light runs across the top
     edge, which is the brand's own accent doing the work colour usually does
     with a fill;

     the icon plate and the heading follow production's existing gold
     treatment, untouched.

   The cards that are not hovered give up a pixel and most of their shadow, so
   the raised one is the only object with height on the row. One shared
   transition means moving between cards reads as the elevation being handed
   over rather than as two animations firing.
   --------------------------------------------------------------------------- */
.grid .card--link {
  transition: transform 420ms cubic-bezier(.16,.84,.44,1),
              box-shadow 420ms cubic-bezier(.16,.84,.44,1),
              border-color 300ms var(--ease-out);
  will-change: transform;
}
/* The gold hairline along the top edge. Scaled from the centre so it opens
   outward rather than sliding in from one side. */
.grid .card--link::after {
  content: "";
  position: absolute;
  inset-inline: var(--sp-6);
  inset-block-start: 0;
  block-size: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg,
    rgba(201,153,47,0), var(--gold-lite) 22%, #F4E3A8 50%, var(--gold-lite) 78%, rgba(201,153,47,0));
  transform: scaleX(0);
  transform-origin: 50% 50%;
  opacity: 0;
  transition: transform 420ms cubic-bezier(.16,.84,.44,1), opacity 260ms var(--ease-out);
  pointer-events: none;
  z-index: 3;
}
.grid .card--link:hover,
.grid .card--link:focus-within {
  transform: translateY(-14px);
  border-color: rgba(201,153,47,.55);
  box-shadow: 0 26px 40px -22px rgba(9,40,36,.34), 0 46px 70px -40px rgba(9,40,36,.20);
}
.grid .card--link:hover::after,
.grid .card--link:focus-within::after { transform: scaleX(1); opacity: 1; }

@supports selector(:has(*)) {
  .grid:has(.card--link:hover) .card--link:not(:hover) {
    transform: translateY(1px);
    box-shadow: 0 1px 2px rgba(9,40,36,.03);
    border-color: var(--line-2);
  }
}

/* ---------------------------------------------------------------------------
   TASK 3 — THE PATIENT JOURNEY

   The seven steps were a numbered list with a hairline down the side. The
   content was right and the hierarchy was right; what was missing was any
   sense that the seven are one continuous passage rather than seven
   paragraphs that happen to be stacked.

   So the spine becomes the subject. It runs unbroken from the first step to
   the last, lit gold at the top where the journey begins and fading toward
   the foot; each step sits on it at its own node, and the step's number is
   set as a large ghosted numeral behind the heading rather than as a label in
   front of it — the eye reads the words first and the count second, which is
   the right order for a story.

   Hovering a step brings its node up to full gold, draws its card a little
   toward the reader and lifts the numeral out of the background. Production's
   own scroll reveal still stages the steps in sequence, so arriving at the
   section still reads as the journey being laid out rather than appearing.

   No content is added, removed or reworded. This is entirely presentation.
   --------------------------------------------------------------------------- */
.steps--thread {
  position: relative;
  padding-inline-start: 3.25rem;
}
/* The spine. One element, full height, brightest where the journey starts. */
.steps--thread::before {
  content: "";
  position: absolute;
  inset-block: .75rem 1.25rem;
  inset-inline-start: 1.05rem;
  inline-size: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg,
    rgba(201,153,47,.55) 0%,
    rgba(201,153,47,.34) 26%,
    rgba(182,197,224,.42) 62%,
    rgba(182,197,224,.16) 100%);
}

.steps--thread .step {
  position: relative;
  display: block;
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  margin-inline-start: .5rem;
  border-radius: var(--r-lg);
  background: transparent;
  transition: transform 380ms cubic-bezier(.22,.61,.36,1),
              background-color var(--dur-3) var(--ease-out),
              box-shadow 380ms cubic-bezier(.22,.61,.36,1);
}
.steps--thread .step + .step { margin-block-start: var(--sp-3); }

/* The node on the spine. Sits in the gap the padding opened, so it lands on
   the line rather than beside it. */
.steps--thread .step::before {
  content: "";
  position: absolute;
  inset-block-start: 1.75rem;
  inset-inline-start: -1.02rem;
  inline-size: 11px; block-size: 11px;
  border-radius: 50%;
  background: var(--ivory-2);
  border: 2px solid rgba(201,153,47,.5);
  box-shadow: 0 0 0 4px var(--surface-sunk);
  transition: background-color var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out),
              transform var(--dur-2) var(--ease-out);
}

/* The number, moved behind the heading and set large. aria is unaffected —
   this is the same element, restyled. */
.steps--thread .step-num {
  position: absolute;
  inset-block-start: .45rem;
  inset-inline-end: var(--sp-5);
  font-family: var(--font-display);
  font-size: 3.25rem; font-weight: 300; line-height: 1;
  letter-spacing: -.04em;
  color: var(--navy-700);
  opacity: .07;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  transition: opacity var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
}

.steps--thread .step-body { position: relative; z-index: 1; }
.steps--thread .step-body h3 {
  font-size: var(--fs-h4);
  letter-spacing: -.015em;
  margin-block-end: var(--sp-2);
}
.steps--thread .step-body p { color: var(--ink-3); max-inline-size: 46ch; }

/* Hover: the step comes forward, its node fills, its numeral surfaces. */
.steps--thread .step:hover {
  background: var(--white);
  box-shadow: 0 2px 4px rgba(9,40,36,.04), 0 16px 34px -20px rgba(9,40,36,.22);
  transform: translateX(4px);
}
.steps--thread .step:hover::before {
  background: var(--gold-lite);
  border-color: var(--gold);
  transform: scale(1.18);
}
.steps--thread .step:hover .step-num { opacity: .16; color: var(--gold); }

/* ---------------------------------------------------------------------------
   TASK 4 — THE COST ESTIMATOR
   --------------------------------------------------------------------------- */

/* The comparison control reads as one line. A procedure name runs long and a
   country name runs short, so giving both fields the same stacked shape left
   "Compare against" sitting above a half-empty row. The label now sits beside
   its select, and the pair bottom-aligns with the procedure control next to
   it. */
.estimator-controls {
  /* The comparison column sizes to its own content instead of taking a rigid
     half. Split evenly, the inline label ate enough of its column that the
     select fell to 132px and clipped "United States" to "United…" — the fix
     for a stranded label should not create a truncated value. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.18fr);
  align-items: end;
}
.field--inline {
  display: flex; align-items: center; gap: var(--sp-3);
  flex-wrap: nowrap;
}
/* Wide enough for the longest country in the list with room to spare. Sizing
   the whole column to content instead swung it the other way — the comparison
   field took 364px and squeezed the procedure select down to 158px, which
   clips "Heart Bypass (CABG)". Both controls need to fit their own longest
   value, so the split is weighted rather than content-driven. */
.field--inline .select { min-inline-size: 9.5rem; }
.field--inline .field-label {
  margin: 0; flex: none; white-space: nowrap;
}
.field--inline .select { flex: 1 1 auto; min-inline-size: 0; }

/* --- the breathing perimeter ----------------------------------------------
   The gold stays exactly as it was; what changes is how it moves.

   It previously carried the header credential's travelling arc — one bright
   point circling the edge. On a panel this large that highlight is only ever
   on a fraction of the perimeter at a time, so three of the four sides sat
   dim while one was lit. The border was animated but the CARD was not
   highlighted.

   A fade instead lights the whole boundary at once: all four sides rise
   together, hold at the top of the breath, and settle back. That is what
   draws the eye to the panel rather than to a moving dot on its edge.

   Tuned to read as breathing rather than blinking:
     6s for a full cycle, which is near resting breath and well below the
     rate at which a repeating change becomes a flicker;
     ease-in-out at both ends, so it arrives and leaves rather than steps;
     the floor is 0.34, not 0, so the border never disappears — the card
     always has a defined gold edge and the animation only varies its
     strength;
     the peak carries a very slight outward bloom, enough to feel lit rather
     than merely brighter.

   One element, one CSS animation, no JavaScript, and nothing outside the
   card's own boundary. */
@keyframes estBreathe {
  0%,
  100% { opacity: .34; }
  50%  { opacity: 1; }
}

.estimator--lit {
  position: relative;
  isolation: isolate;
}
.estimator--lit::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 2.5px;
  /* The same gold as the header ring, laid around the whole edge rather than
     swept through it. The diagonal keeps it from reading as a flat outline. */
  background: linear-gradient(135deg,
    rgba(233,206,131,.85) 0%,
    rgba(255,246,214,1)  22%,
    rgba(201,153,47,.72) 50%,
    rgba(255,246,214,1)  78%,
    rgba(233,206,131,.85) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
  z-index: 3;
  animation: estBreathe 6s cubic-bezier(.45,0,.55,1) infinite;
}
/* The bloom rides the same cycle a beat softer, so the peak of the breath
   reads as light coming off the edge rather than as the line simply going
   brighter. Confined to the card's own box — this is not a glow panel behind
   the calculator. */
.estimator--lit::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  box-shadow: 0 0 18px -2px rgba(201,153,47,.55);
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  animation: estBreathe 6s cubic-bezier(.45,0,.55,1) infinite;
}

/* ---------------------------------------------------------------------------
   REDUCED MOTION
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .switch-menu--tokens .opt-token { transition: none; }
  .grid .card--link,
  .steps--thread .step,
  .steps--thread .step::before,
  .steps--thread .step-num { transition: none; }
  /* The light rests on the top edge rather than travelling. */
  /* Held at full strength: the border stays, the breathing stops. */
  .estimator--lit::after { animation: none; opacity: 1; }
  .estimator--lit::before { animation: none; opacity: 0; }
}

/* ---------------------------------------------------------------------------
   PATIENT STORIES — "People who came to India and went home"

   The previous pass took this section to navy. That made it heavy: the page
   already spends its dark ground on the globe, and putting the patients'
   own accounts on the same field made them read as more infrastructure
   rather than as people. Three human stories should not be the darkest thing
   on the page.

   So it comes back into the light, but not to plain white — a warm ivory that
   sits a shade off the sections either side, so the block is distinct without
   being a slab. The gold does the accenting instead of the background doing
   the shouting.

   The one added device is a hairline that runs behind the row and fades out
   at both ends: three journeys out and back, drawn once, quietly. It is
   decoration in the strict sense — no label, no claim — and it is the only
   thing here that is not either the original content or the brand's own
   accent treatment.

   Every word, tag, date and link is the original.
   --------------------------------------------------------------------------- */
.stories-arc {
  position: relative;
  isolation: isolate;
  /* Warm, not white. Two very low-opacity blooms — one gold at the top left
     where the eyebrow sits, one cool at the lower right — keep the ground
     from reading as flat card stock. */
  /* The warm ivory of the previous pass drifted beige, which read as aged
     paper rather than as a clinic. This is the same idea taken cooler and
     cleaner: the site's own --ivory as the base, one low gold wash at the
     head where the eyebrow sits, and a faint navy settling at the foot so
     the block resolves into the section beneath it instead of stopping.
     No colour here is outside the existing palette. */
  background:
    radial-gradient(64% 46% at 14% 0%, rgba(201,153,47,.10), transparent 58%),
    radial-gradient(80% 52% at 88% 104%, rgba(26,49,96,.07), transparent 60%),
    linear-gradient(180deg, var(--white) 0%, var(--ivory) 34%, #EEF2F8 100%);
  color: var(--ink);
}

/* The route line. Sits behind the cards, level with their heads, and is gone
   before it reaches either margin. */
.stories-arc .grid {
  position: relative;
}
.stories-arc .grid::before {
  content: "";
  position: absolute;
  inset-inline: -4%;
  inset-block-start: 6.5rem;
  block-size: 1px;
  z-index: 0;
  background: linear-gradient(90deg,
    rgba(201,153,47,0) 0%,
    rgba(201,153,47,.34) 18%,
    rgba(201,153,47,.55) 50%,
    rgba(201,153,47,.34) 82%,
    rgba(201,153,47,0) 100%);
  pointer-events: none;
}

.stories-arc .eyebrow { color: var(--gold); }
.stories-arc .eyebrow::before { background: var(--gold-lite); }
.stories-arc h2 { color: var(--ink); }

/* --- the cards ------------------------------------------------------------
   White against the warm ground, so each story reads as a document laid on a
   surface rather than as a panel cut out of it. */
.stories-arc .story-card {
  position: relative;
  z-index: 1;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(9,40,36,.05), 0 14px 30px -24px rgba(9,40,36,.20);
  transition: transform 420ms cubic-bezier(.16,.84,.44,1),
              box-shadow 420ms cubic-bezier(.16,.84,.44,1),
              border-color 300ms var(--ease-out);
}
/* The gold spine on the inside edge, drawn from the top on approach — the
   same device the journey section uses, at the scale of one story. */
.stories-arc .story-card::before {
  content: "";
  position: absolute; inset-block: 0; inset-inline-start: 0;
  inline-size: 2px; z-index: 2;
  background: linear-gradient(180deg, var(--gold-lite), rgba(201,153,47,0) 70%);
  transform: scaleY(0); transform-origin: top;
  transition: transform 520ms cubic-bezier(.16,.84,.44,1);
}
.stories-arc .story-card:hover,
.stories-arc .story-card:focus-within {
  transform: translateY(-8px);
  border-color: rgba(201,153,47,.4);
  box-shadow: 0 20px 34px -20px rgba(9,40,36,.24), 0 40px 64px -40px rgba(9,40,36,.16);
}
.stories-arc .story-card:hover::before,
.stories-arc .story-card:focus-within::before { transform: scaleY(1); }

/* The illustration sits on a tinted plate rather than bleeding to the card
   edge, so it reads as a plate in a case file. */
.stories-arc .post-thumb {
  background: linear-gradient(180deg, var(--navy-50) 0%, var(--ivory-2) 100%);
  border-block-end: 1px solid var(--line-2);
}
.stories-arc .post-thumb img {
  transition: transform 620ms cubic-bezier(.16,.84,.44,1);
}
.stories-arc .story-card:hover .post-thumb img,
.stories-arc .story-card:focus-within .post-thumb img { transform: scale(1.03); }

/* The speciality mark: a gold rule and small caps. --gold rather than
   --gold-lite because this is small text on a light ground, where the lighter
   tone would not carry. */
.stories-arc .tag {
  display: inline-flex; align-items: center; gap: .55rem;
  background: none; border: 0; padding: 0;
  color: var(--gold);
  font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
}
.stories-arc .tag::before {
  content: ""; inline-size: 1.5rem; block-size: 1px;
  background: var(--gold-lite); flex: none;
}

.stories-arc .post-body { padding-block-start: var(--sp-5); }
.stories-arc .post-body h3 { margin-block-start: var(--sp-3); }
.stories-arc .post-body h3 a {
  color: var(--ink); text-decoration: none;
  background-image: linear-gradient(var(--gold-lite), var(--gold-lite));
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size 420ms var(--ease-out);
}
.stories-arc .story-card:hover .post-body h3 a,
.stories-arc .story-card:focus-within .post-body h3 a { background-size: 100% 1px; }
.stories-arc .post-body p { color: var(--ink-3); }
.stories-arc .post-foot { color: var(--ink-3); }
.stories-arc .link-arrow { color: var(--gold); }
.stories-arc .link-arrow:hover { color: var(--navy-700); }

/* ---------------------------------------------------------------------------
   CTA BAND — "No account, no payment, no obligation"

   The lead paragraph inherited .lead's --ink-2, which is a colour for light
   grounds. On the band's navy that measured 1.57:1 — the sentence was not
   low-contrast, it was very nearly invisible.

   --navy-100 is the brand's own token for body text on navy and takes it to
   about 11:1. Deliberately that token rather than #fff: white would flatten
   it against the heading directly above, and the point of this line is that
   it reads as the reassurance underneath the headline, not as a second
   headline. Text, position, size and weight are all untouched.
   --------------------------------------------------------------------------- */
.cta-band .lead { color: var(--navy-100); }
@media (prefers-reduced-motion: reduce) {
  .stories-arc .story-card,
  .stories-arc .story-card::before,
  .stories-arc .post-thumb img,
  .stories-arc .post-body h3 a,
  .grid .card--link,
  .grid .card--link::after { transition: none; }
}

/* ---------------------------------------------------------------------------
   TESTIMONIALS — "What the experience actually felt like"

   Three accounts in three equal cards gave the reviewer and the review the
   same weight, and cut each quote into a narrow column where a sentence
   breaks four or five times. The account is the content; the person is the
   provenance. They should not be the same size or the same shape.

   So the row becomes a ledger. Each testimonial is one full-width entry with
   the person on the left in a fixed column — initials, name, flag, city and
   procedure — a gold hairline between, and the quote itself running long on
   the right at a comfortable measure. The separation is literal: a rule you
   can see, with the identity set small and quiet against the quote set large.

   The quote mark moves behind the opening words as a watermark rather than
   sitting above them as an icon, so the first thing read is the sentence.

   Same three accounts, same words, same names, same flags, same procedures.
   --------------------------------------------------------------------------- */
.quotes-list { display: block; }

.quotes-ledger .quote-card {
  position: relative;
  display: grid;
  grid-template-columns: 15rem 1fr;
  align-items: start;
  gap: 0;
  margin: 0;
  padding: var(--sp-7) 0;
  background: none;
  border: 0;
  border-block-end: 1px solid var(--line-2);
}
.quotes-ledger .quote-card:first-child { padding-block-start: var(--sp-5); }
.quotes-ledger .quote-card:last-child { border-block-end: 0; }

/* --- left: who --------------------------------------------------------- */
.quotes-ledger .quote-foot {
  grid-column: 1;
  display: block;
  /* Row 1 explicitly. The quote comes first in the DOM and takes column 2,
     and grid's sparse auto-placement only moves forward — so the attribution,
     asking for column 1, was pushed down to a second row. Both cells have to
     name their row.

     margin:0 undoes production's margin-block-start:auto, which pushes the
     attribution to the foot of a vertical card. Here it is a column heading,
     not a footer. */
  grid-row: 1;
  margin: 0;
  padding-inline-end: var(--sp-6);
  border-inline-end: 1px solid var(--line);
  min-block-size: 6rem;
  position: relative;
}
/* The gold segment on the dividing rule — the only strong accent in the
   entry, and it marks the join between the person and what they said. */
.quotes-ledger .quote-foot::after {
  content: "";
  position: absolute;
  inset-inline-end: -1px;
  inset-block-start: 0;
  inline-size: 1px; block-size: 2.75rem;
  background: linear-gradient(180deg, var(--gold-lite), rgba(201,153,47,0));
}
.quotes-ledger .avatar {
  display: inline-flex;
  margin-block-end: var(--sp-4);
}
.quotes-ledger .quote-name {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: 400;
  letter-spacing: -.015em;
  color: var(--ink);
  line-height: 1.15;
}
.quotes-ledger .quote-where {
  display: flex; align-items: flex-start; gap: .5rem;
  margin-block-start: var(--sp-3);
  font-size: var(--fs-xs);
  line-height: 1.5;
  letter-spacing: .04em;
  color: var(--ink-3);
}
.quotes-ledger .quote-where .flag {
  inline-size: 20px; block-size: 14px; flex: none;
  margin-block-start: .15em;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(13,27,46,.10);
}

/* --- right: what they said --------------------------------------------- */
.quotes-ledger .quote-text {
  grid-column: 2;
  grid-row: 1;
  position: relative;
  z-index: 1;
  margin: 0;
  padding-inline-start: var(--sp-7);
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1rem + .62vw, 1.6rem);
  font-weight: 300;
  line-height: 1.5;
  letter-spacing: -.012em;
  color: var(--ink);
  max-inline-size: 54ch;
  text-wrap: pretty;
}

/* The mark, behind the first line. */
.quotes-ledger .quote-mark {
  position: absolute;
  inset-block-start: calc(var(--sp-7) - .35rem);
  inset-inline-start: calc(15rem + var(--sp-5));
  inline-size: 4.25rem; block-size: 4.25rem;
  color: var(--gold-lite);
  opacity: .13;
  z-index: 0;
  pointer-events: none;
}

/* A quiet lift on approach: the rule warms and the entry shifts a hair. */
.quotes-ledger .quote-card {
  transition: background-color var(--dur-3) var(--ease-out);
}
.quotes-ledger .quote-card:hover { background: var(--ivory); }
.quotes-ledger .quote-card:hover .quote-foot::after { block-size: 5.5rem; }
.quotes-ledger .quote-foot::after { transition: block-size 420ms cubic-bezier(.16,.84,.44,1); }

@media (prefers-reduced-motion: reduce) {
  .quotes-ledger .quote-card,
  .quotes-ledger .quote-foot::after { transition: none; }
}

/* ---------------------------------------------------------------------------
   TESTIMONIALS v6 — THE ANIMATED TESTIMONIAL
   "What the experience actually felt like"

   The ledger above showed all three accounts at once. Three testimonials in
   view together are three things to skim; a reader gives each one a second
   and believes none of them. This shows ONE patient — their face, their
   name, their city, their procedure and their words — and holds the other
   two behind as depth, so the section reads as people rather than as proof.

   THE GROUND
   The section stays white, and the component sits on it as one navy plate.
   Navy is the colour this brand keeps for its own voice — the hero and the
   network globe both use it — so an account of what MEDYRA was actually
   like belongs on it. Taking the whole SECTION navy was tried on Stories
   earlier in this prototype and made the page heavy; a plate keeps the
   page's light rhythm and still gives the portraits a ground warm enough to
   sit in. It also does the real work here: three faces lit at 3200K against
   deep navy is the entire reason the section feels human rather than
   corporate.

   THE GOLD
   Four places, all hairlines: the top edge of the plate, the frame on the
   portrait that is forward, the two navigation buttons, and the numeral of
   the account you are on. Nothing glows and nothing pulses. Gold here marks
   what is current, which is exactly the job it does everywhere else in this
   design system.

   DESKTOP ONLY. No breakpoint is introduced below, and none of the existing
   ones are touched — the block is entirely new selectors, so the section's
   published behaviour at any width is unchanged until this is approved.
   --------------------------------------------------------------------------- */

.at {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 24rem) minmax(0, 1fr);
  gap: var(--sp-8);
  align-items: center;
  padding: var(--sp-8);
  border-radius: var(--r-lg);
  background:
    linear-gradient(158deg, var(--navy-900) 0%, var(--navy-800) 58%, #0B1A34 100%);
  box-shadow: var(--e-4);
  overflow: hidden;
  isolation: isolate;
}

/* The hairline along the top edge. Brightest at the centre and gone by the
   corners, so the plate is lit rather than outlined. */
.at::before {
  content: "";
  position: absolute;
  inset-block-start: 0; inset-inline: 0;
  block-size: 1px;
  background: linear-gradient(90deg,
    transparent, rgba(212, 175, 55, .5) 28%, rgba(212, 175, 55, .62) 50%,
    rgba(212, 175, 55, .5) 72%, transparent);
  z-index: 2;
}

/* Atmosphere behind the portrait, not light cast on it. One very soft
   radial, sized larger than the stage and centred on it, so the stack has
   air around it instead of sitting flat on the gradient. */
.at::after {
  content: "";
  position: absolute;
  inset-block-start: 50%; inset-inline-start: 20%;
  inline-size: 44rem; block-size: 44rem;
  translate: -50% -50%;
  background: radial-gradient(circle,
    rgba(58, 93, 160, .30) 0%, rgba(58, 93, 160, .12) 42%, transparent 68%);
  pointer-events: none;
  z-index: 0;
}

.at > * { position: relative; z-index: 1; }

/* --- the portrait stage ---------------------------------------------------
   A square. The supplied portraits are 5:4 landscape, so a square crop takes
   a little off each side and leaves the face where the photographer put it;
   a portrait-shaped box would have cut the shoulders off all three. */
.at-stage {
  position: relative;
  aspect-ratio: 1;
  perspective: 1400px;
  transform-style: preserve-3d;
}

.at-card {
  position: absolute;
  inset: 0;
  transform-origin: bottom center;
  transition:
    transform var(--dur-4) var(--ease-soft),
    opacity   var(--dur-4) var(--ease-soft);
}

/* The frame. Separate element from .at-card on purpose: the card owns the
   stacking transform, this owns the arrival lift and the filter. Filters
   flatten 3D, so it has to be the child or the depth collapses. */
.at-shot {
  position: relative;
  block-size: 100%;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--navy-950);
  box-shadow: 0 24px 60px -18px rgba(0, 0, 0, .68);
  transition: filter var(--dur-4) var(--ease-soft);
}
.at-shot img {
  inline-size: 100%; block-size: 100%;
  object-fit: cover;
  /* Faces sit above centre in all three frames. */
  object-position: 50% 34%;
  display: block;
  user-select: none;
}

/* The gold frame belongs to the portrait that is forward — it is how you
   know which face the words belong to. */
.at-shot::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  border: 1px solid transparent;
  transition: border-color var(--dur-4) var(--ease-soft);
  pointer-events: none;
}

/* Positions. data-pos is distance behind the front card, set by
   proto-testimonials.js. Both held cards tilt away from the vertical and
   away from each other, so the stack fans rather than stacks square. */
.at.is-ready .at-card[data-pos="0"] {
  transform: translate3d(0, 0, 0) rotate(0deg) scale(1);
  opacity: 1;
  z-index: 3;
}
.at.is-ready .at-card[data-pos="0"] .at-shot::after { border-color: rgba(212, 175, 55, .40); }

.at.is-ready .at-card[data-pos="1"] {
  transform: translate3d(5%, 1.5%, -110px) rotate(4.5deg) scale(.93);
  opacity: .46;
  z-index: 2;
}
.at.is-ready .at-card[data-pos="1"] .at-shot { filter: saturate(.72) brightness(.74); }

.at.is-ready .at-card[data-pos="2"] {
  transform: translate3d(-5.5%, 2.5%, -180px) rotate(-5.5deg) scale(.885);
  opacity: .32;
  z-index: 1;
}
.at.is-ready .at-card[data-pos="2"] .at-shot { filter: saturate(.6) brightness(.62); }

.at.is-ready .at-card:not([data-pos="0"]) { cursor: pointer; }

/* The arrival. The reference throws the promoted card up 80px; at this size
   that is a bounce, and a bounce is the wrong register for what these three
   people are describing. Twenty pixels reads as the card coming forward and
   settling, which is all the movement the moment needs. */
@keyframes atRise {
  0%   { transform: translateY(0); }
  42%  { transform: translateY(-20px); }
  100% { transform: translateY(0); }
}
.at-card.is-entering .at-shot { animation: atRise 720ms var(--ease-soft); }

/* --- the record ----------------------------------------------------------- */
.at-panel {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-7);
  min-block-size: 100%;
}

/* All three records occupy one grid cell, so the panel is always as tall as
   the longest account and the layout cannot move when you navigate — including
   after a language switch, where the same sentence can run two lines longer. */
.at-records { display: grid; }

.at.is-ready .at-record {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition:
    opacity var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-out),
    visibility 0s linear var(--dur-3);
}
.at.is-ready .at-record.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity var(--dur-3) var(--ease-out) 60ms,
    transform 380ms var(--ease-out) 60ms,
    visibility 0s;
}

.at-id { display: flex; flex-direction: column; gap: var(--sp-2); }

.at-name {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: #F3F7FE;
}

.at-where {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--navy-200);
}
.at-where .flag {
  inline-size: 20px; block-size: 14px;
  border-radius: 2px;
  flex: none;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .18);
}

@keyframes atUp {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.at-record.is-active .at-name  { animation: atUp 420ms var(--ease-out) both; }
.at-record.is-active .at-where { animation: atUp 420ms var(--ease-out) 70ms both; }

.at-quote { position: relative; margin-block-start: var(--sp-6); }

/* The mark sits behind the opening words as a watermark. It is the same
   glyph the section has always used — moved out of the way of the sentence
   rather than removed, so the first thing read is what the patient said. */
.at-mark {
  position: absolute;
  inline-size: 5.5rem; block-size: 5.5rem;
  inset-block-start: -1.6rem; inset-inline-start: -1.2rem;
  color: rgba(212, 175, 55, .11);
  z-index: 0;
  pointer-events: none;
}

/* The string i18n.js owns and screen readers read. Once the component is
   live the words are shown by .at-anim instead, so this goes to the
   standard visually-hidden treatment rather than display:none — it still
   has to be announced. */
.at.is-ready .at-text {
  position: absolute;
  inline-size: 1px; block-size: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.at-text,
.at-anim {
  position: relative;
  z-index: 1;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 1.05rem + .72vw, 1.68rem);
  font-weight: 300;
  line-height: 1.52;
  color: var(--on-dark);
  max-inline-size: 34ch;
}

/* Each word comes in from a blur. This is the reference component's one
   real signature and it survives intact — it is what makes the quote read
   as being spoken rather than swapped. Fifteen milliseconds a word puts a
   forty-word account at about six-tenths of a second end to end, which is
   under the threshold where a reader starts waiting for it. */
.at-anim span { display: inline-block; }

@keyframes atWord {
  from { opacity: 0; filter: blur(7px); transform: translateY(5px); }
  to   { opacity: 1; filter: blur(0);   transform: none; }
}
.at-record.is-active .at-anim span {
  animation: atWord 400ms var(--ease-out) both;
  animation-delay: calc(var(--i) * 15ms);
}

/* --- navigation ----------------------------------------------------------- */
.at-nav { display: flex; align-items: center; gap: var(--sp-3); }

.at-btn {
  inline-size: 2.875rem; block-size: 2.875rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  border: 1px solid rgba(212, 175, 55, .34);
  background: transparent;
  color: var(--gold-lite);
  cursor: pointer;
  transition:
    border-color var(--dur-2) var(--ease-out),
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}
.at-btn svg { inline-size: 1.25rem; block-size: 1.25rem; transition: transform var(--dur-3) var(--ease-out); }
.at-btn:hover, .at-btn:focus-visible {
  border-color: rgba(212, 175, 55, .8);
  background: rgba(212, 175, 55, .10);
  color: #F0D68A;
}
/* The arrows cant on hover — the reference's one piece of wit, and small
   enough to keep. */
.at-btn[data-at-nav="prev"]:hover svg { transform: rotate(-12deg); }
.at-btn[data-at-nav="next"]:hover svg { transform: rotate(12deg); }

.at-count {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  margin-inline-start: var(--sp-3);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--navy-200);
}
.at-count-n { color: var(--gold-lite); }
.at-count i { inline-size: 1.5rem; block-size: 1px; background: rgba(182, 197, 224, .38); }

/* --- before the script runs -----------------------------------------------
   Not a design, a floor. Every word is readable, the three portraits are
   all present, and nothing is absolutely positioned on top of anything
   else. If proto-testimonials.js fails to load this is what is left, and it
   is still the section. */
.at:not(.is-ready) .at-stage {
  aspect-ratio: auto;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3);
}
.at:not(.is-ready) .at-card { position: static; aspect-ratio: 1; }
.at:not(.is-ready) .at-record + .at-record { margin-block-start: var(--sp-7); }
.at:not(.is-ready) .at-nav { display: none; }

@media (prefers-reduced-motion: reduce) {
  .at-card,
  .at-shot,
  .at-btn svg { transition: none; }
  .at-card.is-entering .at-shot,
  .at-record.is-active .at-name,
  .at-record.is-active .at-where,
  .at-record.is-active .at-anim span { animation: none; }
  /* Without the per-word entry the words still have to be visible — the
     animation was carrying opacity. */
  .at-record.is-active .at-anim span { opacity: 1; filter: none; transform: none; }
}

/* ===========================================================================
   v7 — FOUR SECTIONS RESTAGED
   Appended last, all-new selectors. No rule above is edited, no shared or
   global style is touched, and no breakpoint is introduced or changed.
   Desktop iteration only.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1 — TREATMENT SUITE (six cards)

   The six cards, their headings, copy, prices, stay lengths and links are
   untouched. Six equal tiles read as a menu; these are the six disciplines
   the business is organised around, so they are restaged as a numbered suite
   of records.

   Four things carry it: a standing numeral set from a CSS counter, so the
   markup needed no per-card edit; the icon lifted onto a tinted plate rather
   than floating; a hairline rule under the meta so price and length of stay
   read as record fields; and a gold edge on the leading side that grows on
   approach — the same device the stories register uses below, so the two
   sections rhyme.
   --------------------------------------------------------------------------- */
.treat-grid { counter-reset: treat; }

.treat-suite .treat-grid .card--link {
  counter-increment: treat;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-6);
  padding-block-end: 0;
  background: var(--white);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  overflow: hidden;
}

/* The numeral rides .card-icon::after because .card--link's own ::before and
   ::after are both already spoken for in the production stylesheet — this
   refines the card without competing for them. position:static on the icon
   guarantees the numeral anchors to the card, not to the plate. */
.treat-suite .treat-grid .card-icon { position: static; }
.treat-suite .treat-grid .card-icon::after {
  content: counter(treat, decimal-leading-zero);
  position: absolute;
  inset-block-start: var(--sp-5);
  inset-inline-end: var(--sp-5);
  font-family: var(--font-display);
  font-size: 2.6rem; font-weight: 300; line-height: 1;
  letter-spacing: -0.02em;
  color: var(--navy-900); opacity: .07;
  transition: opacity var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
  pointer-events: none;
}
.treat-suite .treat-grid .card--link:hover .card-icon::after,
.treat-suite .treat-grid .card--link:focus-within .card-icon::after {
  opacity: .2; color: var(--gold);
}

/* The icon plate: gold-tinted at rest so the row of six reads warm rather
   than as six navy chips, taking the brand navy on approach — which is the
   production hover, kept. */
.treat-suite .treat-grid .card-icon {
  inline-size: 3rem; block-size: 3rem;
  border-radius: var(--r-sm);
  background: var(--gold-soft);
  color: var(--gold);
  box-shadow: inset 0 0 0 1px rgba(140, 101, 24, .14);
  transition: background-color var(--dur-3) var(--ease-out),
              color var(--dur-3) var(--ease-out),
              box-shadow var(--dur-3) var(--ease-out);
}
.treat-suite .treat-grid .card--link:hover .card-icon {
  background: var(--navy-700); color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
}

.treat-suite .treat-grid h3 { margin-block-end: 0; padding-inline-end: 3.2rem; }
.treat-suite .treat-grid p { color: var(--ink-3); margin-block-end: 0; }

/* The meta footer, ruled off and pushed to the bottom so all six align on it
   however long the description runs. */
.treat-suite .treat-grid .card-meta {
  margin-block-start: auto;
  padding-block: var(--sp-4);
  border-block-start: 1px solid var(--line-2);
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3);
  font-size: var(--fs-xs); color: var(--ink-3);
}
.treat-suite .treat-grid .card-meta strong { font-size: var(--fs-sm); }

/* The leading gold edge, scaled from the top so it grows down the card. */
.treat-suite .treat-grid .card--link .card-icon::before {
  content: "";
  position: absolute;
  inset-block: 0; inset-inline-start: 0;
  inline-size: 2px;
  background: linear-gradient(180deg, var(--gold-lite), rgba(212, 175, 55, 0));
  transform: scaleY(0); transform-origin: top;
  transition: transform var(--dur-4) var(--ease-soft);
}
.treat-suite .treat-grid .card--link:hover .card-icon::before,
.treat-suite .treat-grid .card--link:focus-within .card-icon::before { transform: scaleY(1); }

/* ---------------------------------------------------------------------------
   2 — JOURNEY INFOGRAPHIC

   Replaces the static consult.svg. Seven stops on one route, drawn left to
   right when the block arrives. The information is the seven step headings
   already listed beside it and the nine-day figure already in the lead — the
   diagram restates the shape of the journey, it does not add facts.

   Motion is keyed off .is-in, which the production reveal engine adds on
   scroll. No observer, no timer, no script.
   --------------------------------------------------------------------------- */
.jpath {
  --stops: 7;
  /* Explicit, because this block carries .hide-sm and that utility declares
     `display: initial` — which on a div computes to `inline`, not `block`.
     The original figure it replaces had the same condition and got away with
     it wrapping a single image, but this container has block children,
     padding, a border and a background, none of which an inline box lays out
     predictably. proto.css loads after site.css, so declaring it here wins on
     source order without editing the shared utility. */
  display: block;
  position: relative;
  padding: var(--sp-6) var(--sp-5) var(--sp-5);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--white), var(--ivory));
}

.jpath-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4);
  margin-block-end: var(--sp-5);
}
.jpath-eyebrow {
  font-size: var(--fs-eyebrow); letter-spacing: .16em; text-transform: uppercase;
  font-weight: 600; color: var(--gold);
}
.jpath-span { font-size: var(--fs-xs); color: var(--ink-3); }
.jpath-span b {
  font-family: var(--font-display); font-size: var(--fs-h4); font-weight: 400;
  color: var(--navy-700); margin-inline-end: .25rem;
}
.jpath-span i { font-style: normal; }

/* The <svg> is a fallback bed only; the visible route is drawn on the stops
   row itself, below, so it is guaranteed to pass through every marker. */
.jpath-svg { display: none; }

.jpath-stops {
  position: relative;
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(var(--stops), minmax(0, 1fr));
  align-items: center;
  min-block-size: 8rem;
}

/* The route: a hairline bed always present, and a gold line that draws along
   it when the block scrolls in. */
.jpath-stops::before,
.jpath-stops::after {
  content: "";
  position: absolute;
  inset-inline: 0; inset-block-start: 50%;
  block-size: 1px;
}
.jpath-stops::before { background: var(--line); transform: translateY(-.5px); }
.jpath-stops::after {
  background: var(--gold-lite);
  transform: translateY(-.5px) scaleX(0);
  transform-origin: left center;
  transition: transform 1500ms var(--ease-soft) 140ms;
}
[dir="rtl"] .jpath-stops::after { transform-origin: right center; }
[data-reveal].is-in .jpath-stops::after { transform: translateY(-.5px) scaleX(1); }

/* TRANSITIONS, NOT KEYFRAMES — deliberately, and for the same reason the
   production reveal engine uses them.

   A keyframe animation with fill-mode forwards only reaches its end state if
   the animation actually runs. In any context where the browser is not
   running the rendering lifecycle for this document, it does not run, and the
   element is left sitting on the from-state — which here is opacity 0, so the
   whole infographic would simply be missing rather than un-animated.

   A transition has no such failure: if frames are skipped the computed style
   jumps straight to the target. Same movement, same stagger, and the worst
   case is that it appears instantly instead of drawing. */
.jpath-stops > li {
  position: relative;
  block-size: 100%;
  opacity: 0; transform: translateY(6px);
  transition: opacity 460ms var(--ease-out), transform 460ms var(--ease-out);
  transition-delay: calc(300ms + var(--i) * 150ms);
}
[data-reveal].is-in .jpath-stops > li { opacity: 1; transform: none; }

/* The marker sits on the line; the last is filled, as the destination. */
.jpath-dot {
  position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  inline-size: 11px; block-size: 11px; border-radius: var(--r-pill);
  translate: -50% -50%;
  background: var(--white);
  box-shadow: 0 0 0 1.5px var(--gold-lite);
  z-index: 2;
  transition: box-shadow 420ms var(--ease-out), background-color 420ms var(--ease-out);
}
.jpath-dot--end {
  background: var(--gold-lite);
  box-shadow: 0 0 0 1.5px var(--gold-lite), 0 0 0 5px rgba(212, 175, 55, .16);
}

/* ---------------------------------------------------------------------------
   THE ANIMATION LAYER

   One marker travels the route once, and each stop lights as it reaches it.
   That is the whole idea: the line already says "there is a path", the runner
   says "and you are moved along it" — which is the section's actual claim.

   It runs ONCE. Nothing here loops, nothing pulses indefinitely, and the
   whole sequence is over in about three and a half seconds.

   Everything is keyed off .is-in, the class the production reveal engine adds
   when the block scrolls into view, so it starts on arrival like every other
   animated thing on this page. Purely decorative: the runner carries no
   content, and if the animation never runs the infographic is exactly the
   static diagram it was before.

   Timings are shared through --jt so the runner and the seven lights cannot
   drift apart: the runner crosses in --jt, and stop i lights at the moment
   the runner reaches it, i/6 of the way through.
   --------------------------------------------------------------------------- */
.jpath { --jt: 2600ms; --jt-start: 420ms; }

.jpath-runner {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  inline-size: 9px; block-size: 9px;
  border-radius: var(--r-pill);
  background: var(--gold-lite);
  box-shadow: 0 0 0 4px rgba(212, 175, 55, .18), 0 0 12px 2px rgba(212, 175, 55, .38);
  translate: -50% -50%;
  opacity: 0;
  z-index: 3;
  pointer-events: none;
}
[data-reveal].is-in .jpath-runner {
  animation: jRun var(--jt) var(--ease-soft) var(--jt-start) 1 both;
}
/* Travels the full width of the stops row, then goes out at the destination
   — the last stop is where the journey ends, so the runner does not linger. */
@keyframes jRun {
  0%   { opacity: 0; inset-inline-start: 0; }
  8%   { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; inset-inline-start: 100%; }
}

/* Each stop lights as the runner arrives. A short warm hold, then it settles
   back to its resting state — so the finished diagram looks exactly as it did
   before the animation existed. */
[data-reveal].is-in .jpath-stops > li .jpath-dot {
  animation: jLight 900ms var(--ease-out) 1 both;
  animation-delay: calc(var(--jt-start) + (var(--i) / 6) * var(--jt));
}
@keyframes jLight {
  0%   { box-shadow: 0 0 0 1.5px var(--gold-lite); }
  22%  { box-shadow: 0 0 0 1.5px var(--gold-lite), 0 0 0 7px rgba(212, 175, 55, .26); background: var(--gold-soft); }
  100% { box-shadow: 0 0 0 1.5px var(--gold-lite); }
}
/* The destination keeps its filled state through and after the light. */
[data-reveal].is-in .jpath-stops > li .jpath-dot--end {
  animation: jLightEnd 900ms var(--ease-out) 1 both;
  animation-delay: calc(var(--jt-start) + var(--jt));
}
@keyframes jLightEnd {
  0%   { box-shadow: 0 0 0 1.5px var(--gold-lite), 0 0 0 5px rgba(212, 175, 55, .16); }
  30%  { box-shadow: 0 0 0 1.5px var(--gold-lite), 0 0 0 12px rgba(212, 175, 55, .22); }
  100% { box-shadow: 0 0 0 1.5px var(--gold-lite), 0 0 0 5px rgba(212, 175, 55, .16); }
}

/* The label warms as its stop lights, then settles. */
[data-reveal].is-in .jpath-stops > li .jpath-n {
  animation: jNum 900ms var(--ease-out) 1 both;
  animation-delay: calc(var(--jt-start) + (var(--i) / 6) * var(--jt));
}
@keyframes jNum {
  0%, 100% { color: var(--gold); }
  25%      { color: var(--navy-700); }
}

/* The hairline from marker to label. */
.jpath-tick {
  position: absolute; inset-inline-start: 50%;
  inline-size: 1px; background: var(--line);
  z-index: 1;
}
.jpath-up   .jpath-tick { inset-block-end: 50%; block-size: 1.6rem; }
.jpath-down .jpath-tick { inset-block-start: 50%; block-size: 1.6rem; }

/* The label is allowed to be twice its column and is centred on the marker,
   so a word like "Treatment" sets on one line at this width instead of
   breaking or clipping. It cannot collide with its neighbours: the stops
   alternate above and below the route, so the nearest label on the same side
   is two columns away. */
.jpath-txt {
  position: absolute;
  inline-size: 200%; inset-inline-start: -50%;
  text-align: center;
}
.jpath-up   .jpath-txt { inset-block-end: calc(50% + 2rem); }
.jpath-down .jpath-txt { inset-block-start: calc(50% + 2rem); }

.jpath-n {
  display: block;
  font-family: var(--font-display); font-size: var(--fs-xs); font-weight: 500;
  color: var(--gold); letter-spacing: .04em;
}
.jpath-l {
  display: block; margin-block-start: 2px;
  font-size: 11px; line-height: 1.25; font-weight: 500;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-2);
}

/* ---------------------------------------------------------------------------
   3 — ESTIMATOR CONTROLS: LABELS ON ONE ROW, SELECTS ON THE NEXT

   "Procedure" and "Compare against" now share row 1 and read as a pair of
   column headings over their two controls in row 2.

   Placement is left to the existing two-column grid's own auto-flow — the
   markup is ordered label, label, select, select, which lands exactly that
   way. Nothing here declares a grid line, so the production stylesheet's own
   single-column rule below 620px still governs narrow widths untouched.
   --------------------------------------------------------------------------- */
.estimator-controls--rows { gap: var(--sp-2) var(--sp-4); align-items: end; }
.estimator-controls--rows .field-label { margin-block-end: 0; }

/* ---------------------------------------------------------------------------
   4 — OTHER MARKETS
   Rows are built by proto-estimator.js from the same data the calculator
   uses, reusing the production .compare-row structure so the bars, track and
   price column are the estimator's own rather than a second chart.
   --------------------------------------------------------------------------- */
.mkts-h { display: block; }
.mkts-proc { color: var(--ink); }
.mkts-h-tail { color: var(--ink-3); font-weight: 400; }

/* The width arrives as --w rather than an inline transform, so it can
   transition when the procedure changes instead of snapping. */
.mkts-row .compare-fill {
  transform: scaleX(var(--w, 0));
  transition: transform 620ms var(--ease-soft);
}
[dir="rtl"] .mkts-row .compare-fill { transform-origin: right center; }

/* India leads and is the only row in brand navy; every other row keeps the
   muted grey the production stylesheet already uses for a comparison. */
.mkts-row--india .compare-label,
.mkts-row--india .compare-price { color: var(--navy-700); font-weight: 600; }

/* No fill mode: the row's own state is visible, and the animation only adds
   the entry on top of it. With `both` a skipped animation would hold the
   from-state and the market list would be blank rather than un-animated. */
.mkts-rows.is-in .mkts-row {
  animation: mktRow 420ms var(--ease-out);
  animation-delay: calc(var(--i) * 70ms);
}
@keyframes mktRow {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.mkts-foot { margin-block-start: var(--sp-4); }

/* ---------------------------------------------------------------------------
   7 — EXPERIENCE: THE PLATE BECOMES PART OF THE PAGE

   The testimonial's inner composition is deliberately unchanged — same
   portrait stack, same record, same navigation, same motion. What changes is
   the boundary. It was a navy card with a 16px radius and a deep shadow
   dropped into a white section, which is precisely why it read as a component
   inserted into the page rather than part of it.

   So the navy stops being a card and becomes the section, using the device
   the Global Care Network already uses further up: a long vertical gradient
   that starts in the page's own canvas colour, passes through navy, and
   returns to canvas at the bottom. No edge, no corner, no shadow — nothing
   for the eye to read as a seam. The section heading moves onto the navy
   with it.
   --------------------------------------------------------------------------- */
.quotes-anim {
  position: relative;
  background: transparent;              /* section--white no longer paints */
  isolation: isolate;
  overflow: hidden;
}
.quotes-anim::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
    var(--ivory) 0%,
    var(--navy-900) 18%,
    var(--navy-800) 60%,
    var(--navy-900) 86%,
    var(--ivory) 100%);
}
/* Atmosphere, at section scale now rather than inside a box. */
.quotes-anim::after {
  content: "";
  position: absolute; z-index: -1;
  inset-block-start: 48%; inset-inline-start: 26%;
  inline-size: 52rem; block-size: 52rem;
  translate: -50% -50%;
  background: radial-gradient(circle,
    rgba(58, 93, 160, .26) 0%, rgba(58, 93, 160, .10) 44%, transparent 70%);
  pointer-events: none;
}

.quotes-anim .section-head h2 { color: #F3F7FE; }
.quotes-anim .eyebrow { color: var(--gold-lite); }
.quotes-anim .eyebrow::before { background: var(--gold-lite); }

/* The plate's chrome is removed: no ground, no radius, no shadow, no top
   hairline. The grid, the gap and the component inside are untouched. */
.quotes-anim .at {
  background: none;
  box-shadow: none;
  border-radius: 0;
  padding: var(--sp-5) 0 0;
  overflow: visible;
}
.quotes-anim .at::before,
.quotes-anim .at::after { content: none; }

/* ---------------------------------------------------------------------------
   8 — PATIENT STORIES AS A REGISTER

   The three stories, their three images, tags, headlines, standfirsts, dates,
   read times and links are all exactly as they were.

   Three equal teasers side by side read as a blog index, and gave the
   illustration a letterbox crop it was never drawn for. Here each story is
   one wide record: the illustration held in a plate on the leading edge at a
   size where it can be seen, the speciality standing in the gutter between,
   and the headline running long on the right. They step down the page in a
   slight stagger so they read in sequence rather than as three things to
   compare.

   .stories-arc stays on the section, so the warm ground, the eyebrow and the
   tag treatment authored earlier in this file all still apply.
   --------------------------------------------------------------------------- */
/* --- v8 replaces the stepped register below with an editorial hierarchy ---
   The .reg-* rules that follow this block no longer match anything and are
   left in place only so the previous direction can be compared; they are
   inert and are stripped on approval. */

.pstories {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  gap: var(--sp-8);
  align-items: start;
}

.ps { position: relative; }

/* --- the lead ------------------------------------------------------------
   Given the room to be a picture rather than a thumbnail. The plate is the
   ivory the section already uses, so the illustration sits on its own ground
   instead of being cropped into a card. */
.ps-plate {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--ivory-2);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.ps-plate img {
  inline-size: 100%; block-size: 100%;
  object-fit: cover; display: block;
  transition: transform var(--dur-4) var(--ease-soft);
}
.ps:hover .ps-plate img,
.ps:focus-within .ps-plate img { transform: scale(1.03); }

/* A hairline of gold along the base of the lead's plate — the one accent in
   the section, marking which story is the lead. */
.ps--lead .ps-plate::after {
  content: "";
  position: absolute; inset-inline: 0; inset-block-end: 0;
  block-size: 2px;
  background: linear-gradient(90deg, var(--gold-lite), rgba(212, 175, 55, 0) 72%);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--dur-4) var(--ease-soft);
}
[dir="rtl"] .ps--lead .ps-plate::after { transform-origin: right center; }
.ps--lead:hover .ps-plate::after,
.ps--lead:focus-within .ps-plate::after { transform: scaleX(1); }

.ps--lead .ps-body { padding-block-start: var(--sp-5); }
.ps--lead .ps-h {
  margin-block: var(--sp-3) 0;
  font-size: var(--fs-h3);
  line-height: 1.2;
}
.ps--lead .ps-p { margin-block-start: var(--sp-4); max-inline-size: 46ch; }

/* --- the two beside it ---------------------------------------------------
   Ruled entries rather than cards: a rule between them is quieter than two
   more boxes, and keeps the lead the only object in the section. */
.ps-side { display: flex; flex-direction: column; }
.ps--row {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  padding-block: var(--sp-6);
  border-block-start: 1px solid var(--line-2);
}
.ps-side .ps--row:first-child { border-block-start: 0; padding-block-start: 0; }
.ps-side .ps--row:last-child { padding-block-end: 0; }

.ps-plate--sm { aspect-ratio: 1; border-radius: var(--r-sm); }

.ps--row .ps-h {
  margin-block: var(--sp-3) 0;
  font-size: var(--fs-h4);
  line-height: 1.3;
}
.ps--row .ps-p { margin-block-start: var(--sp-3); }

/* Shared: the headline underline and the footer. */
.ps-h a {
  color: var(--ink); text-decoration: none;
  background-image: linear-gradient(var(--gold-lite), var(--gold-lite));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size var(--dur-3) var(--ease-out);
}
.ps:hover .ps-h a,
.ps:focus-within .ps-h a { background-size: 100% 1px; }
.ps-foot { margin-block-start: var(--sp-4); color: var(--ink-3); }

@media (prefers-reduced-motion: reduce) {
  .ps-plate img, .ps-h a, .ps--lead .ps-plate::after { transition: none; }
}

.reg { display: flex; flex-direction: column; gap: var(--sp-5); }

.reg-item {
  position: relative;
  display: grid;
  grid-template-columns: 13rem 8.5rem minmax(0, 1fr);
  align-items: center;
  gap: 0 var(--sp-6);
  padding: var(--sp-5);
  background: var(--white);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  box-shadow: var(--e-1);
  /* The stagger: each record sits a little further in than the one above, so
     the column reads as a diagonal rather than a hard left edge. */
  margin-inline-start: calc(var(--s, 0) * 2.25rem);
  transition: transform var(--dur-3) var(--ease-out),
              box-shadow var(--dur-3) var(--ease-out),
              border-color var(--dur-3) var(--ease-out);
}
.reg-item:hover,
.reg-item:focus-within {
  transform: translateY(-3px);
  box-shadow: var(--e-3);
  border-color: rgba(212, 175, 55, .38);
}

/* The illustration on a tinted plate — a document laid on the record rather
   than a thumbnail bleeding to its edge. */
.reg-plate {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--ivory-2);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.reg-plate img {
  inline-size: 100%; block-size: 100%;
  object-fit: cover; display: block;
  transition: transform var(--dur-4) var(--ease-soft);
}
.reg-item:hover .reg-plate img,
.reg-item:focus-within .reg-plate img { transform: scale(1.04); }

/* The speciality, standing in the gutter. */
.reg-mark {
  margin: 0;
  padding-inline-end: var(--sp-5);
  border-inline-end: 1px solid var(--line-2);
  align-self: stretch;
  display: flex; align-items: center;
}
.reg-body { min-inline-size: 0; }
.reg-h { margin: 0; font-size: var(--fs-h4); line-height: 1.28; }
.reg-h a {
  color: var(--ink); text-decoration: none;
  background-image: linear-gradient(var(--gold-lite), var(--gold-lite));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size var(--dur-3) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.reg-item:hover .reg-h a,
.reg-item:focus-within .reg-h a { background-size: 100% 1px; }
.reg-p { margin-block: var(--sp-3) 0; max-inline-size: 56ch; }
.reg-foot { margin-block-start: var(--sp-4); color: var(--ink-3); }

@media (prefers-reduced-motion: reduce) {
  .treat-suite .treat-grid .card-icon,
  .treat-suite .treat-grid .card-icon::before,
  .treat-suite .treat-grid .card-icon::after,
  .mkts-row .compare-fill,
  .reg-item, .reg-plate img, .reg-h a { transition: none; }
  [data-reveal].is-in .jpath-stops::after,
  [data-reveal].is-in .jpath-stops > li,
  .mkts-rows.is-in .mkts-row { animation: none; }
  /* Without the entry animations these still have to be visible. */
  .jpath-stops > li { opacity: 1; transform: none; }
  .jpath-stops::after { transform: translateY(-.5px) scaleX(1); }
  .mkts-rows.is-in .mkts-row { opacity: 1; transform: none; }
}


/* ---------------------------------------------------------------------------
   9 — PATIENT STORIES: EDITORIAL POLISH

   Appended last, per this file's own convention: nothing above is edited, so
   the whole pass reverts by deleting this block. The v8 structure is kept
   exactly — one lead with a 16/10 plate, two ruled entries beside it, the
   same three images, tags, headlines, standfirsts, dates, read times and
   links. No markup changed, no content changed, no information architecture
   changed. The ledger numerals below are a CSS counter, not new elements.

   WHY IT READ FLAT
   The bones were right and the surface was doing almost nothing:

     the plates were a flat ivory box with one 1px grey ring — no elevation,
     no seat, so three illustrations sat on the page like pasted images
     rather than like plates laid on a record;

     the section's only gold was three tag rules. The gold hairline that
     marks the lead was authored at `transform: scaleX(0)`, i.e. it does not
     exist until you hover — so at rest, which is how the section is
     actually seen, the lead carried no accent at all and nothing said which
     story was the lead;

     the divider between the two entries was flat --line-2, where every
     other rule on this page is a gradient that fades;

     the two entries had no hover of their own beyond the shared image zoom;

     lead and entries shared one standfirst colour and one foot treatment,
     so the hierarchy was carried by font-size alone.

   WHAT THIS ADDS — all of it devices already in use on this page:
     the seated, elevated plate from the treatment suite's icon plate;
     the ghosted Fraunces decimal-leading-zero numeral from .treat-suite;
     the translateX-on-approach from .steps--thread;
     the gradient hairline used by every other rule in the design;
     the ruled meta footer from .card-meta;
     tabular figures, as .steps--thread .step-num already sets.
   No new colour, radius, easing or font is introduced.
   --------------------------------------------------------------------------- */

/* --- the plates: seated and lifted, not pasted -----------------------------
   A cooler navy hairline instead of the grey one, a short inner shadow along
   the base so the artwork sits *in* the plate rather than on it, and real
   elevation off the section ground. box-shadow only — nothing here can move
   the layout. */
.ps-plate {
  box-shadow:
    inset 0 0 0 1px rgba(26, 49, 96, .11),
    inset 0 -22px 34px -26px rgba(10, 23, 48, .30),
    var(--e-2);
  transition: box-shadow var(--dur-3) var(--ease-out);
}
.ps:hover .ps-plate,
.ps:focus-within .ps-plate {
  box-shadow:
    inset 0 0 0 1px rgba(201, 153, 47, .42),
    inset 0 -22px 34px -26px rgba(10, 23, 48, .26),
    var(--e-3);
}

/* --- the lead's gold rule, present at rest ---------------------------------
   Was scaleX(0): invisible until hovered, which is the one state the section
   is least often in. A short stub at rest marks the lead permanently and
   still extends the full width on approach — same element, same mechanism,
   one changed value. The hover rules authored above are more specific and
   still win, so the extension is untouched. */
.ps--lead .ps-plate::after { transform: scaleX(.16); }

/* --- the ledger numeral ----------------------------------------------------
   The same device the treatment suite uses: a large Fraunces numeral, ghosted
   into the ground, that surfaces and turns gold on approach. Set from a CSS
   counter so no element is added to the markup.

   Anchored to .ps (already position: relative) at the bottom trailing corner,
   where the foot line — short, left-aligned — leaves the space empty, so it
   can never collide with type. z-index: -1 keeps it behind the text as a
   watermark; .stories-arc already isolates, so it cannot fall behind the
   section's own ground. */
.pstories { counter-reset: psnum; }
.ps { counter-increment: psnum; }
.ps::before {
  content: counter(psnum, decimal-leading-zero);
  position: absolute;
  inset-block-end: -.35rem;
  inset-inline-end: 0;
  z-index: -1;
  font-family: var(--font-display);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
  color: var(--navy-900);
  opacity: .07;
  pointer-events: none;
  transition: opacity var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
}
.ps--lead::before { font-size: 3.4rem; }
.ps--row::before  { font-size: 2.2rem; }
.ps:hover::before,
.ps:focus-within::before { opacity: .2; color: var(--gold); }

/* --- the two entries: a considered approach state --------------------------
   .steps--thread's device — the record shifts toward the reader rather than
   lifting into a card, which would put two more boxes next to the lead.

   The shift is applied to the entry's two children, not to .ps--row itself,
   and that is load-bearing rather than stylistic. Every .ps carries
   data-reveal, whose heroRevealRise animation ends on `transform: none` with
   animation-fill-mode: both — so it keeps applying that value for the life
   of the page, and a CSS animation outranks a normal declaration. A hover
   transform on .ps--row is therefore silently dead: measured as identity
   even while :focus-within was matching. The plate and the body carry no
   animation, so the same 4px on them behaves exactly as intended and needs
   no !important to win. */
.ps--row .ps-plate,
.ps--row .ps-body {
  transition: transform var(--dur-3) var(--ease-out),
              box-shadow var(--dur-3) var(--ease-out);
}
.ps--row:hover .ps-plate,
.ps--row:focus-within .ps-plate,
.ps--row:hover .ps-body,
.ps--row:focus-within .ps-body { transform: translateX(4px); }
[dir="rtl"] .ps--row:hover .ps-plate,
[dir="rtl"] .ps--row:focus-within .ps-plate,
[dir="rtl"] .ps--row:hover .ps-body,
[dir="rtl"] .ps--row:focus-within .ps-body { transform: translateX(-4px); }

/* --- the divider: a rule that fades, like every other rule here -------------
   The flat --line-2 border is kept in the box model (transparent) so the
   1px it occupies does not change, and the visible line is drawn as a
   gradient that picks up gold at the leading edge and falls away. */
.ps-side .ps--row { border-block-start-color: transparent; }
.ps-side .ps--row + .ps--row::after {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: 0;
  block-size: 1px;
  background: linear-gradient(90deg,
    rgba(201, 153, 47, .50) 0%,
    rgba(220, 227, 237, .95) 22%,
    rgba(220, 227, 237, 0) 92%);
  pointer-events: none;
}
[dir="rtl"] .ps-side .ps--row + .ps--row::after {
  background: linear-gradient(270deg,
    rgba(201, 153, 47, .50) 0%,
    rgba(220, 227, 237, .95) 22%,
    rgba(220, 227, 237, 0) 92%);
}

/* --- hierarchy: the lead reads first --------------------------------------
   Lead and entries previously shared one standfirst colour and one foot.
   The lead's standfirst steps up to --ink-2 (the token .lead itself uses)
   while the entries stay at --ink-3, and the lead's foot is ruled off as a
   record field exactly as .card-meta is. The entries' feet stay unruled, so
   the rule itself is part of what marks the lead. */
.ps--lead .ps-p { color: var(--ink-2); }
.ps--lead .ps-foot {
  padding-block-start: var(--sp-4);
  border-block-start: 1px solid var(--line-2);
}
.ps-foot { font-variant-numeric: tabular-nums; letter-spacing: .01em; }

/* --- responsive -------------------------------------------------------------
   NOT a redesign — a repair. .pstories had no media query at any width in
   either stylesheet, so the two-column grid held all the way down: measured
   at a 360px viewport the entries computed to `152px 0px`, i.e. the plate
   overflowed its own column and every entry's text collapsed to zero width.
   The 2026-08 homepage revision is recorded as desktop-only, and this is
   what that meant here.

   The structure is unchanged — same lead, same two entries, same order.
   Below 900px they stack into one column (the entries' text is unusably
   narrow before that: 127px at a 768px viewport), and below 560px the
   entry plate steps down so its text keeps a workable measure. */
@media (max-width: 900px) {
  .pstories {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-7);
  }
}

@media (max-width: 560px) {
  .ps--row {
    grid-template-columns: 5.5rem minmax(0, 1fr);
    gap: var(--sp-4);
  }
  .ps--row { padding-block: var(--sp-5); }
  /* The foot leaves too little clear space at this measure for the numeral
     to stay out of the type, so the entries drop it. The lead keeps its own. */
  .ps--row::before { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .ps-plate, .ps-body, .ps::before { transition: none; }
  .ps--row:hover .ps-plate,
  .ps--row:focus-within .ps-plate,
  .ps--row:hover .ps-body,
  .ps--row:focus-within .ps-body { transform: none; }
}

/* ===========================================================================
   v8 — "WHAT THE EXPERIENCE ACTUALLY FELT LIKE", RESTAGED AS AN EDITORIAL
   SPREAD

   Appended last. Every selector below is scoped to .quotes-editorial, a
   modifier added to this one section, so nothing here can reach any other
   section, any other page, or the published site.css. Deleting this block and
   the class returns the section to exactly what it was.

   WHAT IS NOT TOUCHED
   The animated portrait stack is the anchor of this section and none of it is
   edited here: .at-card, .at-shot, the [data-pos] transforms, @keyframes
   atRise / atUp / atWord, every duration, delay and easing, the entering
   class, and the testimonial block in home.js are all exactly as they were.
   The one
   property this block sets on .at-stage is an inline-size bound — the same
   job the grid column was already doing, moved so the single-column layout
   can also bound it. No transform, transition, keyframe or sequence changes.

   WHY THE SECTION NEEDED THIS
   Three things made it read as a testimonial card rather than as the page's
   strongest human moment:

     1. It was symmetrical. A centred eyebrow, a centred h2 and a balanced
        two-column block — the default section pattern used repeatedly above
        it. The hero earns its weight by being asymmetric; this inherited
        "generic section" staging instead.

     2. The hierarchy was upside down. The section's own title was the
        largest type (~40px) and the patient's sentence was third in line,
        behind the title and the name. The words are the reason the section
        exists, so the words are now the largest thing in it and the title
        steps back to a department head.

     3. The label came before the content. Name, country and treatment sat
        above the quote, which reads as a database record. Editorial runs the
        other way: the sentence, then who said it. The markup now does too,
        so the reading order is fixed for a screen reader as well.

   And one outright bug: .at had a single grid — 24rem for the stage, 1fr for
   the words — with no breakpoint anywhere. At 768px the text column was
   246px; at 375px it computed to 0px and the quote was clipped out of sight
   by the section's own overflow:hidden. The layout below is single-column
   first and only becomes a spread when there is room for one.
   --------------------------------------------------------------------------- */

/* --- the head stops being centred ----------------------------------------
   Left-set and narrow, so the eye starts at the same margin the quote below
   it starts at, and the section reads as one column of thought rather than
   as a banner over a box. */
.quotes-editorial .section-head {
  max-width: 32rem;
  margin-inline: 0;
  text-align: start;
}
.quotes-editorial .section-head h2 {
  font-size: clamp(1.3rem, 1.1rem + .85vw, 1.75rem);
  font-weight: 300;
  line-height: 1.22;
  letter-spacing: -0.005em;
}

/* --- the composition ------------------------------------------------------
   Single column is the base, not the fallback: it is what phones and small
   tablets get, and it is the layout that cannot crush the words. The spread
   arrives at 64rem, where there is room for a folio rail, a full-size stage
   and a real measure side by side. */
.quotes-editorial .at {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.75rem, 1.2rem + 1.6vw, 2.75rem);
  align-items: start;
  padding: 0;
}

/* The stage keeps its square and its perspective; this only stops it from
   growing to the full width of a tablet, which the grid column used to do. */
.quotes-editorial .at-stage { inline-size: min(100%, 26rem); }

/* --- the folio ------------------------------------------------------------
   The carousel counter, restyled. It was "1 — 3" in 13px uppercase at the
   foot of the panel, doing the job of a UI affordance. As a large numeral it
   does the same job and also numbers the account, which is the oldest
   editorial device there is. Horizontal here, vertical in the spread. */
.quotes-editorial .at-count {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: 0;
  font-size: inherit;
  letter-spacing: normal;
  text-transform: none;
}
.quotes-editorial .at-count-n {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 1.5rem + 1.5vw, 2.85rem);
  font-weight: 300;
  line-height: 1;
  color: var(--gold-lite);
  font-variant-numeric: tabular-nums;
}
.quotes-editorial .at-count-of {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--navy-200);
  font-variant-numeric: tabular-nums;
}
/* The leading zero is typography, not data. The element is aria-hidden and
   the component publishes plain 1..N, so this only dresses the numeral —
   and it stays correct for as long as the section has fewer than ten
   accounts, which is what the markup carries. */
.quotes-editorial .at-count-n::before,
.quotes-editorial .at-count-of::before { content: "0"; }

.quotes-editorial .at-count i {
  inline-size: 1.75rem;
  block-size: 1px;
  background: linear-gradient(90deg, rgba(212, 175, 55, .7), rgba(212, 175, 55, .12));
}

/* --- the record ----------------------------------------------------------
   The panel was a flex column with space-between and a 100% minimum height,
   which produced leftover space rather than composed space — a 438px panel
   holding 245px of quote with the buttons pinned to the floor. Plain flow,
   with the spacing stated. */
.quotes-editorial .at-panel {
  display: block;
  min-block-size: 0;
}
.quotes-editorial .at-quote { margin-block-start: 0; }

/* The words. Now the largest type in the section — ahead of the h2, which is
   the whole point of the restage. The measure is held at 28ch so the line
   count stays editorial as the type grows. */
.quotes-editorial .at-text,
.quotes-editorial .at-anim {
  font-size: clamp(1.45rem, 1.12rem + 1.15vw, 2rem);
  line-height: 1.36;
  letter-spacing: -0.012em;
  max-inline-size: 34ch;
  color: #F3F7FE;
}

/* The mark hangs further out of the measure and drops in contrast — a
   watermark behind the opening words rather than a glyph beside them. */
.quotes-editorial .at-mark {
  inline-size: 5.5rem;
  block-size: 5.5rem;
  inset-block-start: -1.7rem;
  inset-inline-start: -0.75rem;
  color: rgba(212, 175, 55, .09);
}

/* --- the credit ----------------------------------------------------------
   Below the words now, under a gold hairline that fades out before it
   reaches the end of the measure — the same fading-rule device the plate's
   top edge and the stories route line already use.

   The name drops from 25px display serif to letterspaced micro-caps. It was
   competing with the quote for the same job; as metadata it frames the quote
   instead. */
.quotes-editorial .at-id {
  position: relative;
  gap: var(--sp-2);
  margin-block-start: clamp(1.5rem, 1.1rem + 1.15vw, 2.25rem);
  padding-block-start: clamp(1rem, .8rem + .7vw, 1.5rem);
  max-inline-size: 28ch;
}
.quotes-editorial .at-id::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: min(100%, 15rem);
  block-size: 1px;
  background: linear-gradient(90deg, rgba(212, 175, 55, .5), rgba(212, 175, 55, 0));
}
.quotes-editorial .at-name {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #EAF0FA;
}
.quotes-editorial .at-where {
  font-size: var(--fs-sm);
  letter-spacing: .005em;
  color: var(--navy-200);
}

/* --- navigation ----------------------------------------------------------
   The buttons keep their existing treatment, including the canted arrows on
   hover. Only their seat changes: they sit under the credit now that the
   counter no longer shares the row. */
.quotes-editorial .at-nav {
  margin-block-start: clamp(1.5rem, 1.1rem + 1.15vw, 2.25rem);
}

/* --- the spread -----------------------------------------------------------
   Three columns: folio, stage, words. The folio is pinned to the top of the
   composition and the words are optically centred against the portrait, so
   the block has a top-left anchor and a settled middle rather than three
   things all starting on the same line.

   68rem, not 64. At 1024px the spread does technically fit, but it hands the
   words a 408px column next to a 400px portrait — the quote stops reading as
   the lead and the two columns just look like a tie. One notch wider the
   measure clears 480px and the composition works. Below that the single
   column gives the quote 620px, which is the better layout anyway. */
@media (min-width: 68rem) {
  .quotes-editorial .at {
    grid-template-columns: 4rem minmax(0, 25rem) minmax(0, 1fr);
    gap: clamp(2rem, .5rem + 2.3vw, 3.25rem);
  }
  .quotes-editorial .at-stage { inline-size: 100%; }

  .quotes-editorial .at-count {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-3);
    align-self: start;
    padding-block-start: .35rem;
  }
  .quotes-editorial .at-panel { align-self: center; }

  .quotes-editorial .at-mark {
    inline-size: 7rem;
    block-size: 7rem;
    inset-block-start: -2.2rem;
    inset-inline-start: -1.9rem;
  }
}

/* --- before the script runs -----------------------------------------------
   The existing floor still applies: three portraits in a row, all three
   accounts in flow, no navigation. Two corrections for the new layout — the
   stage is no longer bounded to 26rem when it is holding three portraits
   side by side, and the folio numeral is meaningless when every account is
   already on screen.

   The grid has to be restated with them. Hiding the folio takes it out of
   grid placement altogether, which slides the stage into the 4rem rail the
   folio was occupying and the three portraits collapse into a 64px strip.
   The floor is a stack, so it says so explicitly rather than relying on
   auto-placement to land on the right columns. */
.quotes-editorial .at:not(.is-ready) {
  grid-template-columns: minmax(0, 1fr);
}
.quotes-editorial .at:not(.is-ready) .at-stage {
  inline-size: 100%;
  max-inline-size: none;
}
.quotes-editorial .at:not(.is-ready) .at-count { display: none; }

/* ===========================================================================
   v9 — PATIENT STORIES, REBUILT AS A REGISTER OF JOURNEYS

   Appended last, all-new selectors under .storyreg / .jr. The v8 .ps-* and
   the older .reg-* rules above no longer match any element and are inert;
   they are left in place under this file's existing convention so the three
   directions can be compared, and are stripped on approval.

   THE PROBLEM THIS SOLVES
   v8 was an article listing. tag -> headline -> standfirst -> date -> read
   time is the CMS teaser schema, and ruling it, numbering it and lifting it
   on hover decorated that schema instead of replacing it. Two measurements
   make the case: the grid ran 545px against 505px, so the "lead" led by 8%;
   and the entries cropped a 640x400 composition into a 152px square. The
   section's own headline — "People who came to India and went home" — was
   promising a journey while the layout delivered a blog index.

   THE COMPOSITION
   One meridian, three departures. A single gold hairline descends the whole
   register with a node at each record, so the stories read as one continuous
   thing rather than as three cards sitting near each other. That line is not
   ornament: it is the section's argument, and each node is a person who
   travelled. Every record opens with its real route — Lagos, Amman, Almaty,
   all three to India — which is the fact the previous pass buried on another
   page while showing publication dates instead.

   Hierarchy is built rather than asserted. The lead opens the register with
   its plate on the meridian edge at roughly 1.1x the body column, so the
   picture is the first mass the eye lands on; the two entries invert to
   text-first with a compact plate on the trailing edge, at a little over a
   third of the lead's width. Nothing needs a badge to say which one leads.

   WHY IT CANNOT BE CONFUSED WITH THE EXPERIENCE SECTION ABOVE
   That section is navy, one person at a time, a photographed face and a
   first-person quote. This one is the page's own ivory, all three at once,
   abstract speciality plates and third-person reporting. It also carries no
   numerals: the folio device belongs to the experience section, and the
   meridian belongs to this one, so the two never echo each other.

   BORROWED, NOT INVENTED
   The fading gold hairline, the navy plate ground, --e-2 elevation, the
   headline underline that draws on approach, tabular figures in the foot,
   letterspaced micro-caps for metadata and the 4pt spacing scale are all
   already in this design system. No new colour, radius, easing or family.
   --------------------------------------------------------------------------- */

/* --- the register ---------------------------------------------------------
   --rail is declared once and used three times: it insets the records, it
   places the meridian, and it positions the nodes. Keeping it a single token
   is what stops the line and the dots drifting apart at any width. */
.storyreg {
  --rail: clamp(1.25rem, .75rem + 1.6vw, 2.5rem);
  position: relative;
  display: grid;
  gap: clamp(2.75rem, 1.9rem + 2.6vw, 4.75rem);
  padding-inline-start: var(--rail);
}

/* The meridian. Full strength where the register begins, falling away
   through the last record so it resolves into the section instead of
   stopping at an edge — the same behaviour every other rule in this design
   has. inset-inline-start keeps it on the correct side under RTL. */
.storyreg::before {
  content: "";
  position: absolute;
  inset-block: .5rem 0;
  inset-inline-start: 0;
  inline-size: 1px;
  background: linear-gradient(180deg,
    rgba(201, 153, 47, 0) 0,
    rgba(201, 153, 47, .55) 1.5rem,
    rgba(201, 153, 47, .30) 58%,
    rgba(201, 153, 47, 0) 100%);
  pointer-events: none;
}

/* --- a record ------------------------------------------------------------- */
.jr {
  position: relative;   /* also the containing block for .card-stretch */
  display: grid;
  gap: clamp(1.25rem, .9rem + 1.3vw, 2.25rem);
}

/* The node. Centred on the meridian by pulling back the rail plus half its
   own width; both are logical offsets, so RTL mirrors without a second rule.
   Painted with the page ground so the hairline appears to pass behind it. */
.jr::before {
  content: "";
  position: absolute;
  inset-block-start: .34rem;
  inset-inline-start: calc(-1 * var(--rail) - 3px);
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--ivory);
  box-shadow: 0 0 0 1px rgba(201, 153, 47, .55);
  transition: box-shadow var(--dur-3) var(--ease-out), background-color var(--dur-3) var(--ease-out);
}
/* The lead's departure is the one that is already marked. */
.jr--lead::before {
  background: var(--gold-lite);
  box-shadow: 0 0 0 1px rgba(201, 153, 47, .55), 0 0 0 4px rgba(201, 153, 47, .13);
}
.jr:hover::before,
.jr:focus-within::before {
  background: var(--gold-lite);
  box-shadow: 0 0 0 1px rgba(201, 153, 47, .7), 0 0 0 4px rgba(201, 153, 47, .15);
}

/* --- the route ------------------------------------------------------------
   The line that used to be a tag pill. Origin, a drawn run, destination, then
   the speciality — one metadata line that states the journey instead of
   labelling a category. Micro-caps because this is a reference field, not
   prose; the display face is kept for the headline, where it does real work. */
.jr-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
  line-height: 1;
}
.jr-from { color: var(--navy-700); }
.jr-to   { color: var(--ink-3); }

/* The run between the two cities: a hairline that gains weight toward the
   destination, so the route reads directionally without an arrow glyph. */
.jr-run {
  inline-size: clamp(1.5rem, 1rem + 1.6vw, 3rem);
  block-size: 1px;
  flex: none;
  background: linear-gradient(90deg, rgba(201, 153, 47, .25), rgba(201, 153, 47, .85));
  transition: inline-size var(--dur-4) var(--ease-soft);
}
[dir="rtl"] .jr-run {
  background: linear-gradient(270deg, rgba(201, 153, 47, .25), rgba(201, 153, 47, .85));
}
.jr:hover .jr-run,
.jr:focus-within .jr-run { inline-size: clamp(2.25rem, 1.5rem + 2.4vw, 4.25rem); }

.jr-sep {
  inline-size: 3px; block-size: 3px; border-radius: 50%; flex: none;
  background: var(--line);
}
.jr-spec { color: var(--ink-3); }

/* --- the plate ------------------------------------------------------------
   These assets are not photographs — they are abstract navy speciality
   compositions drawn at 640x400. v8 cropped them to squares, which cut the
   composition in half. Held near their native ratio they become the section's
   visual mass: three dark blocks on the page's own ivory. One hairline, one
   step of the system's elevation, no inset shadow trying to make a drawing
   look like a photograph. */
.jr-plate {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--navy-900);
  /* The edge has to hold for all three assets, and they do not share a
     ground: cardiac runs navy-700 to navy-950, onco navy-100 to navy-700,
     but ortho is gold-soft to navy-100 — a light plate whose lower half is
     within a few steps of the ivory it sits on. At .12 the hairline let that
     one dissolve into the section and the record read as missing its
     picture. .2 is still a hairline on the dark plates and is what keeps the
     light one a plate. */
  box-shadow: 0 0 0 1px rgba(26, 49, 96, .20), var(--e-2);
  transition: box-shadow var(--dur-3) var(--ease-out);
}
.jr-plate img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-4) var(--ease-soft);
}
.jr:hover .jr-plate,
.jr:focus-within .jr-plate {
  box-shadow: 0 0 0 1px rgba(201, 153, 47, .40), var(--e-3);
}
.jr:hover .jr-plate img,
.jr:focus-within .jr-plate img { transform: scale(1.035); }

/* --- the words ------------------------------------------------------------ */
.jr-body { display: grid; gap: var(--sp-4); align-content: start; }

.jr-h { margin: 0; line-height: 1.18; letter-spacing: -0.01em; }
.jr-h a {
  color: var(--ink);
  text-decoration: none;
  background-image: linear-gradient(var(--gold-lite), var(--gold-lite));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size var(--dur-3) var(--ease-out);
}
[dir="rtl"] .jr-h a { background-position: 100% 100%; }
.jr:hover .jr-h a,
.jr:focus-within .jr-h a { background-size: 100% 1px; }

.jr-p { margin: 0; color: var(--ink-3); }

.jr-foot {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
}

/* --- the lead -------------------------------------------------------------
   Picture first, on the meridian edge, at a size where the drawing is a
   picture rather than a thumbnail. */
.jr--lead .jr-h { font-size: clamp(1.5rem, 1.15rem + 1.25vw, 2.15rem); }
.jr--lead .jr-p {
  font-size: var(--fs-lead);
  color: var(--ink-2);
  max-inline-size: 42ch;
}

/* --- the two entries ------------------------------------------------------
   Text first, plate trailing and compact. The inversion is what carries the
   hierarchy: no rule, badge or numeral is needed to say which record leads. */
.jr--entry .jr-h { font-size: clamp(1.15rem, 1.02rem + .5vw, 1.5rem); }
.jr--entry .jr-p { font-size: var(--fs-sm); max-inline-size: 56ch; }

/* --- the spread -----------------------------------------------------------
   Below this the register is a single column, which is the right shape for a
   vertical meridian and is why this design does not have to be shrunk to
   reach a phone. */
@media (min-width: 62rem) {
  .jr--lead {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    grid-template-areas:
      "meta  meta"
      "plate body";
    align-items: start;
    column-gap: clamp(1.75rem, .8rem + 2.4vw, 3.25rem);
  }
  /* The entries run on the lead's own column proportion, inverted. Giving the
     plate a whole column and then bounding it inside that column is what
     produces the air between the words and the picture: the standfirst stops
     at a readable measure instead of stretching to the section edge, and the
     plate lands flush with the right margin the lead's body already sets, so
     the three records share one vertical edge. */
  .jr--entry {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    grid-template-areas:
      "meta meta"
      "body plate";
    align-items: start;
    column-gap: clamp(1.75rem, .8rem + 2.4vw, 3.25rem);
  }
  .jr--entry .jr-plate {
    max-inline-size: 15.5rem;
    justify-self: end;
  }
  .jr-meta  { grid-area: meta; }
  .jr-plate { grid-area: plate; }
  .jr-body  { grid-area: body; }

  /* The entry plate is small enough that 16:10 would read as a strip, so it
     takes the squarer crop the composition also survives. */
  .jr--entry .jr-plate { aspect-ratio: 4 / 3; }

  /* The lead's body is optically dropped to the plate's first third rather
     than its top edge, so the headline sits against the picture instead of
     racing it. */
  .jr--lead .jr-body { padding-block-start: var(--sp-2); }
}

/* --- narrow ---------------------------------------------------------------
   Not the spread shrunk. Below 62rem the lead keeps its shape — picture, then
   words — because that is what a lead is, and it is the one record that earns
   a full-width plate on a phone.

   The entries change shape instead. Stacking them the same way was measured
   at 768px as a 352px plate sitting in a 669px column with 317px of dead
   space beside it, and it pushed the section to 2086px — a third of which was
   holding nothing. As a compact row the picture and the words occupy the same
   band, the empty area disappears, and the entries read as register lines
   under the lead rather than as three more leads. The square crop is the one
   these compositions survive at this size. */
@media (max-width: 61.99rem) {
  /* The lead needs its areas named here too. The three children are assigned
     to named areas below, and an item sent to an area its own grid does not
     define is placed implicitly instead — measured at 768px as the lead's
     plate and body landing in the same cell, on top of each other. Stating
     the single-column template is what keeps that from happening. */
  .jr--lead {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "meta"
      "plate"
      "body";
  }
  /* Entries stack like the lead, so every record carries the same picture.
     This replaces an earlier two-column register line whose plate was
     clamp(4.5rem, 2.2rem + 11vw, 11rem) wide. That treatment was deliberate --
     it protected the headline's measure -- but it had two costs that only show
     on a phone:

       1. The lead's plate rendered 315x177 at 375px while the entries'
          rendered 76x43. Scrolling the register, the three records did not
          read as the same kind of thing.
       2. .jr-play is a fixed 48px disc anchored to the plate's bottom-right.
          In a 76x43 plate a 48px disc is larger than the plate is tall, so it
          overflowed its own frame and covered most of the picture.

     Stacking fixes both at once and costs nothing the lead was not already
     paying: the headline gets the full column rather than 229px of it. */
  .jr--entry {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "meta"
      "plate"
      "body";
    align-items: start;
  }
  .jr-meta  { grid-area: meta; }
  .jr-plate { grid-area: plate; }
  .jr-body  { grid-area: body; }

  .jr--entry .jr-plate { aspect-ratio: 1; }
  .jr--entry .jr-body  { gap: var(--sp-3); }
}

@media (prefers-reduced-motion: reduce) {
  .jr-plate,
  .jr-plate img,
  .jr-h a,
  .jr-run,
  .jr::before { transition: none; }
  .jr:hover .jr-plate img,
  .jr:focus-within .jr-plate img { transform: none; }
  .jr:hover .jr-run,
  .jr:focus-within .jr-run { inline-size: clamp(1.5rem, 1rem + 1.6vw, 3rem); }
}

/* --- the record is the click target ---------------------------------------
   .card-stretch::after is `position:absolute; inset:0`, so it fills the
   nearest positioned ancestor. The markup carried `class="card-stretch rel"`
   and .rel is `position:relative` — on the anchor itself, which meant the
   overlay was contained by the headline and stretched over nothing but its
   own text. Measured: elementFromPoint over the lead's picture returned the
   IMG, not the link.

   Dropping .rel lets it resolve against .jr instead, which is already
   positioned for the node. The whole record — plate included — becomes the
   link, which is what a section built around a large picture needs. The
   class was only ever used by these three records, here and in production,
   so nothing else changes behaviour.

   Stated here rather than left implicit: .jr must stay position:relative or
   the overlay escapes to the section. */
.jr > .card-stretch::after { border-radius: var(--r-md); }

/* ===========================================================================
   v10 — FIVE ACCOUNTS, AN ATMOSPHERIC GROUND, AND DEPTH ON THE STORIES

   Appended last. Everything here is either a new selector or a later rule on
   an existing one; no rule above is edited.
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   1 — TWO MORE POSITIONS IN THE STACK

   The approved animation defines the fan for three cards: data-pos 0, 1 and 2.
   With five accounts the two deepest cards matched no rule at all, so they sat
   untransformed at full size and opacity on top of the front portrait. These
   two rules continue the existing progression rather than restating it — the
   same alternating fan, the same easing, the same transition, each step
   further back, smaller, dimmer and less saturated on exactly the curve the
   first three already follow. Nothing about positions 0-2 changes, and no
   timing, transform or keyframe of the approved component is touched.

   z-index stays at 0 for both: .at-stage is transform-style: preserve-3d, so
   two cards on the same layer sort by their actual Z, and -246 / -310 already
   put them in the right order behind position 2.
   --------------------------------------------------------------------------- */
.at.is-ready .at-card[data-pos="3"] {
  transform: translate3d(4.5%, 3.4%, -246px) rotate(3.4deg) scale(.845);
  opacity: .20;
  z-index: 0;
}
.at.is-ready .at-card[data-pos="3"] .at-shot { filter: saturate(.5) brightness(.52); }

.at.is-ready .at-card[data-pos="4"] {
  transform: translate3d(-4%, 4.2%, -310px) rotate(-2.6deg) scale(.81);
  opacity: .12;
  z-index: 0;
}
.at.is-ready .at-card[data-pos="4"] .at-shot { filter: saturate(.42) brightness(.44); }

/* The two supplied portraits are 1122x1402 — taller than the 5:4 the first
   three were shot at. The stage crop is square, so they need their own
   focal point or the square takes the chin and not the face. */
.at-card[data-at="3"] .at-shot img,
.at-card[data-at="4"] .at-shot img { object-position: 50% 26%; }

/* Neither new profile was supplied with a country or a treatment, so those
   records carry a name and nothing else. The credit rule and its spacing are
   unchanged; there is simply one line under it instead of two. */
.at-record--plain .at-id { gap: 0; }

/* ---------------------------------------------------------------------------
   2 — THE GROUND

   The section was a flat vertical gradient with one bloom on it. It read as a
   coloured block behind a photograph rather than as a space the photograph is
   standing in.

   Three layers now do the work, and each has a job:
     ::before  the gradient, deepened, plus two wide colour fields set at
               different scales — the far wall.
     .at::before  a genuinely blurred mass sitting directly behind the
               portrait stack — the mid-ground, and the only element here
               carrying a real filter: blur(). This is what produces
               depth-of-field rather than a suggestion of it.
     ::after   a vignette that closes the corners, and the hero's own film
               grain at low opacity — the near field, and the thing that ties
               this section to the top of the page.

   All of it is behind z-index 0 and none of it sits between the reader and
   the words. Measured contrast on the quote is unchanged.
   --------------------------------------------------------------------------- */
.quotes-editorial::before {
  background:
    /* two wide fields, offset from each other, so the ground has more than
       one distance in it */
    radial-gradient(120% 62% at 18% 28%, rgba(36, 65, 122, .38), transparent 62%),
    radial-gradient(90% 54% at 86% 74%, rgba(16, 40, 84, .42), transparent 66%),
    linear-gradient(180deg,
      var(--ivory) 0%,
      var(--navy-900) 16%,
      #0E1F3D 42%,
      var(--navy-800) 62%,
      var(--navy-900) 86%,
      var(--ivory) 100%);
}

/* The mid-ground. .quotes-anim had switched this pseudo-element off with
   content:none; it is brought back for the one job a background layer cannot
   do from the section level — being blurred, and being anchored to the
   portrait rather than to the viewport. */
.quotes-editorial .at::before {
  content: "";
  position: absolute;
  inset-block-start: 46%;
  inset-inline-start: 26%;
  inline-size: min(46rem, 78%);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background:
    radial-gradient(circle,
      rgba(58, 93, 160, .40) 0%,
      rgba(40, 70, 130, .20) 46%,
      transparent 70%);
  filter: blur(46px);
  opacity: .9;
  z-index: -1;
  pointer-events: none;
}

/* The near field. */
.quotes-editorial::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  inline-size: auto;
  block-size: auto;
  translate: none;
  background-image:
    /* Grain, at 5% inside the SVG itself. The hero carries this same
       turbulence at opacity .045 on a layer of its own; here it has to share
       a layer with the vignette, and a background-image cannot be given its
       own alpha. Carried at full strength under an overlay blend it did not
       read as grain at all — it lifted the whole section off navy and onto a
       flat concrete grey, which is the opposite of the depth this is for.
       Encoding the alpha into the rect keeps it a texture. */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.05'/%3E%3C/svg%3E"),
    /* vignette — corners recede, centre stays open where the words are */
    radial-gradient(128% 92% at 50% 46%, transparent 42%, rgba(3, 8, 20, .52) 100%);
  background-repeat: repeat, no-repeat;
  opacity: 1;
}

/* ---------------------------------------------------------------------------
   3 — THE REVIEW IS THE CONTROL

   Five accounts need to announce themselves as five. The folio already reads
   01/05, and the two arrows already work; what was missing was that the
   review itself is the obvious thing to click. The panel takes the pointer
   and a hairline hint, and the testimonial block in home.js advances on a
   click that is
   not a drag, a selection or an existing control.
   --------------------------------------------------------------------------- */
.quotes-editorial .at-panel { cursor: pointer; }
.quotes-editorial .at-panel:hover .at-anim,
.quotes-editorial .at-panel:focus-within .at-anim { color: #FFFFFF; }

.quotes-editorial .at-hint {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-block-start: var(--sp-4);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--navy-200);
  opacity: .72;
  transition: opacity var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
}
.quotes-editorial .at-panel:hover .at-hint { opacity: 1; color: var(--gold-lite); }
.quotes-editorial .at-hint i {
  inline-size: 1.5rem; block-size: 1px;
  background: linear-gradient(90deg, rgba(212,175,55,.7), rgba(212,175,55,.1));
}
[dir="rtl"] .quotes-editorial .at-hint i {
  background: linear-gradient(270deg, rgba(212,175,55,.7), rgba(212,175,55,.1));
}

/* ---------------------------------------------------------------------------
   4 — THE SOUND CONTROL

   Built by the audio block in home.js and parked in the hero's lower trailing
   corner,
   clear of the headline, the CTA row and the Concierge float. It is the only
   thing on the page that says sound exists, so it stays visible for the whole
   session rather than disappearing once used.
   --------------------------------------------------------------------------- */
.aud {
  position: fixed;
  inset-block-end: clamp(1.25rem, .8rem + 1.6vw, 2.25rem);
  inset-inline-start: clamp(1.25rem, .6rem + 2.6vw, 2.5rem);
  z-index: var(--z-sticky);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: .55rem 1.1rem .55rem .85rem;
  border-radius: var(--r-pill);
  border: 1px solid rgba(212, 175, 55, .34);
  background: rgba(6, 13, 28, .42);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: var(--on-dark);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease-out),
              background-color var(--dur-2) var(--ease-out),
              color var(--dur-2) var(--ease-out);
}
.aud:hover, .aud:focus-visible {
  border-color: rgba(212, 175, 55, .75);
  background: rgba(6, 13, 28, .62);
  color: #F0D68A;
}

/* Three bars. At rest they sit still at different heights — a mark, not an
   animation. Once sound is on they breathe, which is the only moving thing
   in the hero that is not the film itself. */
.aud-ico { display: inline-flex; align-items: flex-end; gap: 2px; block-size: 14px; }
.aud-wave {
  inline-size: 2px;
  background: var(--gold-lite);
  border-radius: 1px;
  block-size: 5px;
  transition: block-size var(--dur-3) var(--ease-out);
}
.aud-wave:nth-child(2) { block-size: 9px; }
.aud-wave:nth-child(3) { block-size: 6px; }

@keyframes audWave {
  0%, 100% { block-size: 4px; }
  50%      { block-size: 13px; }
}
.aud.is-on .aud-wave { animation: audWave 1500ms var(--ease-soft) infinite; }
.aud.is-on .aud-wave:nth-child(2) { animation-duration: 1100ms; animation-delay: 140ms; }
.aud.is-on .aud-wave:nth-child(3) { animation-duration: 1750ms; animation-delay: 300ms; }

@media (prefers-reduced-motion: reduce) {
  .aud.is-on .aud-wave { animation: none; }
}

/* ---------------------------------------------------------------------------
   5 — DEPTH ON THE PATIENT STORIES

   The register already had a hover: the plate's ring warmed and its picture
   scaled 1.035. What it did not have was hierarchy under the cursor — three
   records all holding the same weight while one is being read.

   The lift is applied to .jr-plate and .jr-body, never to .jr. Every record
   carries data-reveal, and heroRevealRise ends on `transform: none` with
   animation-fill-mode: both, so it keeps asserting that value for the life of
   the page — a CSS animation outranks a normal declaration, and a transform
   on .jr itself is silently dead. Same reason the opacity of the records not
   under the cursor is stepped on the children rather than on the record.

   The rotateX is one degree. At 1200px of perspective that is enough to read
   as the card tipping toward the reader and not enough to notice as an
   effect, which is the whole brief: the story rises, it does not perform.
   --------------------------------------------------------------------------- */
.storyreg { perspective: 1200px; }

.jr-plate,
.jr-body,
.jr-meta {
  transition: transform var(--dur-4) var(--ease-soft),
              opacity var(--dur-3) var(--ease-out),
              box-shadow var(--dur-3) var(--ease-out);
  transform-style: preserve-3d;
}

.jr:hover .jr-plate,
.jr:focus-within .jr-plate {
  transform: translate3d(0, -9px, 26px) rotateX(1deg);
  box-shadow:
    0 0 0 1px rgba(201, 153, 47, .46),
    0 26px 50px -22px rgba(6, 16, 36, .46),
    var(--e-3);
}
.jr:hover .jr-body,
.jr:focus-within .jr-body { transform: translate3d(0, -5px, 12px); }
.jr:hover .jr-meta,
.jr:focus-within .jr-meta { transform: translate3d(0, -3px, 6px); }

/* The others step back. .55 is far enough to be felt as focus and near
   enough that nothing reads as disabled. */
.storyreg:hover .jr:not(:hover) .jr-plate,
.storyreg:hover .jr:not(:hover) .jr-body,
.storyreg:hover .jr:not(:hover) .jr-meta { opacity: .55; }

/* The node on the meridian follows the focus, so the line stays part of the
   interaction rather than sitting behind it. */
.storyreg:hover .jr:not(:hover)::before { opacity: .45; }

@media (prefers-reduced-motion: reduce) {
  .jr-plate, .jr-body, .jr-meta { transition: opacity var(--dur-3) var(--ease-out); }
  .jr:hover .jr-plate,
  .jr:focus-within .jr-plate,
  .jr:hover .jr-body,
  .jr:focus-within .jr-body,
  .jr:hover .jr-meta,
  .jr:focus-within .jr-meta { transform: none; }
}

/* ===========================================================================
   v11 — THE TESTIMONIAL SCENE

   Replaces the v10 ground. v10 built depth out of colour: a deepened
   gradient, two offset fields and one blurred navy mass. It was deeper than
   the flat block before it and still had the same basic problem — the
   portrait sat on a surface rather than in a space, because nothing in the
   background had anything to do with the person on screen.

   This does. The section is lit by a heavily blurred, darkened copy of the
   portrait belonging to the account being read. The colour behind the words
   is the colour of that person's own photograph, thrown far out of focus,
   and it changes as the accounts change. That is what a long lens does to a
   background, and it is why the portrait now reads as standing in the scene
   instead of being pasted over one.

   Five rules, no script. .at-card[data-pos="0"] is state the approved
   component already publishes; :has() reads it from the section. The backdrop
   therefore cannot drift out of step with the portrait, because it is driven
   by the same attribute the portrait is.

   READABILITY IS NOT NEGOTIABLE HERE
   The blurred layer is masked away at the top and bottom so the section still
   resolves into the page's ivory at both seams, and a navy scrim is laid over
   it, weighted to the side the quote sits on. Measured by compositing this
   exact layer stack onto a canvas and sampling 48 points across the quote's
   own box, against the brightest of the five scenes: the quote holds a
   minimum of 15.47:1 and the metadata line 9.54:1. The brightest background
   pixel anywhere under the type is rgb(23,30,47).
   --------------------------------------------------------------------------- */

/* The far wall keeps its gradient — this is what joins the section to the
   ivory above and below it — but loses v10's two colour fields, which the
   scene layer now does better and with meaning. */
.quotes-editorial::before {
  background: linear-gradient(180deg,
    var(--ivory) 0%,
    var(--navy-900) 16%,
    #0B1B36 44%,
    #0C1E3C 66%,
    var(--navy-900) 86%,
    var(--ivory) 100%);
}

/* v10's separate blurred mass is switched off: with the scene behind it, a
   second unexplained glow is exactly the visual noise the brief rules out. */
.quotes-editorial .at::before { content: none; }

.quotes-editorial .at-amb {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  /* Fades out before either seam so the ivory hand-off is untouched. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 20%, #000 80%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 20%, #000 80%, transparent 100%);
}

/* Inset past the edges so the blur has material to work with and never
   shows a soft border where the layer stops. */
.quotes-editorial .at-amb-i {
  position: absolute;
  inset: -14%;
  display: block;
  background-size: cover;
  background-position: 50% 28%;
  filter: blur(76px) saturate(.62) brightness(.46);
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 1100ms var(--ease-soft);
  will-change: opacity;
}

/* The one belonging to the account on screen. */
/* The v11 :has() block that used to live here is gone. It selected the same
   thing as the .is-live rule further down but at higher specificity, so the
   stale selector would have won and lit the wrong scene — the very fault
   .is-live was introduced to remove. One rule, one mechanism. */

/* Before the script runs there is no data-pos at all, so the first account
   lights the scene rather than leaving it black. */
/* Before the scripts run nothing is lit, which is the correct floor: the
   stack is not yet a stack and no account is active. */

/* The scrim. Deepest on the trailing side, where the quote is, and open in
   the middle where the portrait stands — so the blur reads as light in the
   room rather than as a wash over the type. */
.quotes-editorial .at-amb::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg,
      rgba(8, 20, 42, .30) 0%,
      rgba(8, 20, 42, .10) 26%,
      rgba(8, 20, 42, .58) 62%,
      rgba(8, 20, 42, .78) 100%),
    linear-gradient(180deg,
      rgba(10, 23, 48, .55) 0%,
      rgba(10, 23, 48, .12) 40%,
      rgba(10, 23, 48, .55) 100%);
}
[dir="rtl"] .quotes-editorial .at-amb::after {
  background:
    linear-gradient(270deg,
      rgba(8, 20, 42, .30) 0%,
      rgba(8, 20, 42, .10) 26%,
      rgba(8, 20, 42, .58) 62%,
      rgba(8, 20, 42, .78) 100%),
    linear-gradient(180deg,
      rgba(10, 23, 48, .55) 0%,
      rgba(10, 23, 48, .12) 40%,
      rgba(10, 23, 48, .55) 100%);
}

/* The near field, unchanged in principle from v10 — vignette plus the hero's
   own grain at 5% — but lighter now, because the scene below it is already
   carrying the depth. */
.quotes-editorial::after {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.04'/%3E%3C/svg%3E"),
    radial-gradient(120% 88% at 50% 46%, transparent 46%, rgba(3, 8, 20, .48) 100%);
}

/* The portrait belongs to the scene now, so its frame stops being a card
   edge: the hard shadow goes, and what is left is a soft seat under it and a
   fine light catch along the top — the way an object sits in a room. */
.quotes-editorial .at-shot {
  box-shadow:
    0 40px 80px -32px rgba(2, 7, 18, .78),
    0 0 0 1px rgba(255, 255, 255, .07);
}

@media (prefers-reduced-motion: reduce) {
  .quotes-editorial .at-amb-i { transition: none; }
}

/* ===========================================================================
   v12 — THE TESTIMONIAL, RECOMPOSED

   Previous passes kept adjusting the ground under an unchanged arrangement:
   a gradient that faded to ivory at both ends, a square portrait plate, a
   quote beside it, a numeral counting 01/05. Each pass changed the paint.
   None of them changed what the section *is*, which is why it kept reading as
   a testimonial block with better lighting.

   Three structural changes, not a repaint:

   1. IT BECOMES A BAND, NOT A SECTION.
      The hero is the strongest thing on this homepage and it is a solid,
      full-bleed, hard-edged dark field. This section was the opposite — a
      soft wash dissolving into ivory at both seams, which is precisely what
      made it read as a panel inserted into a page rather than as a moment in
      a film. It now holds one deep field edge to edge with defined top and
      bottom, the same device, so the two dark moments on the page rhyme.

   2. THE PORTRAIT IS CROPPED BY THE FRAME.
      It was a square plate floating inside the composition with air on every
      side — the shape of a card. It is now tall, much larger, and runs off
      the bottom edge of the band. Something cropped by the frame reads as
      standing in a space; something with margin on all four sides reads as
      pasted onto one. The approved stack, its fan, its tilt, its lift and
      its per-word entry are all untouched: only the frame it plays inside
      changed.

   3. THE COUNT BECOMES FIVE FACES.
      01/05 asked the reader to decode a numeral. Five portraits, four dim
      and one lit, say the same thing without being read at all — and make
      the active reviewer unmistakable, which is the one thing the section
      was consistently failing to do.

   The quote keeps its place as the largest type in the band. Readability was
   the constraint the whole time and is measured again below.
   --------------------------------------------------------------------------- */

/* --- 1. the band ----------------------------------------------------------
   The ivory fade at both ends is gone. What replaces it is one field with a
   single low light source behind the portrait — the pool of light in a room,
   not a gradient across a rectangle. */
.quotes-editorial::before {
  background:
    radial-gradient(78% 92% at 30% 76%, rgba(38, 70, 132, .55), transparent 68%),
    radial-gradient(60% 70% at 82% 18%, rgba(20, 44, 92, .40), transparent 72%),
    linear-gradient(180deg, #060D1C 0%, #08132A 44%, #060D1C 100%);
}

/* Hard edges, top and bottom — the band's own two rules, the only gold in the
   section's chrome. They are what make it read as a deliberate frame rather
   than as a colour that happens to stop. */
.quotes-editorial {
  border-block: 1px solid rgba(201, 153, 47, .22);
}

/* The per-patient scene stays, but quieter: the field is doing the lighting
   now and two light sources would only muddy it. */
.quotes-editorial .at-amb-i { opacity: 0; filter: blur(90px) saturate(.55) brightness(.38); }
/* .is-live is set by the review-index block in home.js from the component's
   own data-pos.
   This was five :has() rules; they were measured going stale and lighting a
   different account from the one on screen. */
.quotes-editorial .at-amb-i.is-live { opacity: .34; }

.quotes-editorial .at-amb { mask-image: none; -webkit-mask-image: none; }
.quotes-editorial .at-amb::after {
  background: linear-gradient(90deg,
    rgba(6, 13, 28, .20) 0%, rgba(6, 13, 28, .05) 24%,
    rgba(6, 13, 28, .62) 58%, rgba(6, 13, 28, .86) 100%);
}
[dir="rtl"] .quotes-editorial .at-amb::after {
  background: linear-gradient(270deg,
    rgba(6, 13, 28, .20) 0%, rgba(6, 13, 28, .05) 24%,
    rgba(6, 13, 28, .62) 58%, rgba(6, 13, 28, .86) 100%);
}

/* Grain stays; the vignette goes. A band with hard rules does not need its
   corners darkened as well — that was there to disguise an edge that no
   longer exists. */
.quotes-editorial::after {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.045'/%3E%3C/svg%3E");
}

/* --- 2. the head ---------------------------------------------------------- */
.quotes-editorial .section-head { max-width: 40rem; margin-block-end: clamp(1.5rem, 1rem + 1.6vw, 2.75rem); }

/* --- 3. the portrait, cropped by the band --------------------------------
   The section stops clipping its own children so the stack can run past the
   bottom rule; .at-stage keeps every property the approved animation depends
   on — aspect ratio, perspective, transform-style — and only its size and
   seat change. */
.quotes-editorial { overflow: clip; }

@media (min-width: 68rem) {
  .quotes-editorial .at {
    grid-template-columns: 6.25rem minmax(0, 27rem) minmax(0, 1fr);
    column-gap: clamp(2rem, .5rem + 2.6vw, 3.75rem);
    align-items: end;
  }

  /* The band was carrying a void above the portrait: the stack is anchored to
     the bottom edge and the head sits at the top, so everything between them
     was empty. Pulling the section's own top padding in closes it without
     touching the composition — the air that is left now reads as chosen
     rather than left over. */
  .quotes-editorial { padding-block-start: clamp(2.5rem, 1.5rem + 3vw, 4.5rem); }

  /* Taller than wide, larger than before, and pushed down so its lower edge
     passes the band's bottom rule. The negative margin is the crop. */
  .quotes-editorial .at-stage {
    inline-size: 100%;
    aspect-ratio: 4 / 5;
    /* Enough of a crop to read as framed, not so much that the account's
       face is what gets cut. */
    margin-block-end: clamp(-5rem, -2.5rem - 3.4vw, -2rem);
    align-self: end;
  }

  .quotes-editorial .at-panel {
    align-self: center;
    padding-block-end: clamp(2rem, 1rem + 2.4vw, 4rem);
  }
}

/* The frame the portrait sits in: no card edge, a long soft shadow beneath
   it as if it were lit from above, and the gold hairline reserved for the
   one in front. */
.quotes-editorial .at-shot {
  border-radius: var(--r-md) var(--r-md) 0 0;
  box-shadow: 0 60px 90px -40px rgba(0, 0, 0, .85);
}

/* --- 4. the words --------------------------------------------------------- */
.quotes-editorial .at-text,
.quotes-editorial .at-anim {
  font-size: clamp(1.5rem, 1.1rem + 1.35vw, 2.3rem);
  line-height: 1.34;
  max-inline-size: 30ch;
  color: #F6F9FE;
}
.quotes-editorial .at-mark { color: rgba(201, 153, 47, .13); }

.quotes-editorial .at-name { color: #FFFFFF; letter-spacing: .2em; }
.quotes-editorial .at-where { color: #A9BCDC; }
.quotes-editorial .at-id::before {
  background: linear-gradient(90deg, rgba(201, 153, 47, .85), rgba(201, 153, 47, 0));
}

/* --- 5. the five faces ----------------------------------------------------
   A column, in the rail the numeral used to occupy. Dim and small at rest;
   the live one is full colour, larger, and carries the gold. */
.quotes-editorial .at-count { display: none; }

.at-faces {
  grid-column: 1;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  /* Seated on the portrait's own baseline rather than floating mid-rail, so
     the rail and the picture share a line instead of each starting somewhere
     of their own. */
  align-self: end;
  margin: 0;
  padding: 0;
  padding-block-end: clamp(1.5rem, 1rem + 2vw, 3.5rem);
}

.at-face {
  position: relative;
  inline-size: 3.75rem;
  block-size: 4.75rem;
  padding: 0;
  border: 0;
  border-radius: 3px;
  overflow: hidden;
  cursor: pointer;
  background: var(--navy-900);
  opacity: .42;
  filter: saturate(.35) brightness(.66);
  transform: scale(.92);
  transition:
    opacity var(--dur-3) var(--ease-out),
    filter var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-soft),
    box-shadow var(--dur-3) var(--ease-out);
}
.at-face img {
  inline-size: 100%; block-size: 100%;
  object-fit: cover; object-position: 50% 26%;
  display: block;
}
.at-face:hover,
.at-face:focus-visible { opacity: .8; filter: saturate(.7) brightness(.85); transform: scale(.98); }

/* Lit. Selected off the same attribute the portrait stack is driven by, so
   the index cannot show a different account from the one being read. */
.at-face.is-live {
  opacity: 1;
  filter: none;
  transform: scale(1);
  box-shadow: 0 0 0 1px rgba(201, 153, 47, .85), 0 10px 22px -10px rgba(0, 0, 0, .7);
  cursor: default;
}

/* --- 6. narrow ------------------------------------------------------------
   Not a mobile pass — only enough that the new composition does not break
   the existing structure below the spread. The faces become a row, the
   portrait stops bleeding, and the band keeps its rules. */
@media (max-width: 67.99rem) {
  .at-faces { flex-direction: row; align-self: start; }
  .at-face { inline-size: 2.75rem; block-size: 3.25rem; }
  .quotes-editorial .at-stage { margin-block-end: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .at-face { transition: opacity var(--dur-3) linear; }
}

/* ===========================================================================
   v13 — ONE OBJECT, ONE AXIS, ONE GROUNDLINE

   The v12 pass fixed the ground and broke the composition. Three faults, all
   of them real:

     · The portrait was bottom-anchored with a negative margin so it could
       bleed past the band, while the quote was centred in its own column.
       Two different vertical rules in one row is exactly why the picture read
       as sitting low and the text as sitting high. Nothing tied them.
     · The gold rules top and bottom drew a box around the section, which is
       the opposite of a section that should flow out of the estimator above
       and into the stories below.
     · The faces, the quote, the portrait and the arrows each began at a
       different edge, so the section was four things in a container rather
       than one designed object.

   What replaces it:

     ONE AXIS.       The portrait and the quote are both centred on the same
                     horizontal line. Not bottom-aligned, not independently
                     placed — align-items: center on a two-column grid, so
                     whichever is taller sets the row and the other centres
                     against it. The visual centre of the section is now a
                     property of the grid instead of a coincidence.

     ONE GROUNDLINE. A single hairline runs the full content width beneath
                     both columns, and the faces and the arrows stand on it.
                     It is the thing that makes image, review and navigation
                     one structure: they share a floor.

     ONE LEFT EDGE.  The eyebrow, the heading, the portrait and the faces all
                     start on the same margin. The quote and the arrows end
                     on the same right margin. Two edges, four elements, no
                     stray alignments.

   The borders are gone. The band still reads as its own moment because it is
   deep and the page around it is ivory — contrast and spacing do that work,
   which is what they are for.
   --------------------------------------------------------------------------- */

/* --- the field ------------------------------------------------------------
   No rules. A deep core with a long falloff at each end, so the section
   arrives and leaves rather than starting and stopping. */
.quotes-editorial { border-block: 0; }

.quotes-editorial::before {
  background:
    radial-gradient(72% 56% at 26% 52%, rgba(40, 74, 138, .50), transparent 70%),
    radial-gradient(56% 48% at 88% 20%, rgba(18, 42, 90, .38), transparent 74%),
    linear-gradient(180deg,
      var(--ivory) 0%,
      #0A1730 11%,
      #070F22 34%,
      #070F22 66%,
      #0A1730 89%,
      var(--ivory) 100%);
}

/* The per-patient scene stays inside the field's own falloff so it can never
   paint over the seams. */
.quotes-editorial .at-amb {
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 15%, #000 85%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 15%, #000 85%, transparent 100%);
}

/* --- the composition ------------------------------------------------------ */
@media (min-width: 68rem) {
  .quotes-editorial .at {
    /* The text column is sized to the measure it actually holds rather than
       to whatever is left over. A 1fr column left the quote finishing well
       short of its own right edge, which put a void between the words and
       the arrows and undid the alignment the foot was there to state.
       justify-content:start keeps the whole block on the left margin, so the
       panel and the foot still end on one line. */
    grid-template-columns: minmax(0, 23rem) minmax(0, 34rem);
    justify-content: start;
    grid-template-areas:
      "stage panel"
      "foot  foot";
    column-gap: clamp(2.5rem, 1rem + 3.4vw, 5rem);
    row-gap: clamp(2rem, 1.2rem + 2vw, 3.25rem);
    /* The one line that fixes the complaint: both columns centre on the same
       axis, so neither can drift high or low against the other. */
    align-items: center;
    padding: 0;
  }

  .quotes-editorial .at-stage {
    grid-area: stage;
    inline-size: 100%;
    aspect-ratio: 4 / 5;
    margin: 0;
    /* Explicit, because v12 bottom-anchored this to make the bleed work and
       an inherited align-self:end is exactly the "picture low, text high"
       fault being corrected here. */
    align-self: center;
  }
  .quotes-editorial .at-panel { grid-area: panel; align-self: center; }
  .at-foot { grid-area: foot; }
}

/* The portrait stops being a plate: square top corners are a card, and the
   only shadow it needs is the one that seats it. */
.quotes-editorial .at-shot {
  border-radius: var(--r-md);
  box-shadow: 0 44px 80px -38px rgba(0, 0, 0, .82);
}

/* --- the words ------------------------------------------------------------
   Set against the portrait rather than beside it: the measure is held short
   so the column has a shape, and the credit closes it on the same rule the
   foot uses, so the two horizontals rhyme. */
.quotes-editorial .at-text,
.quotes-editorial .at-anim {
  font-size: clamp(1.45rem, 1.05rem + 1.3vw, 2.15rem);
  line-height: 1.38;
  max-inline-size: 28ch;
}
.quotes-editorial .at-quote { margin-block-start: 0; }
.quotes-editorial .at-id { margin-block-start: clamp(1.5rem, 1.1rem + 1.2vw, 2.25rem); }

/* --- the groundline and the foot -----------------------------------------
   Everything below the line is navigation; everything above it is the
   account. One rule, full width, doing the whole job of separating them. */
.at-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
  padding-block-start: clamp(1.25rem, .9rem + 1.2vw, 2rem);
  border-block-start: 1px solid transparent;
  position: relative;
}
.at-foot::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 1px;
  background: linear-gradient(90deg,
    rgba(201, 153, 47, .55) 0%,
    rgba(182, 197, 224, .26) 42%,
    rgba(182, 197, 224, 0) 100%);
}
[dir="rtl"] .at-foot::before {
  background: linear-gradient(270deg,
    rgba(201, 153, 47, .55) 0%,
    rgba(182, 197, 224, .26) 42%,
    rgba(182, 197, 224, 0) 100%);
}

/* --- the five faces, now a row on the groundline -------------------------- */
.at-faces {
  display: flex;
  flex-direction: row;
  align-self: auto;
  gap: var(--sp-3);
  margin: 0;
  /* v12 seated this against the portrait's baseline; on the groundline it
     needs no offset of its own. */
  padding: 0;
}
.at-face {
  inline-size: 3.25rem;
  block-size: 4rem;
}

/* The navigation joins the same row instead of hanging under the quote. */
.quotes-editorial .at-nav {
  margin: 0;
  gap: var(--sp-3);
}
.quotes-editorial .at-hint { margin: 0; }

/* --- narrow ---------------------------------------------------------------
   Not a mobile pass. Enough that the new structure holds together below the
   spread: one column, same groundline, same foot. */
@media (max-width: 67.99rem) {
  .quotes-editorial .at {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "stage" "panel" "foot";
    row-gap: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  }
  .quotes-editorial .at-stage { inline-size: min(100%, 22rem); aspect-ratio: 4 / 5; margin: 0; }
  .at-foot { flex-wrap: wrap; }
}

/* ===========================================================================
   v14 — THE LEAD STORY'S PHOTOGRAPH

   Presentation only. No structural change to the register: same grid, same
   hover, same copy, same two entries, same everything else.

   The supplied photograph is 1280x720 — exactly 16:9. The lead plate was
   16:10, which is a cover-crop of 5% off each side. Measured against the
   frame, that removed only background (the lamp's edge on one side, wall on
   the other): the face sat at 38.9% / 28%, the phone at 47.8% / 68%, the
   reports at 50% / 80%, the top of the head at 9%. Nothing that matters was
   being cut.

   It is still moved to 16:9, for two reasons that have nothing to do with
   rescuing a bad crop:

     · At the photograph's own ratio the crop is zero, so the composition the
       photographer framed — subject left, negative space right — arrives
       intact. That negative space happens to sit against the headline, which
       is the best possible accident for this layout.
     · 16:9 makes the plate 540x304 instead of 540x337 against a 240px text
       column. The picture still leads, but it stops overhanging the copy by
       nearly a hundred pixels.

   object-position stays at the default 50% 50%. With no crop there is
   nothing to bias, and any other value would only shift a nonexistent
   window. This is the one case where the correct focal decision is to make
   no decision.
   --------------------------------------------------------------------------- */
.jr--lead .jr-plate { aspect-ratio: 16 / 9; }

/* A photograph needs a slightly cooler seat than a flat navy drawing did:
   the ring stays a hairline, and the ground behind it is irrelevant now that
   the image fills the box edge to edge. */
.jr--lead .jr-plate { background: var(--navy-950); }

/* The copy centres against the picture instead of hanging from its top edge.
   Measured: the plate is 304px and the text column 240px, so top-aligning
   left a 63px void under the last line and nothing under the picture — the
   two columns read as two separate things starting at the same ceiling.
   Centred, the 64px is split above and below the copy and the pair reads as
   one row. The meta line above is untouched and still spans both. */
@media (min-width: 62rem) {
  .jr--lead .jr-body { align-self: center; padding-block-start: 0; }
}

/* ===========================================================================
   v15 — THREE STORIES, ONE SYSTEM

   The register was built with a lead and two entries: 536px plate against
   248px, 34.4px headline against 23.5px, 20.8px standfirst against 15px.
   That hierarchy was defensible while all three carried the same abstract
   artwork. It stopped being defensible the moment one of them carried a real
   photograph, because the difference then read as "this story matters and
   those two are footnotes" rather than as a considered lead.

   So the lead/entry split goes. All three rows now run on one grid, one plate
   size, one type scale and one rhythm. The first story keeps the photograph
   and keeps its plate at exactly the size it already had — the other two come
   up to meet it rather than it coming down.

   Measured intent at 1440:
     plate      536 x 302   (16:9, all three, unchanged for story one)
     headline   33.6px      (was 34.4 / 23.5)
     standfirst 20.8px      (was 20.8 / 15)
     meta+foot  13px        (unchanged — secondary on purpose)
   --------------------------------------------------------------------------- */

@media (min-width: 62rem) {
  /* One grid for all three. The plate leads on every row: alternating it
     would be a pattern, and a pattern is the thing that makes three items
     read as a listing. */
  .jr--lead,
  .jr--entry {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    grid-template-areas:
      "meta  meta"
      "plate body";
    column-gap: clamp(1.75rem, .8rem + 2.4vw, 3.25rem);
    align-items: center;
  }
  .jr--entry .jr-plate { max-inline-size: none; justify-self: stretch; }
  .jr--lead .jr-body,
  .jr--entry .jr-body { align-self: center; padding-block-start: 0; }
}

/* One ratio. The photograph is natively 16:9 and is not cropped at all; the
   two illustrations are 640x400 drawn with preserveAspectRatio slice, so at
   16:9 they lose 5% top and bottom off a deliberately central composition —
   which is the cheaper compromise than letterboxing the real photograph. */
.jr-plate,
.jr--lead .jr-plate,
.jr--entry .jr-plate { aspect-ratio: 16 / 9; }

/* One type scale. Not "bigger" — the same step the homepage already uses
   between a section h2 (48px here) and the body it introduces. The headline
   now holds its own beside a 536px picture instead of sitting under it. */
.jr--lead .jr-h,
.jr--entry .jr-h {
  font-size: clamp(1.5rem, 1.15rem + 1.2vw, 2.1rem);
  line-height: 1.16;
  letter-spacing: -0.012em;
  /* 20ch was throwing the longest headline onto a third line and leaving a
     third of the column empty beside it. 25ch fills the measure the column
     actually offers without letting the line run past comfortable. */
  max-inline-size: 25ch;
}
.jr--lead .jr-p,
.jr--entry .jr-p {
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: var(--ink-2);
  max-inline-size: 46ch;
}
/* The expansion reads as the same paragraph, one tone quieter — it is
   context, not a second standfirst. */
.jr-p-more { color: var(--ink-3); }

.jr--lead .jr-body,
.jr--entry .jr-body { gap: var(--sp-4); }

/* The label on the two illustrations. Small, unmissable, and gone the moment
   a real photograph replaces the file behind it. */
.jr-plate { position: relative; }
.jr-tempmark {
  position: absolute;
  inset-block-end: .5rem;
  inset-inline-start: .5rem;
  z-index: 2;
  padding: .25rem .5rem;
  border-radius: 3px;
  background: rgba(6, 13, 28, .72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #E7EDF7;
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  pointer-events: none;
}

/* ===========================================================================
   v16 — THE FIRST STORY'S MEDIA IS A VIDEO

   Presentation only. The frame, its ratio, its radius, its shadow, its hover
   and the whole surrounding row are exactly what they were — the <video>
   simply takes the seat the <img> had. The file is 1280x720, the same 16:9
   the plate already used for the photograph, so there is no crop, no
   letterbox and no layout shift.

   Everything below is the <img> rules restated for <video>. It is written as
   a shared selector rather than a copy so the two can never drift.
   --------------------------------------------------------------------------- */
.jr-plate img,
.jr-plate .jr-video {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-4) var(--ease-soft);
}

/* The same approach-scale the stills get, so the row's hover reads
   identically whichever medium a card happens to carry. */
.jr:hover .jr-plate .jr-video,
.jr:focus-within .jr-plate .jr-video { transform: scale(1.035); }

/* No player furniture of any kind, in any engine. The element carries no
   `controls` attribute, but Chromium can still surface an overlay play
   button on a muted, script-driven video, and that is precisely the
   embedded-player look this is meant to avoid. */
.jr-video::-webkit-media-controls,
.jr-video::-webkit-media-controls-enclosure,
.jr-video::-webkit-media-controls-panel,
.jr-video::-webkit-media-controls-start-playback-button,
.jr-video::-webkit-media-controls-overlay-play-button { display: none !important; }

/* The click target is the story, not the film: the stretched link must stay
   the top surface over the plate. */
.jr-video { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .jr-plate .jr-video { transition: none; }
  .jr:hover .jr-plate .jr-video,
  .jr:focus-within .jr-plate .jr-video { transform: none; }
}

/* ===========================================================================
   v17 — THE STORY MEDIA IS CLICKABLE AGAIN

   Not caused by the video; the video is only what made me look. The depth
   pass gave .jr-plate / .jr-body / .jr-meta `transform-style: preserve-3d`.
   preserve-3d establishes a 3D rendering context, and that lifts the plate
   above the .card-stretch::after overlay even though the overlay comes later
   in the DOM — so the whole-record link worked over the headline, the
   standfirst and the date, and did nothing over the picture. On all three
   stories, since the depth pass landed.

   Measured before: elementsFromPoint over the media returned DIV.jr-plate and
   resolved to no link, while the same probe over the text returned
   A.card-stretch -> stories.html#adaeze.

   preserve-3d was never needed here. The perspective lives on .storyreg and
   the translate/rotate lives on these elements themselves; none of them has a
   3D-transformed child whose depth has to be preserved. Removing it keeps the
   hover exactly as it is and gives the overlay the top surface back.
   --------------------------------------------------------------------------- */
.jr-plate,
.jr-body,
.jr-meta { transform-style: flat; }

/* ===========================================================================
   v18 — THE FIVE-REVIEW RAIL

   The faces moved from a strip under the portrait to a column beside it, and
   the arrows came with them. That is the whole change: choosing an account
   and stepping between accounts are now one control in one place, which is
   what stops the section reading as a picture with a carousel bolted
   underneath.

   Three columns, one axis:

       [ rail ]  [ portrait ]  [ the words ]

   align-items: center keeps all three on the same horizontal axis, which is
   the fix for the image-high / text-low disconnection. The portrait column is
   a fixed 23rem so the rail cannot take width from it — the main visual is
   exactly the size it was before the rail existed.
   --------------------------------------------------------------------------- */

@media (min-width: 68rem) {
  .quotes-editorial .at {
    /* auto for the rail, fixed for the portrait so it can never be squeezed,
       and the words take what is left up to a readable maximum. */
    grid-template-columns: auto 23rem minmax(0, 34rem);
    grid-template-areas: "rail stage panel";
    column-gap: clamp(1.75rem, .4rem + 2.4vw, 3.25rem);
    align-items: center;
  }
  .at-rail  { grid-area: rail; }
  .quotes-editorial .at-stage { grid-area: stage; align-self: center; }
  .quotes-editorial .at-panel { grid-area: panel; align-self: center; }
}

/* --- the rail ------------------------------------------------------------- */
.at-rail {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-4);
  align-self: center;
}

.at-faces {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
}

/* Sized so the column of five lands just under the portrait's own height —
   five at 4.5rem plus their gaps is 392px against the stage's 460px, so the
   rail reads as shorter than what it indexes rather than competing with it. */
.at-face {
  inline-size: 3.75rem;
  block-size: 4.5rem;
}

/* The active one, in a vertical list, wants an edge as well as a lift: a gold
   rule on the leading side is how a list says "this one" without shouting. */
.at-face.is-live {
  box-shadow:
    inset 3px 0 0 0 var(--gold-lite),
    0 0 0 1px rgba(201, 153, 47, .85),
    0 10px 22px -10px rgba(0, 0, 0, .7);
}
[dir="rtl"] .at-face.is-live {
  box-shadow:
    inset -3px 0 0 0 var(--gold-lite),
    0 0 0 1px rgba(201, 153, 47, .85),
    0 10px 22px -10px rgba(0, 0, 0, .7);
}

/* --- the arrows, at the foot of the rail ---------------------------------
   Smaller than they were: at the foot of a 60px column a 46px control is the
   loudest thing in the rail, which is the wrong order. These are secondary to
   the faces above them and to everything on the right. */
.quotes-editorial .at-nav {
  margin: 0;
  gap: var(--sp-2);
  padding-block-start: var(--sp-2);
}
.quotes-editorial .at-btn {
  inline-size: 2.25rem;
  block-size: 2.25rem;
}
.quotes-editorial .at-btn svg { inline-size: 1rem; block-size: 1rem; }

/* --- the hint, now a caption under the words ------------------------------
   It stopped being part of a control row and became what it always read as:
   a quiet line telling you the review itself is the thing to click. */
.quotes-editorial .at-hint {
  display: inline-flex;
  margin-block-start: clamp(1.25rem, .9rem + 1.1vw, 2rem);
}

/* --- narrow ---------------------------------------------------------------
   Not a mobile pass. Below the spread the rail lies down into a row again so
   nothing overflows; the order stays rail, portrait, words. */
@media (max-width: 67.99rem) {
  .quotes-editorial .at {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "rail" "stage" "panel";
  }
  .at-rail { flex-direction: row; align-items: center; gap: var(--sp-4); }
  .at-faces { flex-direction: row; }
  .at-face { inline-size: 3rem; block-size: 3.75rem; }
}


/* ===========================================================================
   v19 — RESPONSIVE PASS: TOUCH CONTROL FOR THE PATIENT-STORY FILMS

   Appended last, all-new selectors, nothing above edited. Every rule is
   inside @media (hover: none), so a pointer device never renders any of it
   and the approved desktop composition is untouched by definition.

   .jr-play is injected by home.js only on coarse-pointer devices — see the
   POINTER CAPABILITY note there. The story films are driven by pointerenter
   and pointerleave, and a finger never sends the second one: measured, a tap
   started the film unmuted and left it playing while the same tap followed
   the stretched link off the page. This is the control that replaces that.
   =========================================================================== */
@media (hover: none) {
  .jr-play {
    position: absolute;
    inset-block-end: var(--sp-4);
    inset-inline-end: var(--sp-4);
    /* Above the stretched link's ::after, which covers the whole card. */
    z-index: 2;

    /* 48px: comfortably over the 44px touch-target floor, and the same disc
       language the brand already uses — navy ground, gold mark, gold ring. */
    inline-size: 48px;
    block-size: 48px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    border-radius: 50%;
    cursor: pointer;

    background: rgba(10, 23, 48, .82);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    color: var(--gold-lite);
    box-shadow: 0 0 0 1px rgba(212,175,55,.55), var(--e-2);

    transition: background-color var(--dur-2) var(--ease-out),
                box-shadow var(--dur-2) var(--ease-out);
  }
  .jr-play svg { inline-size: 22px; block-size: 22px; }

  /* :active rather than :hover — the only press state a finger can express. */
  .jr-play:active {
    background: rgba(10, 23, 48, .94);
    box-shadow: 0 0 0 2px var(--gold-lite), var(--e-2);
  }
  .jr-play:focus-visible {
    outline: 2px solid var(--gold-lite);
    outline-offset: 3px;
  }

  /* While a film is running the control recedes, so it sits over the picture
     rather than on top of the person speaking. */
  .jr-video[data-story-video="playing"] ~ .jr-play,
  .jr-video[data-story-video="playing-silent"] ~ .jr-play {
    background: rgba(10, 23, 48, .55);
  }
}

@media (hover: none) and (prefers-reduced-motion: reduce) {
  .jr-play { transition: none; }
}


/* ===========================================================================
   v20 — RESPONSIVE PASS: THE EXPERIENCE RAIL AND THE SOUND CONTROL ON PHONES

   Two narrow-screen corrections. Both are inside max-width queries and touch
   only selectors that exist on the homepage alone (.at-face is in index.html
   only; .aud is created by home.js, which no other page loads), so the
   approved desktop composition and every other page are untouched.
   =========================================================================== */

/* --- 1. The five faces stay legible at phone size -------------------------
   Below 68rem the rail turns horizontal and each face drops to 3rem x 3.75rem.
   At that size the inactive treatment — opacity .42 over
   saturate(.35) brightness(.66) — stops reading as "a dimmed portrait" and
   starts reading as a dark rectangle: measured at 390px, four of the five
   faces were indistinguishable blocks and there was no way to tell whom you
   were about to select.

   The dimming is eased rather than removed, so the active face is still
   obviously the active one — it keeps its full colour, its gold ring and its
   inset gold edge, which are what actually carry the state. The faces also
   go up to 48px wide so the row clears the 44px touch-target floor with a
   margin rather than sitting exactly on it. */
@media (max-width: 47.99rem) {
  .quotes-editorial .at-face {
    inline-size: 3rem;          /* 48px — comfortably over the touch floor */
    block-size: 3.6rem;
    opacity: .72;
    filter: saturate(.72) brightness(.88);
  }
  .quotes-editorial .at-face.is-live { opacity: 1; filter: none; }
}

/* --- 2. The sound control stops sitting across the reading line -----------
   The pill is 136px wide. On a 390px screen that is 35% of the viewport
   parked over body text: measured, it covered ~5,600px² of the live quote in
   the experience section. On desktop the same control is a small fraction of
   the line and causes no such collision.

   So below 36rem it collapses to the disc it already almost is — same navy
   ground, same gold wave mark, same button, same behaviour — and the label
   is dropped visually only. The button already sets its own aria-label in
   home.js, so nothing is lost to assistive technology. */
@media (max-width: 36rem) {
  .aud {
    inline-size: 3rem;
    block-size: 3rem;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
  }
  .aud .aud-txt {
    position: absolute;
    inline-size: 1px; block-size: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; border: 0;
  }
}

/* ---------------------------------------------------------------------------
   TOUCH TAP TARGETS
   Two controls render below a comfortable finger size on a phone: the top-bar
   phone number (130x21) and the breadcrumb links (35x17). Both are important
   on mobile -- the number is the fastest route to a human.

   The hit area is extended with a pseudo-element rather than with padding, so
   the touch region grows without moving a single pixel of layout or changing
   how either control looks. Applied only where the pointer is coarse; a mouse
   has no trouble with either.
   -------------------------------------------------------------------------- */
@media (hover: none), (pointer: coarse) {
  /* Breadcrumbs sit in open space, so the region can simply be extended --
     41px effective height, no layout movement at all. */
  .crumbs a, .crumb a { position: relative; }
  .crumbs a::after, .crumb a::after {
    content: "";
    position: absolute;
    inset-block: -12px;
    inset-inline: -8px;
    z-index: 0;
  }

  /* The phone number cannot use the same trick: it sits 6px from the top of
     the viewport, so there is nothing to grow into upwards, and downwards the
     nav paints over the extension and wins the hit test. Real padding instead
     -- 21px to 29px, past the 24px minimum, at the cost of 8px on a utility
     strip that is otherwise mostly air. */
  .topbar-call {
    padding-block: 4px;
    margin-block: -4px;   /* keep the strip's own rhythm unchanged */
  }
}


/* ===========================================================================
   v21 — THE STORY IN FOCUS ON TOUCH

   Appended last, all-new selectors, nothing above edited. Everything is inside
   @media (hover: none): a hover device never renders any of it, so the approved
   desktop composition is untouched by definition.

   On desktop the story under the cursor is "in focus": it lifts and takes a gold
   ring, the others step back to .55, its film speaks. A finger has no cursor,
   so home.js gives the story the scroll has settled on `.is-focus` (and the
   register `.has-focus`) and this restates the SAME declarations for it. The
   values below are copied from the :hover / :focus-within rules above, not
   re-designed; if those change, change these with them.

   Two things a touch screen adds:

   1. STICKY STATE. A tap leaves :hover (and :focus-within, on the tapped
      button) on the card after the finger has gone, so a story the visitor
      once touched would stay lit while another is in focus. Cards that are not
      in focus are therefore put back to their resting values here, which is
      what makes "exactly one story lit" true.

   2. A STICKY .storyreg:hover steps EVERY card without :hover back to .55 --
      including the one in focus -- and out-ranks a plain class selector, hence
      the !important on the focused story's opacity. It restores the value the
      cascade would have given it with no sticky state.
   =========================================================================== */
@media (hover: none) {

  /* --- the story in focus: the :hover look --------------------------------- */
  .jr.is-focus::before {
    background: var(--gold-lite);
    box-shadow: 0 0 0 1px rgba(201, 153, 47, .7), 0 0 0 4px rgba(201, 153, 47, .15);
  }
  .jr.is-focus .jr-run { inline-size: clamp(2.25rem, 1.5rem + 2.4vw, 4.25rem); }
  .jr.is-focus .jr-plate {
    transform: translate3d(0, -9px, 26px) rotateX(1deg);
    box-shadow:
      0 0 0 1px rgba(201, 153, 47, .46),
      0 26px 50px -22px rgba(6, 16, 36, .46),
      var(--e-3);
  }
  .jr.is-focus .jr-plate img,
  .jr.is-focus .jr-plate .jr-video { transform: scale(1.035); }
  .jr.is-focus .jr-h a { background-size: 100% 1px; }
  .jr.is-focus .jr-body { transform: translate3d(0, -5px, 12px); }
  .jr.is-focus .jr-meta { transform: translate3d(0, -3px, 6px); }

  .storyreg .jr.is-focus .jr-plate,
  .storyreg .jr.is-focus .jr-body,
  .storyreg .jr.is-focus .jr-meta,
  .storyreg .jr.is-focus::before { opacity: 1 !important; }

  /* --- the others step back ------------------------------------------------ */
  .storyreg.has-focus .jr:not(.is-focus) .jr-plate,
  .storyreg.has-focus .jr:not(.is-focus) .jr-body,
  .storyreg.has-focus .jr:not(.is-focus) .jr-meta { opacity: .55; }
  .storyreg.has-focus .jr:not(.is-focus)::before { opacity: .45; }

  /* --- a tap's leftover :hover / :focus-within is not focus ---------------- */
  .jr:not(.is-focus):is(:hover, :focus-within)::before {
    background: var(--ivory);
    box-shadow: 0 0 0 1px rgba(201, 153, 47, .55);
  }
  .jr--lead:not(.is-focus):is(:hover, :focus-within)::before {
    background: var(--gold-lite);
    box-shadow: 0 0 0 1px rgba(201, 153, 47, .55), 0 0 0 4px rgba(201, 153, 47, .13);
  }
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-run { inline-size: clamp(1.5rem, 1rem + 1.6vw, 3rem); }
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-plate {
    transform: none;
    box-shadow: 0 0 0 1px rgba(26, 49, 96, .20), var(--e-2);
  }
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-plate img,
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-plate .jr-video { transform: none; }
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-h a { background-size: 0 1px; }
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-body,
  .jr:not(.is-focus):is(:hover, :focus-within) .jr-meta { transform: none; }
}

@media (hover: none) and (prefers-reduced-motion: reduce) {
  .jr.is-focus .jr-plate,
  .jr.is-focus .jr-body,
  .jr.is-focus .jr-meta,
  .jr.is-focus .jr-plate img,
  .jr.is-focus .jr-plate .jr-video { transform: none; }
  .jr.is-focus .jr-run { inline-size: clamp(1.5rem, 1rem + 1.6vw, 3rem); }
}
