/* ============================================================
   index.css — HOMEPAGE ONLY.
   Loaded by index.html and by no other page, so plain selectors
   here are page-scoped by load and cannot reach another page.
   Must stay LAST in the <link> order: it resolves ties against
   base.css / v3.css / v9.css by cascade position, not specificity.

   WHY THIS FILE EXISTS
   Until 4 Aug 2026 the homepage's design was carried by eight
   data-* attributes on <html>, applied by the Tweaks panel. The
   attributes were removed in 9e98758 as "orphaned"; five of them
   were live and the page regressed. The panel system is being
   retired, so the state is baked in here instead of restored to
   the attributes. No attribute selectors, no fallback path.

   Section 1-5 below are the five live attributes, resolved to
   what they actually rendered at 9e98758^. Section 6 is the
   former inline <style id="v10-hero-tune"> block, moved verbatim
   so the sheet holds the whole page-specific layer.
   ============================================================ */


/* ------------------------------------------------------------
   2 · was data-heroimg="familybg"        v3.css:188 · v3.css:891
   Base .hero-photo (base.css:552) is hero-cart-cells.webp at 60%.
   ------------------------------------------------------------ */
.hero-photo {
  right: 0;
  left: auto;
  width: 74%;
  /* ⚠️ image-set() selects on RESOLUTION (dpr), not viewport width — it cannot
     serve a phone a narrower file on its own. Width comes from the media-query
     tiers below, each naming its own pair; image-set only picks 1x vs 2x within
     a tier. `.hero-photo` is a CSS background, so there is no srcset to lean on.
     A plain url() precedes each image-set as the fallback for anything that
     does not support it. Files: 800/1200/1600/1800, built from the source PNG
     at q80/80/78/78 — see the tier comments for which width renders where.
     [Jacob, 24 Aug 2026] */
  background:
    linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
    url('assets/hero-lily-newpatient-fadeout-1200.webp');
  background:
    linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
    image-set(
      url('assets/hero-lily-newpatient-fadeout-1200.webp') 1x,
      url('assets/hero-lily-newpatient-fadeout.webp') 2x);
  /* 🔴 Width-driven, not height-driven. `auto 95%` sized the photo off the
     hero's HEIGHT, so as the viewport narrowed the image kept its width and
     its left edge — the physician — marched left into the headline. That is
     the 1000–1200 band failing exactly as CLAUDE.md says it does; at 1200 the
     headline sat across her face. min(68vw, 990px) ties the photo to the
     viewport, so she tracks the text column instead of closing on it, and
     the cap holds the photo still above ~1456 where the container centres.
     -40px pushes her clear of the text; the third woman has ~80px of image
     to her right, so nothing is cropped off a person. */
  /* 🔴 Rescaled for the new photo on 24 Aug 2026. This frame is 1800x1522,
     ratio 1.183, where hero-zhou-patient-daughter-faded.webp was 1.423. The
     figures below are the old ones times 0.831 (= 1.183/1.423), which holds
     the rendered HEIGHT constant — and height is what the vertical offsets in
     every tier are actually tuned to. ⛔ Do not copy the pre-24-Aug widths
     back; at ratio 1.183 they render ~20% taller than the 828px slot.
     Heads sit at ~21% of this frame's height against the old photo's ~19%, so
     the y offsets carry over unchanged. */
  background-size: cover, min(56.5vw, 823px) auto;
  /* bottom 100px lifts the group off the trust strip - they sat low against it.
     [Jacob, 8 Aug 2026] · x shifted 100px left 24 Aug 2026 [Jacob] */
  background-position: center, right 60px bottom 100px;
  background-repeat: no-repeat, no-repeat;
}

/* Above 1440 the container stops growing and centres, so the text stops
   moving right while the photo would keep going. The -40px nudge is no
   longer buying clearance, and it crops the right-hand edge for nothing —
   the photo sits flush to the right instead.
   ------------------------------------------------------------------
   The +20% enlargement lives here too [Jacob, 8 Aug 2026], and this is
   the only place it can. The comment above records a wider photo pushing
   the physician into the headline in the 1000-1200 band; +20% does it
   again, because the image scales on the viewport (81.6vw) while the text
   column does not. Rendered at 1200 the lede's last two lines run across
   her coat. It was tried at a 1300 breakpoint (still clipped her at 1301)
   and at 1400 (1401-1440 clear but only just). 1441 is where the container
   stops growing, so it is the first width at which the text stops chasing
   the photo — the enlargement belongs to that same fact, not to a number
   picked to dodge a collision.
   🔴 Judge this slot by rendering it, not by arithmetic. An overlap model
   assuming "opaque content starts at 26% of the image width" called every
   width from 1101 to 1440 a collision, including ones that are visibly
   fine. The fade puts the visible left edge nowhere near the geometric
   one, and no formula here survived contact with a screenshot. */
/* ⚠️ Bounded at 1919 on 10 Aug 2026 so the ultrawide tier below can take over
   without touching these values. 1441-1919 renders byte-identically to before. */
@media (min-width: 1441px) and (max-width: 1919px) {
  .hero-photo {
    /* Size restored to the 8 Aug values [Jacob, 10 Aug 2026]. A -10% pass was
       tried first and measured insufficient: at 1536 it cut the headline
       overlap from 144px to 55px but did not clear it, and it left the photo
       at 56% of viewport at 1919 against 62% at 1920 — a visible step. */
    background-size: cover, min(67.8vw, 987px) auto;
    /* renders at most 987px -> 1200 at 1x, 1800 at 2x */
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      url('assets/hero-lily-newpatient-fadeout-1200.webp');
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      image-set(
        url('assets/hero-lily-newpatient-fadeout-1200.webp') 1x,
        url('assets/hero-lily-newpatient-fadeout.webp') 2x);
    /* Was `calc(50% - 100px)` [Jacob, 8 Aug 2026]; re-anchored to the copy on
       10 Aug 2026 — same intent, height-independent. See the 1920+ block for
       the measurement. 12.43vw and 181px are 390/2560 of this tier's own two
       size terms (81.6vw and the 1188px cap, which binds from ~1456). */
    /* 🔴 x overhang, tapered — this is what clears the headline instead of
       shrinking the photo. Raising her to the copy's top line put the HEADLINE
       beside her rather than the lede, and at 1441-1600 it crossed her coat.
       The push needed falls linearly with width (182px at 1441, 144 at 1536,
       112 at 1600, 0 by 1919) because the text column stops growing while the
       photo does not, so a LINEAR taper to zero at 1920 tracks it exactly and
       leaves the 1920 boundary seamless — a flat push would jump 190px there.
       0.44 gives 25-35px of clearance across the band; measured, not assumed.
       ⚠️ Budget: the source's right 20.7% is transparent (content ends at col
       2030/2560), so at 1176-1188px wide there are ~243px of overhang that
       clip fade rather than people. Peak push is 211px at 1441, inside that by
       ~32px. ⛔ Do not raise 0.44 without re-checking against that 243px. */
    background-position: center, calc(100% + (1920px - 100vw) * 0.44 - 100px) calc(clamp(56px, calc(6vh + 16px), 100px) - min(12.43vw, 181px));
  }
}

/* 1920+ — ultrawide. [Jacob, 10 Aug 2026, reported on a 2560x1440 panel]
   Two faults, both of which only appear once the container has stopped
   growing and the viewport keeps going.

   1 · THE PHOTO FROZE. min(81.6vw, 1188px) hits its cap at ~1456, so from
       there up the photo is a fixed 1188px no matter how wide the screen is:
       75% of the viewport at 1440, but 46% at 2560. It read as small because
       it WAS small — everything else kept scaling and it did not. Not a
       source limit; the asset is 2560x1799 natural.

   2 · IT SAT LOW. `calc(50% - 100px)` centres the layer in .hero-photo, whose
       height follows the hero's min-height: max(620px, 100svh - 72px). Taller
       window, lower box centre, and a flat -100px cannot keep up. Measured at
       a constant 1440 width: photo top vs copy top is -2px at 1200 viewport
       height, +15px at 1329. The lift was tuned at one height and drifts at
       every other one.

   🔴 Both are fixed by anchoring to the COPY, not to the box — which is what
   the 1101-1200 comment already says the design intends ("the eye judges the
   photo against the copy"). This tier just does it in a way that survives a
   change of viewport height.

   Constants below are measured off the asset's alpha channel, not assumed —
   the 1441 comment is right that guessed fractions do not survive a render,
   so these were read out of the pixels (canvas, 10 Aug 2026):
     · visible content starts   25.6% across  (col 655 / 2560, max alpha >=128)
     · visible content spans    21.7% - 77.7% down (rows 390-1398 / 1799)
     · aspect                   1799/2560 = 0.7027
   So the empty margin above the people is 0.217 x 0.7027 = 0.1525 of the
   layer's WIDTH — that is the 9.45vw and 247px below (0.1525 of 62vw and of
   the 1620px cap). Subtracting it from the copy's top offset puts the top of
   her head level with the top of the headline at any viewport height.

   ⚠️ Copy offset is 16px (v3.css `.hero.hero-bg` padding) + .hero-grid's
   clamp(40px, 6vh, 84px) = clamp(56px, 6vh + 16px, 100px). If either moves,
   this moves with it — unlike the -100px it replaces, which did not.

   Why 62vw / 1620px:
     · 62vw lands on 1190px at 1920, within 2px of the 1188px the tier below
       ends on, so the boundary is seamless rather than a step.
     · Clearance from the text column only IMPROVES with width — visible left
       edge advances at 0.539vw while the column's right edge advances at
       0.5vw. 40px at 1920, 65px at 2560, 480px at 3440. The cap is not
       holding a collision off; it is holding SHARPNESS.
     · 1620px cap binds at ~2613 and keeps the render at or below the 2560px
       source, so it never upscales on a DPR-1 panel.
   ⚠️ Two-value syntax per layer, for the reason recorded at 1101-1200: the
   3-value form silently drops the whole declaration in some engines. */
@media (min-width: 1920px) {
  .hero-photo {
    background-size: cover, min(51.5vw, 1346px) auto;
    /* renders at most 1346px -> 1600 at 1x; 1800 is the cap, so 2x is best-effort */
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      url('assets/hero-lily-newpatient-fadeout-1600.webp');
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      image-set(
        url('assets/hero-lily-newpatient-fadeout-1600.webp') 1x,
        url('assets/hero-lily-newpatient-fadeout.webp') 2x);
    background-position: center, calc(100% - 100px) calc(clamp(56px, calc(6vh + 16px), 100px) - min(9.45vw, 247px));
  }
}

/* 1201-1440: +10% [Jacob, 8 Aug 2026]. A middle tier between
   the tuned size below 1200 and the +20% above 1440. Half the enlargement,
   so it does not reproduce the collision +20% caused at 1200 - verified by
   render at 1201, 1280 and 1440, not by arithmetic. */
@media (min-width: 1201px) and (max-width: 1440px) {
  .hero-photo {
    background-size: cover, min(62.2vw, 905px) auto;
    /* renders at most 905px -> 1200 at 1x, 1800 at 2x */
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      url('assets/hero-lily-newpatient-fadeout-1200.webp');
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      image-set(
        url('assets/hero-lily-newpatient-fadeout-1200.webp') 1x,
        url('assets/hero-lily-newpatient-fadeout.webp') 2x);
    /* -90px = 50px further right than the base rule [Jacob, 8 Aug 2026].
       Safe because the right 20% of the source is transparent (alpha mean
       <=10 until 20% in), so the overhang eats fade, not the daughter.
       y re-anchored to the copy 10 Aug 2026 — see the 1920+ block. 11.4vw is
       390/2560 of this tier's 74.8vw; the 1089px cap does not bind below
       1456, so no min() is needed inside this range. */
    background-position: center, calc(100% - 10px) calc(clamp(56px, calc(6vh + 16px), 100px) - 11.4vw);
  }
}

/* 1101-1200 — the two-column layout's tightest band [Jacob, 8 Aug 2026].
   The photo goes 100px further right and the column widens to take the space
   back, so the HEADLINE fills its side instead of leaving a gutter down the
   middle.
   🔴 The lede is deliberately NOT widened with it. It keeps --measure (58ch)
   and simply sits in a wider column. Chrome spec §4 records that the 52-56ch
   caps were already inside the 45-75 character optimum, and that widening
   them for a 50+ audience reading clinical copy makes reading worse, not
   better. ⛔ Do not "finish the job" by stretching .lede to match. */
@media (min-width: 1101px) and (max-width: 1200px) {
  .hero-photo {
    /* +10%, matching the 1201-1440 tier [Jacob, 8 Aug 2026]. */
    background-size: cover, min(62.2vw, 905px) auto;
    /* renders at most 905px -> 1200 at 1x, 1800 at 2x */
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      url('assets/hero-lily-newpatient-fadeout-1200.webp');
    background-image:
      linear-gradient(180deg, var(--bg) 0%, transparent 8%, transparent 92%, var(--bg) 100%),
      image-set(
        url('assets/hero-lily-newpatient-fadeout-1200.webp') 1x,
        url('assets/hero-lily-newpatient-fadeout.webp') 2x);
    /* 🔴 Vertical anchor: 100px ABOVE centre, not centred and not bottom-
       anchored. All three desktop tiers use the same lift.
       "Centred" is ambiguous in this slot and the two readings differ by
       over 100px. Centred in the hero BOX is what the CSS did first, and it
       looks wrong: .hero-grid is align-content:start with top padding, so
       the copy sits in the upper part of the hero while the box's centre is
       much lower. The eye judges the photo against the copy, not against an
       invisible box, so the photo is aligned to the text block instead.
       ⚠️ This offset is tied to where the copy lands. If the hero's padding
       or the headline's length changes, remeasure it — do not assume it
       still holds.
       ⚠️ Two-value syntax with calc() for x. `right -140px center` is the
       3-value form, which is not reliably supported - it silently drops the
       whole declaration in some engines. */
    background-position: center, calc(100% + 40px) calc(clamp(56px, calc(6vh + 16px), 100px) - 11.4vw);
  }
}
/* ⚠️ The .hero-grid and .hero-headline halves of this band CANNOT live here —
   both are re-declared unconditionally in §6 below, and a media query adds no
   specificity, so file order decides. They sit after §6c instead. Placing
   them here applied the photo shift and silently dropped the other two. */

@media (max-width: 1100px) {
  /* Below 1100 the photo becomes a banner ABOVE the text (base.css:1231),
     and it is the first thing under the nav. .hero's 24px top padding and
     the banner's own 8px radius left it floating in a cream gap; the photo
     now meets the nav rule edge to edge. .hero-grid keeps its own
     clamp(40px, 6vh, 84px) top padding, so the eyebrow is unaffected.
     🔴 The padding selector must carry .hero-bg — v3.css:57 sets
     `padding: 16px 0 0` on `.hero.hero-bg`, and a bare `.hero` loses. */
  .hero.hero-bg { flex-direction: column; padding-top: 0; }
  /* The text going full width when the photo stacks above it is handled in
     §6c, AFTER .hero-grid is set — a media query adds no specificity, so a
     later unconditional rule in this same file would beat it here. */
  .hero-photo {
    top: auto; bottom: auto; right: auto; transform: none;
    width: 100%; aspect-ratio: auto; box-shadow: none;
    margin-top: 0; border-radius: 0;
    /* A different photograph from the desktop hero: the same session, but
       the wider four-person frame with the mosaic backdrop intact rather
       than the faded cutout. It only works stacked, where the banner is
       full-bleed and nothing has to sit beside it.
       🔴 The height is the whole problem with this frame. Faces run from 5%
       to 61% of the image, and the old fixed 300px band showed 47% of it —
       any vertical position either sliced Dr. Zhou's forehead or dropped
       the husband. clamp() + `center top` keeps all four in frame at every
       stacked width: at 390 the box is taller than the photo's own ratio,
       so the full height shows and ~25px is cropped off the sides; from
       ~480 up the width binds and the band holds the top 72-87%, which
       clears his chin at 61% with room to spare. Crops torsos, not people. */
    height: clamp(280px, 42vw, 460px);
    /* No fade layer here. The old banner carried a cream gradient over its
       bottom 18% because its photo ended in a hard edge that had to be
       dissolved into the page. This frame is cropped mid-torso against a
       full backdrop, so it reads as a photograph with an edge — which is
       what a full-bleed banner should be. The desktop rule above keeps its
       gradients: that photo has to fade into the copy beside it. */
    /* Swapped from hero-patient-family-wide.webp — the four-person wide shot —
       on 10 Aug 2026. `[Jacob]` At 390 the banner is 280px tall and that frame
       put four faces across a full-bleed strip, so none of them read. This is
       the same shoot cropped to three, which also matches the DESKTOP hero
       (hero-zhou-patient-daughter-faded.webp): the page now shows the same
       people whichever way you come at it. The husband is out of frame here,
       as he already is on desktop.
       ⚠️ The comment below about "keeping all four in frame" predates the swap
       — three now, and the crop is easier for it. */
    background: url('assets/hero-zhou-patient-daughter-wide.webp');
    background-size: cover;
    background-position: center top;
    background-repeat: no-repeat;
  }
}
/* ⚠️ 25 Aug 2026 `[Jacob]` — the block above is restored VERBATIM from the
   pre-24-Aug state: the mobile banner goes back to the live three-person
   frame, while the desktop tiers keep the new Dr. Zhou + patient photo.
   🔴 KNOWN AND ACCEPTED: the two breakpoints now show DIFFERENT PEOPLE. The
   10 Aug swap recorded in the comment above existed specifically to end that
   — "the page now shows the same people whichever way you come at it" — and
   this reverses it. Jacob's call after seeing the alternatives; it is not an
   oversight, and it is not to be "fixed" by quietly swapping one side to
   match the other. If it is ever revisited, the fix is a new mobile crop of
   the NEW session, not a change to the desktop tiers. */



/* ------------------------------------------------------------
   3 · was data-cred="light"     v3.css:666-697 · 1541-1565 · 1568-1583
   Section 2 of the page. Base .credentials (base.css:985) is
   --bg-dark #2A2520 with white text; this is the cream treatment.

   Rules dropped because the element does not exist on this page
   (grep -ciE 'class="[^"]*\b<name>\b' index.html -> 0):
     .credentials .stat-row · .credentials .stat .n · .stat .n em
     .stat .l · .credentials .portrait-slot · .dnv-footnote
     .cred-grid · .cred-item · .cred-k · .cred-quote · .cred-badge-stub
   ------------------------------------------------------------ */
.credentials {
  background: var(--bg);
  color: var(--slate-dark);
  border-top: 1px solid var(--border-soft);
  border-bottom: 1px solid var(--border-soft);
}
.credentials .eyebrow        { color: var(--sage-deep); }
.credentials .display        { color: var(--fg-strong); }
.credentials p,
.credentials .section-head .right { color: var(--slate-dark); }
.credentials .btn-ghost {
  color: var(--fg-strong) !important;
  border-color: var(--fg-strong) !important;
}

.physician {
  border-color: var(--border);
  background: var(--bg-card);
}
.physician h4     { color: var(--fg-strong); }
.physician .role  { color: var(--slate-mid); }
.physician .bio   { color: var(--slate-dark); }
.physician .langs { color: var(--accent-deep); }

/* lead-physician + team-support block */
.lp-name,
.lp-bio em,
.lp-facts .n,
.ts-grid p em      { color: var(--fg-strong) !important; }
.lp-bio,
.ts-grid p         { color: var(--slate-dark) !important; }
.lp-facts .l       { color: var(--slate-mid); }
.lp-eyebrow,
.lp-role,
.lp-facts .n em,
.ts-k              { color: var(--accent-deep); }
.ts-grid {
  background: var(--border-soft);
  border-color: var(--border-soft);
}
.ts-grid li        { background: var(--bg-card); }
.ts-label,
.lp-name .lp-post  { color: var(--slate-mid); }
.lp-facts,
.team-support      { border-color: var(--border-soft); }

.cred-link         { color: var(--accent-deep); }

/* ------------------------------------------------------------
   3b · The clinical team, once its columns stack
   Same complaint as the hero: everything crowds the left and the
   right half of the section sits empty. Three caps were doing it,
   all set for the two-column case and none released when the
   columns collapsed:
     · base.css:512  .section-head .right — 480px
     · v3.css:1326   .lead-physician goes one-column at 960
     · v3.css:1327   .lp-portrait — 360px, so a 900px-wide page
                     showed a 360px portrait with 500px of nothing
   The intro paragraph now runs the container once the head stacks.
   The portrait keeps its place BESIDE the text down to 640 — a
   photograph next to a name reads better than a photograph with a
   name under it, and at 700px the portrait track is still ~250px.
   Below 640 it stacks and fills the width, which on a phone is
   what "full width" should mean.
   Plain selectors are safe here: index.css loads on index.html
   only, and .lead-physician also lives on medical-team.html,
   which this file cannot reach.
   ------------------------------------------------------------ */
@media (max-width: 1100px) {
  .section-head .right { max-width: none; }
}
@media (max-width: 960px) and (min-width: 641px) {
  .lead-physician {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    gap: clamp(28px, 4vw, 48px);
  }
  .lp-portrait { max-width: none; }
}
@media (max-width: 640px) {
  .lp-portrait { max-width: none; }
}
/* .cred-note removed 6 Aug 2026 — the element is gone from index.html, and it
   was the only one in the tree. See the commit for why the sentence went. */

/* ------------------------------------------------------------
   7 · Trust strip meets the section rule below it
   The strip already sits flush against .credentials (hero
   padding-bottom is 0), but it carried an inline
   `border-radius: 8px` that overrode v3.css:107's `8px 8px 0 0`,
   so it rendered rounded bottom corners resting on the section
   line. The inline style is deleted; this drops the strip's own
   bottom border so the junction is ONE 1px rule, not two
   stacked (.credentials already supplies a full-width border-top).
   The side borders now run down and terminate on that rule.
   ------------------------------------------------------------ */
.hero .trust-strip { border-bottom: 0; }

/* Three of the four trust leads render at 32px and "SinoUnited Health"
   rendered at 26px — v9.css:119 shrinks `.n.word.long` so a long string
   cannot overflow a narrow column. In this four-up strip it just read as
   an inconsistent set. The lead now matches its neighbours exactly
   (v3.css:782's clamp, repeated), and the guard it replaces is not needed
   here: measured at 1440 the item is 286px wide against a 250px string,
   and the strip drops to two columns at 980 (v9.css:122) before the
   columns get tight. Scoped to .hero — .n.word.long is shared. */
.hero .trust-item .n.word.long {
  font-size: clamp(24px, 2.4vw, 32px);
  line-height: 1.08;
}


/* ------------------------------------------------------------
   8 · (was: checker result → the reader's own condition page)
   Deleted 12 Aug 2026 with the self-check widget. The routing job
   this link did — send the reader to their own condition page —
   is now done by the three .cond-card lists in §11, which is
   where guide §4 always put it.
   ------------------------------------------------------------ */


/* ------------------------------------------------------------
   9 · Closing-CTA form: country / diagnosis / prior lines
   .row3 is three EQUAL columns (v3.css:696), which in this
   half-panel gives ~162px each and clips the longest option to
   "Mantle cell lympl". The diagnosis select carries by far the
   longest strings, so the track is weighted toward it. Scoped
   to this panel — .row3 is shared and correct elsewhere.
   🔴 The min-width guard is load-bearing, and 641 is the right
   number. v3.css:723 collapses .form .row3 to one column at
   **640** (not 760 — the block starts at v3.css:717), and
   index.css loads AFTER v3.css, so an unguarded rule here wins
   at every width and keeps three columns on a phone — measured
   at 390 as 56 / 119 / 79px fields. Guarding at 761 instead
   would leave 641-760 on the unweighted 3-equal fallback.
   Same cascade-position trap that bit index.css on the nav
   font-size.
   ------------------------------------------------------------ */
/* The row widths are set by the PANEL, not the viewport, so the form is the
   query container. ⚠️ Without this declaration the @container rule below is
   inert and silently does nothing — which is exactly what happened when this
   block was rewritten and the line was sliced out with the old rules. */
.final-cta-panel .form { container-type: inline-size; container-name: ctaform; }

@media (min-width: 641px) {
  /* Row 1 is name / email / country, row 2 is diagnosis / prior lines 50-50.
     `[Jacob, 10 Aug 2026]` Three text inputs share a row comfortably because
     their placeholders are short — "you@example.com" is the longest at 143px.
     The two selects carry the long strings and now get half a row each, which
     is what finally puts "Prior treatment lines (optional)" on ONE line: it
     needs 231px and gets 250 at 1440, where the old three-up gave it 164 and
     clipped the value as well. */
  /* ⚠️ NOT equal thirds. Measured need: email 164px, name 130px, country 90px
     — "you@example.com" is much the longest placeholder and "Australia" much
     the shortest. Equal thirds gave all three 161px at 1440 and clipped the
     email placeholder, so the tracks are weighted to what each holds. */
  .final-cta-panel .row  { grid-template-columns: 1.05fr 1.25fr 0.7fr; }
  .final-cta-panel .row3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* The message textarea keeps its own full-width row. */
  .final-cta-panel .row .field-full { grid-column: 1 / -1; }

  /* Label and control each take a subgrid track, so when one label wraps every
     control in the row still moves together instead of one dropping out of
     line. Kept from the three-column version; the reason has not changed. */
  .final-cta-panel .row,
  .final-cta-panel .row3 { grid-template-rows: auto auto; }
  .final-cta-panel .row .field,
  .final-cta-panel .row3 .field {
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    /* minmax(0, 1fr), not 1fr: an input's max-content default is ~210px and
       every control would overflow its track. */
    grid-template-columns: minmax(0, 1fr);
    row-gap: 6px;
  }

  /* 🔴 Both guards below are load-bearing and both have bitten this file.
     min-width: 641 — v3.css:766 has already collapsed these rows to one column
     at 640, and index.css loads later at equal specificity, so an unguarded
     rule here wins on a phone. Measured once as three columns at 390 with
     fields of 56/119/79px, and again as two.
     The container query — not a media query — because the row's width is set
     by the PANEL, which is side-by-side above 1100 and stacked below, so the
     widths that squeeze are disjoint ranges of viewport. */
  /* Two thresholds, because the two rows fail at different widths — which is
     the point of weighting them separately. Three short text inputs survive a
     much narrower row than two selects carrying long option strings.
       row  (name/email/country)  email needs 164px in a 1.25/3.0 track,
                                  so the row needs ~425px. Guarded at 460, not
                                  425: at 441 of container the email field had
                                  5px of slack, which is arithmetic, not a
                                  margin. 460 leaves the tightest three-column
                                  case 18px.
       row3 (diagnosis/lines)     the longer select needs 181px in a half
                                  track, so ~380px. Guarded at 400.
     Both were derived from measured need and then confirmed across the ladder,
     not chosen and hoped for. */
  @container ctaform (max-width: 460px) {
    .final-cta-panel .row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }
  @container ctaform (max-width: 400px) {
    .final-cta-panel .row3 { grid-template-columns: minmax(0, 1fr); }
  }
}



/* ------------------------------------------------------------
   10 · Section 3 — the conditions intro
   Originally .selfcheck-grid, a 0.9fr / 1.1fr split with the
   intro left and the self-check widget right; then stacked, with
   the widget full-width beneath the intro.

   The widget was removed on 12 Aug 2026 and the .checker* rules
   went with it. What is left is the intro block, which now sits
   directly above the three condition cards (§11) — the routing
   this section is actually for, per guide §4.

   .selfcheck-grid, .selfcheck-conditions and .condition-chip in
   v3.css were already unreachable before that change and are
   still left for a separate CSS sweep.
   ------------------------------------------------------------ */
.selfcheck-intro { max-width: 760px; }
.selfcheck-intro .lede { max-width: 640px; }

/* ------------------------------------------------------------
   11 · Three condition pathways
   The third card is the solid-tumor program. It is a PEER
   PATHWAY for a patient choosing a route, but it is NOT a peer
   program clinically — different target, different indication,
   its own intake. The site separates it everywhere else
   (nav "Solid tumor program" group, therapies.html .ch-solid
   band). Here it keeps the card grid but carries the separation
   in its label and a left rule, so a gastric patient can find
   themselves without the page implying one combined program.
   ------------------------------------------------------------ */
.cond-cards.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) {
  .cond-cards.cols-3 { grid-template-columns: minmax(0, 1fr); }
}
.cond-card-solid {
  border-left: 2px solid var(--sage-deep);
  padding-left: 20px;
}
.cond-card-solid .tgt { color: var(--sage-deep); }


/* ------------------------------------------------------------
   12 · Cost signal — fill the right column instead of stranding
        a button in it
   The section read as unfinished, and the cause was structural
   rather than editorial: .cost-signal is a 1.5fr / 1fr grid
   (v9.css:129) whose right column held ONLY a ghost button,
   bottom-aligned. A full-bleed section, a short paragraph and a
   quiet link floating in space promises more than it delivers.

   The CTA moves into the copy column and becomes solid; the
   right column now carries the "2 + 21" package breakdown.

   ⚠️ This is NOT new content. All 12 other pages carrying
   .cost-signal already publish the 2 + 21 fact — the homepage
   was the only one that did not. Wording is from the live
   claude_guide-costs.md:137-142, which is blockquoted drop-in
   copy, and it carries NO figure, so the "no money outside
   /costs" rule is untouched.

   ⛔ The inclusions list stays OFF this page. guide-costs.md:199:
   the included and not-included lists "only do their job as a
   pair — the patient reads 'included' and relaxes, reads 'not
   included' and trusts." Half of that pair on a teaser produces
   exactly the false comfort the warning exists to prevent.

   Scoped with .cs-home — .cost-signal is shared by 13 pages.
   ------------------------------------------------------------ */
.cs-home { align-items: start; gap: clamp(40px, 5vw, 72px); }
.cs-home .cs-btn { margin-top: 32px; }

/* The right column started level with the "Cost" eyebrow, which read as a
   second eyebrow-less column hanging above the copy. It now starts level
   with the H2 — the top of the actual reading matter.
   29px is the eyebrow's line box (12px text, inline-flex with the rule)
   plus the H2's own inline margin-top:16px = 45px. Measured, not guessed.
   Only while the two columns are side by side; .cost-signal collapses to
   one column at 860 (v9.css:140) and the offset would be dead space. */
@media (min-width: 861px) {
  .cs-home .cs-package { margin-top: 45px; }
}

/* Typographic, not a card. The other 12 .cost-signal pages already
   render this fact as a large serif figure with a small caption
   (therapy.css:869, scoped to .rx-cost so it does not reach here),
   and that treatment is reproduced rather than reinvented. It also
   sidesteps a panel-fill decision: --bg-card is the form-panel
   colour on this site (.final-cta-panel, /eligibility's .el-inquiry)
   and --sage-pale is the read-panel colour, and this is neither. */
.cs-package .package {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
}
.cs-package .package .k {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 40px;
  line-height: 1;
  color: var(--accent-deep);
  letter-spacing: -0.01em;
}
.cs-package .package .v {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--slate-mid);
}
.cs-package-lede {
  margin: 14px 0 0;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--slate-mid);
}
.cs-package ul {
  list-style: none;
  margin: 20px 0 0;
  padding: 0;
}
.cs-package li {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 16px 0;
  border-top: 1px solid var(--border-soft);
}
.cs-package li:last-child { padding-bottom: 0; }
.cs-package .n {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 26px;
  line-height: 1;
  color: var(--fg-strong);
  letter-spacing: -0.01em;
}
.cs-package .l {
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--slate-mid);
}
/* .cost-signal collapses to one column at 860 (v9.css:140) — the
   panel follows it rather than needing its own breakpoint. */


/* ------------------------------------------------------------
   4 · was data-video="link"                          v9.css:170
   One video CTA in the hero, not two. Without this both the text
   link (.hero-video-link) and the trigger card (.hero-media) render.
   ------------------------------------------------------------ */
.hero-media { display: none; }


/* ------------------------------------------------------------
   6 · former inline <style id="v10-hero-tune"> — moved verbatim
   4 Aug 2026. Scoped hero refinements for v10 — calmer vertical
   rhythm, title clear of the photo.
   ------------------------------------------------------------ */
/* Anchor the text block toward the top so it fills the space above rather than below.
   The text column scales with the viewport for the same reason the photo does:
   a fixed 720px track held the headline at full length while the photo drifted
   left underneath it. 46vw keeps the two moving together, 640px caps it so the
   measure stays readable on a wide screen, and the outer minmax(0, …) is what
   lets the track collapse below the 430px floor at phone widths — index.css
   loads after base.css, so this rule beats base.css:1228's `1fr` even inside a
   media query. The lede is 65ch (598px at 18.5px), up from the 54ch used for
   body copy elsewhere on the site. */
.hero-grid { align-content: start; padding-top: clamp(40px, 6vh, 84px); grid-template-columns: minmax(0, clamp(430px, 46vw, 640px)) 1fr; }
.hero-headline { line-height: 1.05; }
.hero-text .lede { margin-top: 18px; max-width: var(--measure); }
.hero-ctas { margin-top: 26px; }
.hero-video-link { margin-top: 30px; }

/* ------------------------------------------------------------
   6b · 1440 and below — buy back vertical room
   The hero is height-bound: v3.css:58 holds it to
   max(620px, 100svh - 72px), and the trust strip sits after the
   text INSIDE that box. On a 900px-tall laptop the video link
   was landing on the strip with no air between them. Two things
   give the room back: the eyebrow goes (the H1 says
   "CAR T-cell therapy" and the strip says NMPA and Shanghai, so
   nothing is lost that is not said twice already), and the
   headline drops from 66px to 60px at 1440. Above 1440 there is
   height to spare and the eyebrow stays.
   ------------------------------------------------------------ */
@media (max-width: 1440px) {
  .hero-headline { font-size: clamp(40px, 4.2vw, 60px); }
  .hero .trust-strip { margin-top: 56px; }
}

/* ------------------------------------------------------------
   6c · Stacked hero — the text takes the whole container
   Below 1100 the photo is a banner above the text (base.css:1231),
   so there is nothing beside the copy to clear and the 46vw column
   just left half the page empty. Track and lede cap both released.
   🔴 This block MUST stay after §6 — the .hero-grid rule there has
   the same specificity and no media query, so file order decides.
   ⚠️ 80ch on the H1 does NOT bind. `ch` is relative to the element's
   own font size, and at a 43-60px headline one ch is ~24-30px, so
   80ch resolves to roughly 2000-2400px — far wider than any stacked
   container. The declaration is there because the headline was asked
   to match the lede's measure, but what it actually does is release
   the 20ch cap and let the headline run the container.
   The lede is capped at 80ch rather than released outright: full
   width at 1024–1100 was running about 100 characters a line. 80ch
   is 736px, so the cap only bites above ~776px of viewport — below
   that the container is already narrower and the copy is full width
   with no second breakpoint needed.
   ------------------------------------------------------------ */
@media (max-width: 1100px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .hero-text .lede { max-width: 80ch; }
  .hero-headline { max-width: 80ch; }
}

/* ------------------------------------------------------------
   6d · 1101–1200 — rebalance the two-column band [Jacob, 8 Aug 2026]
   The photo moves 100px further right (that half is up with the other
   .hero-photo tiers) and the text column widens to take the space back.

   🔴 MUST stay after §6 and §6c, for the reason §6c already gives: the
   .hero-grid rule in §6 has the same specificity and no media query, so
   file order decides. Written first alongside the .hero-photo tier and it
   silently did nothing — the photo shifted, the column stayed at 46vw and
   the headline at 4.2vw.

   Widening the column alone does not fill it: the headline's line breaks
   do not move, so it just leaves ~200px of the wider column empty. The
   type has to grow with it. 5.4vw = 64.8px at 1200, against 50.4px before.

   ⛔ The lede is deliberately NOT widened. It keeps --measure (58ch) and
   simply sits in a wider column. Chrome spec §4 records that the 52–56ch
   caps were already inside the 45–75 character optimum, and that widening
   them for a 50+ audience reading clinical copy makes reading worse.
   ------------------------------------------------------------ */
@media (min-width: 1101px) and (max-width: 1200px) {
  .hero-grid { grid-template-columns: minmax(0, clamp(430px, 52vw, 680px)) 1fr; }
  .hero-headline { font-size: clamp(48px, 5.4vw, 66px); }
}
/* Faces-only supporting care-team strip — grouped with the team line below */
.team-faces { margin-top: clamp(40px, 5vw, 60px); padding-top: 30px; border-top: 1px solid var(--border-soft); }
.cred-team-line { margin-top: 26px; padding-top: 0; border-top: none; }
.team-faces { display: grid; grid-template-columns: minmax(230px, 0.85fr) 2fr; column-gap: clamp(32px, 4vw, 72px); row-gap: 28px; align-items: start; }
.tf-intro { align-self: center; }
.tf-intro p { margin: 0; }
.tf-intro .cred-link { margin-top: 18px; display: inline-flex; }
.tf-row { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); column-gap: clamp(24px, 3vw, 48px); }
.tf-person { display: flex; align-items: center; gap: 16px; padding: 14px 0; border-top: 1px solid var(--border-soft); }
.tf-row > .tf-person:nth-child(-n+2) { border-top: none; padding-top: 0; }
.tf-avatar { flex: 0 0 auto; width: 76px; height: 76px; border-radius: 50%; overflow: hidden; background: color-mix(in oklab, var(--sage-ink, #4a5d54) 8%, #fff); box-shadow: 0 0 0 1px rgba(0,0,0,0.05), 0 3px 10px rgba(0,0,0,0.08); }
.tf-avatar img { width: 100%; height: 100%; object-fit: cover; object-position: center 12%; display: block; }
.tf-txt { display: flex; flex-direction: column; min-width: 0; }
.tf-name { font-size: 15px; font-weight: 600; line-height: 1.25; color: var(--slate-dark, #2b3a34); }
.tf-spec { margin-top: 4px; font-size: var(--fs-note); line-height: 1.3; color: var(--slate-mid); }
@media (max-width: 860px) { .team-faces { grid-template-columns: 1fr; } }
@media (max-width: 520px) { .tf-row { grid-template-columns: 1fr; } }
