/* ==========================================================================
   Juvena Therapeutics — site design system (2026 redesign)
   Poppins only · charcoal / soft-white grounds · one green accent · hairlines
   ========================================================================== */

@font-face{font-family:"Poppins";font-style:normal;font-weight:300;font-display:swap;src:url("../fonts/poppins-300.woff2") format("woff2")}
@font-face{font-family:"Poppins";font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/poppins-400.woff2") format("woff2")}
@font-face{font-family:"Poppins";font-style:italic;font-weight:400;font-display:swap;src:url("../fonts/poppins-400i.woff2") format("woff2")}
@font-face{font-family:"Poppins";font-style:normal;font-weight:500;font-display:swap;src:url("../fonts/poppins-500.woff2") format("woff2")}
@font-face{font-family:"Poppins";font-style:normal;font-weight:600;font-display:swap;src:url("../fonts/poppins-600.woff2") format("woff2")}

:root{
  /* brand */
  --green:#009345; --green-bright:#36CF4E; --green-deep:#0E7A3A;
  /* Brand green is #009345, and white on it measures 3.99:1 — below AA for text
     under 24px, as does #009345 text on the light ground (3.60:1). The site
     is built to a WCAG 2.2 AA target (the public statement was cut 2026-08-21), so TEXT and text-bearing fills use the
     brand's own deep green instead: 5.43:1 on white, 4.90:1 on #F3F3F3. Bars,
     dots, the film line and focus rings keep #009345 — they are graphical
     objects, where 3:1 is the threshold and 3.60:1 clears it. */
  --green-text:var(--green-deep); --grey:#6D6E71;
  --charcoal:#282828; --soft:#F3F3F3; --white:#FFFFFF; --panel:#ECECEE;
  /* --fg-2 is #696A6D, one step below the brand grey #6D6E71 (session 14): small grey text sits over the
     stick-and-ball ground, and the brand grey measures 4.27:1 where a 7% teal mark crosses it;
     #696A6D measures 4.53:1 there and 4.87:1 on the flat soft ground. It and --green-text #0E7A3A are
     what cap the ground's ink: they are the smallest text that may sit on it, so their 4.5:1 line is
     the ground's alpha ceiling on each paper (7.2%/7.7% on #F3F3F3, 15.6%/16.0% on white — the site
     ships 7% and 14%; build_ground.py carries the arithmetic). Move either colour and both tiles must
     be re-derived. The brand grey stays on graphical marks (--grey: the pipeline's partnering bar). */
  --ink:#282828; --fg-1:#3A3A3D; --fg-2:#696A6D; --fg-3:#9A9B9E;
  --on-dark:#FFFFFF; --on-dark-2:#C9CACB; --on-dark-3:#8E8F91;
  --line:#D8D9DB; --line-soft:#ECECEE; --line-dark:rgba(255,255,255,.14);
  --tint:#E6F4EC; --tint-2:#CDEAD9;
  --purple:#A383BC; --teal:#0097A7; --sky:#85B9DC; --blue:#2E9BD6; --navy:#0B5394; --orange:#D47E43;
  /* type */
  --font:"Poppins","Helvetica Neue",Arial,sans-serif;
  --fs-display:clamp(2.75rem,6.2vw,5.75rem);   /* 44 → 92 */
  --fs-h1:clamp(2.25rem,4.4vw,3.75rem);        /* 36 → 60 */
  --fs-h2:clamp(1.75rem,3vw,2.5rem);           /* 28 → 40 */
  --fs-h3:1.5rem;                              /* 24 */
  --fs-lead:1.25rem;                           /* 20 */
  --fs-body:1.0625rem;                         /* 17 */
  --fs-small:.875rem;                          /* 14 */
  --fs-label:.75rem;                           /* 12 caps */
  --fs-micro:.6875rem;                         /* 11 */
  /* layout */
  --container:1240px; --gutter:clamp(20px,4vw,56px);
  --r-sm:4px; --r-md:8px; --r-lg:14px; --r-pill:999px;
  --ease-out:cubic-bezier(.16,1,.3,1); --ease-inout:cubic-bezier(.65,0,.35,1);
  /* Depth (session 19b). The legacy WordPress site lifted its content off exactly this background,
     and the stick-and-ball ground is back, so the plates need it again. Provenance, taken from the
     RENDERED Elementor CSS in the archive (uploads/elementor/css/post-*.css), not from the database:
     the site's stored settings hold 128 shadow objects but only 44 are enabled, and just six
     declarations actually shipped. On page content it was ONE value, `0 3px 6px rgba(0,0,0,.16)`,
     on hand-written 1200px `::before` slabs (white or brand green, `border-radius:0 30px 30px 0`)
     sitting behind picture-and-copy blocks on the home and indications pages; the same value, with a
     0 x-offset, on the two header pills. (`2px 8px 23px 3px rgba(0,0,0,.2)` also rendered, but only
     on popup modals, so it is not the effect.) Borrowed as the idea, not the value: pure black at a
     6px blur reads hard and dated. These are the brand charcoal, straight down, in two layers — a
     1-2px contact edge plus a soft ambient — which is how an object actually sits on a surface.
     Three steps, and no fourth: plate (a card at rest), picture (a photograph), raised (under the
     cursor). A shadow needs an edge to cast from, so it goes on filled plates only. */
  --shadow-sm:0 1px 2px rgba(40,40,40,.06),0 3px 8px -3px rgba(40,40,40,.10);
  --shadow-md:0 1px 2px rgba(40,40,40,.06),0 8px 20px -6px rgba(40,40,40,.16);
  --shadow-lg:0 2px 4px rgba(40,40,40,.07),0 18px 40px -12px rgba(40,40,40,.22);
  --header-h:76px;
}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:auto}
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}
/* The stick-and-ball ground (build_ground.py → ground-soft.svg + ground-white.svg): the legacy site's
   faint teal network, re-drawn on brand as a seamless 1440px tile. Soft sections and page heroes
   are transparent so the body's tile shows through; the WHITE sections carry the same network on
   their own paper (session 19) — one geometry, two inks. The ink strength is set per paper by the
   smallest text that may sit on it: the 4.5:1 line falls at 7.27% on #F3F3F3 and 15.68% on white,
   so the site ships 7% and 14% (build_ground.py's docstring carries the arithmetic; ground_check.js
   is the gate). The two inks land within a few units per channel of each other — (226,237,238) and
   (219,240,243) — so it reads as the same network on lighter paper, about twice as clearly.
   Charcoal sections stay plates. Both films paint their own opaque soft stage, so the ground
   appears after the film, as asked. */
body{font-family:var(--font);font-size:var(--fs-body);line-height:1.6;color:var(--fg-1);background:url("../img/ground-soft.svg") 50% 0/1440px auto repeat var(--soft);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow-x:hidden}
img,picture,video,canvas,svg{display:block;max-width:100%}
/* the year filter hides cards with the hidden attribute; a class rule such as .card--link{display:flex} would
   otherwise outrank the user-agent [hidden] rule (same specificity, later source) */
[hidden]{display:none!important}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
ul{list-style:none}
::selection{background:var(--green-text);color:#fff}
:focus-visible{outline:2px solid var(--green);outline-offset:3px;border-radius:var(--r-sm)}
.skip{position:absolute;left:12px;top:-60px;z-index:2000;background:var(--charcoal);color:#fff;padding:10px 14px;border-radius:var(--r-md)}
.skip:focus{top:12px}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.sr-only h2,.sr-only h3{font-size:1em;font-weight:500}

/* ---------- type ---------- */
.display{font-size:var(--fs-display);font-weight:300;line-height:1.02;letter-spacing:-.02em;color:var(--ink)}
.h1{font-size:var(--fs-h1);font-weight:300;line-height:1.08;letter-spacing:-.018em;color:var(--ink)}
.h2{font-size:var(--fs-h2);font-weight:400;line-height:1.14;letter-spacing:-.012em;color:var(--ink)}
.h3{font-size:var(--fs-h3);font-weight:500;line-height:1.28;letter-spacing:-.006em;color:var(--ink)}
/* last-resort break, scoped to the 400%-zoom / smallest-phone band (320–360px layout viewports).
   Unscoped, this rule split "Fibroinflammato/ry" inside a 5fr column at 1440 and orphaned the comma
   of "Announcements," at 390 (session 11 addendum). A word narrower than its box is never broken;
   the headline that needed breaking ("Announcements," — 356px at the 44px display floor, wider
   than a 390px phone's 350px column) was reworded instead, so no heading word on the site exceeds
   its box from 320px up (research/inspection/wordbreaks.js, every width 320–1440). */
@media (max-width:360px){.display,.h1{overflow-wrap:break-word}}
.lead{font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--fg-1)}
.small{font-size:var(--fs-small);line-height:1.5;color:var(--fg-2)}
.micro{font-size:var(--fs-micro);line-height:1.45;color:var(--fg-3)}
.label{font-size:var(--fs-label);font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--green-text)}
.label--grey{color:var(--fg-2)}
/* Eyebrow tiers (session 11): an eyebrow takes its size from the heading it introduces. One
   12px role under every heading put "TEAM" at 7.4:1 beneath the 89px display — a caption, not a
   structural label (the references run ~4.5:1). Display-level 17px at .10em, h1-level 14px,
   card/meta/h2-level labels stay 12px — existing tokens only, so the type scale holds. Below
   1040px the display is ≈64px and the h1 ≈46px, so each tier steps down one token: 14 / 12. A
   browser without :has() keeps the 12px base (the film beats' paragraph rules are `p:not(.label)`
   so nothing else can restyle an eyebrow). */
.label:has(+ .display){font-size:var(--fs-body);letter-spacing:.10em}
.label:has(+ .h1){font-size:var(--fs-small)}
@media (max-width:1040px){
  .label:has(+ .display){font-size:var(--fs-small);letter-spacing:.12em}
  .label:has(+ .h1){font-size:var(--fs-label)}
}
.em{color:var(--green-text);font-weight:500}
.on-dark .display,.on-dark .h1,.on-dark .h2,.on-dark .h3{color:var(--on-dark)}
.on-dark .lead,.on-dark p{color:var(--on-dark-2)}
.on-dark .label{color:var(--green-bright)}
.on-dark .small{color:var(--on-dark-3)}
strong{font-weight:500}
em{font-style:italic}

/* ---------- layout ---------- */
.wrap{width:min(var(--container),100% - 2*var(--gutter));margin-inline:auto}
/* a centred 860px column under a left-aligned hero jumped the text edge 190px to the
   right; the column now starts at the container edge and only its measure is narrow */
.wrap--narrow{width:min(var(--container),100% - 2*var(--gutter));margin-inline:auto}
.wrap--narrow>*{max-width:860px}
.section{position:relative;padding:clamp(88px,11vw,152px) 0}
.section--tight{padding:clamp(64px,8vw,104px) 0}
.section--soft{background:transparent}
.section--white{background:url("../img/ground-white.svg") 50% 0/1440px auto repeat var(--white)}
.section--dark{background:var(--charcoal);color:var(--on-dark-2)}
.section--tall{min-height:min(92vh,900px);display:flex;align-items:center}
.grid{display:grid;gap:clamp(24px,3vw,48px)}
.grid-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.grid-4{grid-template-columns:repeat(4,minmax(0,1fr))}
/* a two-column grid that itself holds a two-column grid (the contact cards beside the map) makes
   four columns: 157px cards at 768px, and the 24px h3 "Collaborate" (142px) still overflowed its
   card up to 972px — so the outer grid stacks below the 1040px breakpoint (session 11 addendum) */
@media (max-width:1040px){.grid-2--stack{grid-template-columns:1fr}}
.split{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:clamp(32px,5vw,96px);align-items:start}
.split--even{grid-template-columns:repeat(2,minmax(0,1fr))}
.split--rev{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
.stack>*+*{margin-top:1.25rem}
.stack--lg>*+*{margin-top:2rem}
.rule{border:0;border-top:1px solid var(--line);margin:0}
.on-dark .rule,.section--dark .rule{border-color:var(--line-dark)}
.eyebrow{display:flex;align-items:center;gap:14px;margin-bottom:22px}
.eyebrow::before{content:"";width:28px;height:1px;background:currentColor;opacity:.6}
@media (max-width:900px){
  .grid-3,.grid-4{grid-template-columns:repeat(2,minmax(0,1fr))}

  .split,.split--rev,.split--even{grid-template-columns:1fr}
}
@media (max-width:600px){.grid-2,.grid-3,.grid-4{grid-template-columns:1fr}}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:10px;font-weight:500;font-size:var(--fs-small);letter-spacing:0;line-height:1;padding:15px 22px;border-radius:var(--r-pill);border:1px solid transparent;transition:transform .35s var(--ease-out),background .25s,color .25s,border-color .25s,box-shadow .35s;white-space:nowrap}
.btn svg{width:16px;height:16px;transition:transform .35s var(--ease-out)}
.btn:hover svg{transform:translateX(3px)}
.btn:active{transform:scale(.985)}
.btn--primary{background:var(--green-text);color:#fff;box-shadow:0 8px 24px -10px rgba(14,122,58,.55)}
.btn--primary:hover{background:var(--green-deep);box-shadow:0 12px 28px -10px rgba(0,147,69,.7)}
.btn--ghost{border-color:var(--line);color:var(--ink);background:transparent}
.btn--ghost:hover{border-color:var(--ink)}
.on-dark .btn--ghost,.section--dark .btn--ghost{border-color:rgba(255,255,255,.28);color:#fff}
.on-dark .btn--ghost:hover,.section--dark .btn--ghost:hover{border-color:#fff}
.btn--white{background:#fff;color:var(--ink)}
.btn--white:hover{background:var(--soft)}
.link{display:inline-flex;align-items:center;gap:8px;font-weight:500;font-size:var(--fs-small);color:var(--green-text);border-bottom:1px solid transparent;transition:border-color .25s}
.link:hover{border-color:currentColor}
.link svg{width:14px;height:14px}
/* a .link inside running text is part of the sentence: inline-flex broke the line
   around it ("see the ⏎ clinical studies section") */
p .link{display:inline;font-size:inherit}
.on-dark .link{color:var(--green-bright)}

/* ---------- header (floating chrome, adaptive over film) ---------- */
.header{position:fixed;top:0;left:0;right:0;z-index:100;height:var(--header-h);display:flex;align-items:center;color:var(--ink);transition:color .35s,background .35s,box-shadow .35s}
.header .wrap{display:flex;align-items:center;justify-content:space-between;gap:24px;width:min(1400px,100% - 2*var(--gutter))}
.header.on-film{color:#fff}
.header.on-film.on-light{color:var(--ink)}
.header.scrolled:not(.on-film){background:rgba(243,243,243,.86);backdrop-filter:saturate(1.4) blur(14px);-webkit-backdrop-filter:saturate(1.4) blur(14px);box-shadow:0 1px 0 var(--line)}
.header.on-film::before{content:"";position:absolute;inset:0 0 auto 0;height:170%;z-index:-1;pointer-events:none;background:linear-gradient(to bottom,rgba(20,20,20,.42),rgba(20,20,20,0));opacity:1;transition:opacity .35s}
/* Chrome over footage has to stay legible on EVERY frame, and a photograph is
   not a flat ground: measured on the home hero, "Team" sat at 1.46:1 and
   "Pipeline" at 1.73:1 against the ink — both far below AA. On a dark film the
   answer is a dark scrim and white type; on this light film it is the mirror,
   a soft light scrim under ink. Functional, not decoration: it is confined to
   the header band and clears completely below it. */
.header.on-film.on-light::before{opacity:1;background:linear-gradient(to bottom,rgba(243,243,243,.86) 0%,rgba(243,243,243,.66) 42%,rgba(243,243,243,.18) 78%,rgba(243,243,243,0) 100%)}
/* A dark page-hero is the same problem as a dark film: ink chrome on charcoal.
   /careers/ was rendering its ENTIRE primary navigation at 1.00:1 — nav ink
   #282828 sitting on the #282828 hero, invisible until you scrolled 24px and the
   translucent light header background appeared behind it. Reuse the film's own
   over-dark treatment for the un-scrolled state. */
.page-careers .header:not(.scrolled){color:#fff}
.page-careers .header:not(.scrolled) .brand--light{display:none}
.page-careers .header:not(.scrolled) .brand--dark{display:block}
.page-careers .header:not(.scrolled) .nav a:hover{background:rgba(255,255,255,.14)}
.page-careers .header:not(.scrolled) .nav a[aria-current]::after{background:#fff}
.page-careers .header:not(.scrolled) .btn--ghost{border-color:rgba(255,255,255,.4);color:#fff}
.page-careers .header:not(.scrolled) .btn--ghost:hover{border-color:#fff}
.brand{display:inline-flex;align-items:center;height:44px}
.brand img{height:44px;width:auto}
.brand .brand--dark{display:none}
.header.on-film:not(.on-light) .brand--light{display:none}
.header.on-film:not(.on-light) .brand--dark{display:block}
.nav{display:flex;align-items:center;gap:6px}
.nav a{font-size:var(--fs-small);font-weight:500;padding:9px 13px;border-radius:var(--r-pill);opacity:.9;transition:opacity .25s,background .25s}
.nav a:hover{opacity:1;background:rgba(40,40,40,.06)}
.header.on-film:not(.on-light) .nav a:hover{background:rgba(255,255,255,.14)}
.nav a[aria-current="page"]{opacity:1;box-shadow:inset 0 -1px 0 currentColor;border-radius:0;padding-inline:4px;margin-inline:9px}
.header .btn{padding:11px 18px}
.header.on-film:not(.on-light) .btn--ghost{border-color:rgba(255,255,255,.4);color:#fff}
.header.on-film:not(.on-light) .btn--ghost:hover{border-color:#fff}
.menu-btn{display:none;width:44px;height:44px;border-radius:var(--r-pill);align-items:center;justify-content:center}
.menu-btn span{display:block;width:20px;height:1.5px;background:currentColor;position:relative;transition:transform .3s}
.menu-btn span::before,.menu-btn span::after{content:"";position:absolute;left:0;width:20px;height:1.5px;background:currentColor;transition:transform .3s,top .3s}
.menu-btn span::before{top:-6px}.menu-btn span::after{top:6px}
.menu-open .menu-btn span{background:transparent}
.menu-open .menu-btn span::before{top:0;transform:rotate(45deg)}
.menu-open .menu-btn span::after{top:0;transform:rotate(-45deg)}
.mobile-nav{position:fixed;inset:0;z-index:90;background:var(--charcoal);color:#fff;display:none;flex-direction:column;justify-content:center;padding:var(--gutter)}
.menu-open .mobile-nav{display:flex}
.mobile-nav a{font-size:clamp(1.75rem,7vw,2.5rem);font-weight:300;line-height:1.35;letter-spacing:-.01em;display:block;padding:6px 0;border-bottom:1px solid var(--line-dark)}
.mobile-nav .btn{margin-top:28px;align-self:flex-start}
@media (max-width:1040px){
  .nav,.header .btn--ghost{display:none}
  .menu-btn{display:inline-flex}
  .menu-open .header{color:#fff}
  .menu-open .header::before,.menu-open .header.on-film::before,.menu-open .header.on-film.on-light::before{opacity:0}
  .menu-open .brand--light{display:none}.menu-open .brand--dark{display:block!important}
}

/* ---------- cards / stats / misc ---------- */
.card{background:var(--white);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-sm);padding:clamp(24px,3vw,36px);transition:transform .5s var(--ease-out),box-shadow .5s var(--ease-out),border-color .3s}
/* only a card that IS a link lifts — informational cards (careers, patients, contact) were advertising a click they could not take */
.card--link:hover{transform:translateY(-3px);box-shadow:var(--shadow-lg)}
/* a charcoal-on-charcoal shadow is mud, and a card on a dark section has the section to separate it */
.card--dark{background:rgba(255,255,255,.04);border-color:var(--line-dark);color:var(--on-dark-2);box-shadow:none}
.card--dark .h3{color:#fff}
/* measured: on-dark-3 over the card's lighter ground is 4.08:1 — below AA for 14px.
   Card body copy is body copy; it takes the on-dark body colour (9:1). */
.card--dark .small{color:var(--on-dark-2)}
.card--link{display:flex;flex-direction:column}
.card .link{margin-top:22px}
/* the link is pinned to the card foot, so a row of cards keeps one link baseline
   even when one headline wraps a line longer than its neighbours */
.card--link .link{margin-top:auto;padding-top:22px;align-self:flex-start}
.stat{display:flex;flex-direction:column;gap:6px}
.stat b{font-size:clamp(2.5rem,4.5vw,3.75rem);font-weight:300;line-height:1;letter-spacing:-.02em;color:var(--ink)}
.stat span{font-size:var(--fs-small);color:var(--fg-2);max-width:26ch}
/* inside a split column a 60px numeral no longer fits a 3-up cell: "1 in 2,100",
   "142 million" wrapped onto two lines and the home teaser's three numbers ran
   into each other. The h2 size is already in the scale. */
.split .stat b{font-size:var(--fs-h2)}
.on-dark .stat b,.section--dark .stat b{color:#fff}
.on-dark .stat span,.section--dark .stat span{color:var(--on-dark-3)}
.note{font-size:var(--fs-small);color:var(--fg-2);border-left:1px solid var(--line);padding-left:16px}
.section--dark .note{color:var(--on-dark-3);border-color:var(--line-dark)}
.pill{display:inline-flex;align-items:center;gap:8px;font-size:var(--fs-label);font-weight:500;letter-spacing:.06em;text-transform:uppercase;padding:6px 12px;border-radius:var(--r-pill);border:1px solid var(--line);color:var(--fg-2)}
.pill--green{border-color:var(--tint-2);background:var(--tint);color:var(--green-deep)}
.pill--dark{border-color:var(--line-dark);color:var(--on-dark-2)}
.figure{border-radius:var(--r-lg);overflow:hidden;background:var(--panel);box-shadow:var(--shadow-md)}
.figure img{width:100%;height:100%;object-fit:cover}
/* The headshots are transparent cutouts, so the cell's own fill is what the shadow casts from. The
   old gradient ended on --soft, which IS the ground of the #board section: the plate disappeared
   there while its shadow still drew a rounded rectangle round nothing, 13 times. A white plate is
   also the honest ground — the cutouts were matted off white. --shadow-sm, not md: a headshot cell
   is a plate, not a picture, and twenty picture shadows down a grid is heavy. */
.avatar{width:100%;height:auto;aspect-ratio:1;border-radius:var(--r-lg);object-fit:cover;background:var(--white);box-shadow:var(--shadow-sm)}
/* Eight marks in a wrapping flex row left one logo orphaned on a second line at 1440
   and a 3+2+1+2 stack at 390. A fixed 4-column grid (2 on phones) reads as a wall.
   Tone: grayscale alone kept each mark's own weight (CIRM near-black beside a light
   grey Mubadala); contrast(0) flattens every opaque pixel to one grey, brightness
   sets that grey to the fg-2 tone the text mark uses, alpha is untouched — so all
   seven PNGs sit at one weight, and hover restores each brand's own colour. */
.logo-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(28px,3vw,40px) clamp(28px,4vw,64px);align-items:center;justify-items:start}
.logo-row img{height:34px;width:auto;filter:grayscale(1) contrast(0) brightness(.85)}
.logo-row img.logo--wide{height:20px} /* ultra-wide wordmarks (Manta Ray) keep the row's visual weight */
.logo-row .textmark{font-size:var(--fs-lead);font-weight:500;letter-spacing:-.01em;color:var(--fg-2)}
@media (max-width:760px){.logo-row{grid-template-columns:repeat(2,minmax(0,1fr));gap:28px 24px}.logo-row .textmark{font-size:var(--fs-body)}}

/* ---------- rise on arrival ---------- */
.rise>*{opacity:0;transform:translateY(26px);transition:opacity .9s var(--ease-out),transform .9s var(--ease-out)}
.rise.in>*{opacity:1;transform:none}
.rise.in>*:nth-child(2){transition-delay:.09s}
.rise.in>*:nth-child(3){transition-delay:.18s}
.rise.in>*:nth-child(4){transition-delay:.27s}
.rise.in>*:nth-child(5){transition-delay:.36s}
.rise.in>*:nth-child(6){transition-delay:.45s}
.rise.in>*:nth-child(n+7){transition-delay:.52s}
@media (prefers-reduced-motion:reduce){
  .rise>*{opacity:1;transform:none;transition:none}
  /* a shortened transition still JUMPS: cancel the hover/press transforms themselves */
  .card--link:hover,.btn:hover svg,.btn:active{transform:none}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* ---------- page hero (non-film pages) ---------- */
.page-hero{padding:calc(var(--header-h) + clamp(56px,9vw,120px)) 0 clamp(48px,6vw,88px);background:transparent}
.page-hero .display{max-width:16ch}
.page-hero .lead{max-width:56ch;margin-top:26px}
.page-hero--dark{background:var(--charcoal)}
.page-hero--dark .display{color:#fff}
.page-hero--dark .lead{color:var(--on-dark-2)}
.page-hero--dark .label{color:var(--green-bright)}

/* ---------- pipeline chart ---------- */
.pipe{border-top:1px solid var(--line)}
.pipe__head,.pipe__row{display:grid;grid-template-columns:minmax(220px,1.35fr) 5fr;align-items:stretch}
.pipe__head{padding:14px 0;border-bottom:1px solid var(--line)}
.pipe__head > span:first-child{font-size:var(--fs-label);font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--fg-2)}
.pipe__phases{display:grid;grid-template-columns:repeat(5,minmax(0,1fr))}
.pipe__phases span{font-size:var(--fs-label);font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--fg-2);text-align:center}
.pipe__row{min-height:84px;border-bottom:1px solid var(--line)}
.pipe__name{padding:18px 16px 18px 0;align-self:center}
.pipe__name b{display:block;font-weight:500;color:var(--ink);font-size:var(--fs-body)}
.pipe__name span{display:block;font-size:var(--fs-small);color:var(--fg-2);margin-top:2px}
.pipe__track{position:relative;background-image:linear-gradient(to right,var(--line-soft) 1px,transparent 1px);background-size:20% 100%;display:flex;align-items:center}
.pipe__bar{height:12px;border-radius:var(--r-pill);background:var(--green);position:relative;margin-left:16px;width:calc(var(--w) - 16px);transform-origin:left center}
.pipe__bar--navy{background:var(--navy)}
.pipe__bar--sky{background:var(--sky)}
.pipe__bar--grey{background:var(--grey)}
.pipe__bar--blue{background:var(--blue)}      /* JUV-112, as on the corporate overview's pipeline slide (3.1:1 on white) */
.pipe__bar--orange{background:var(--orange)}  /* fibroinflammatory, same source (3.1:1 on white) */
.pipe__bar::after{content:attr(data-status);position:absolute;left:100%;top:50%;transform:translate(10px,-50%);white-space:nowrap;font-size:var(--fs-micro);font-weight:500;letter-spacing:.06em;text-transform:uppercase;color:var(--fg-2)}
.pipe__group{padding:28px 0 10px;font-size:var(--fs-label);font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--green-text)}
/* one program, two indications (JUV-161 on the corporate overview's slide 5): the first row keeps the name, the
   second continues it with no hairline between them, so the pair reads as the slide's single band */
.pipe__row--open{border-bottom:0}
.pipe__row--cont{min-height:56px}
.pipe__row--cont .pipe__name{padding-top:0}
.rise.in .pipe__bar{animation:pipegrow 1.1s var(--ease-out) both}
@keyframes pipegrow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@media (prefers-reduced-motion:reduce){.rise.in .pipe__bar{animation:none}}
@media (max-width:760px){
  /* A phase chart shrunk to 390px stops being a chart. Two things had broken:
     the phase header scrolled away, so bars sat over an unlabelled grid; and the
     status word after each bar was hidden to save width, which left colour and
     length as the ONLY carriers of "Phase 2a, enrolling". Colour-alone is not an
     encoding — it fails for colour-blind readers, in forced-colours mode and in
     print. Both are fixed here without touching the markup: one row per program,
     the status word moved under its bar, and the phase scale pinned so it stays
     on screen for every row it labels. */
  .pipe__head,.pipe__row{grid-template-columns:1fr}
  .pipe__head{position:sticky;top:calc(var(--header-h) - 1px);z-index:2;background:var(--white);padding:10px 0}
  .pipe__head > span:first-child{display:none}   /* the "Program" label only — a descendant selector here also hits the first phase header */
  .pipe__phases span{font-size:.62rem;letter-spacing:.04em}
  .pipe__phases span .long{display:none}
  .pipe__phases span::after{content:attr(data-short)}
  .pipe__row{min-height:0;padding-bottom:14px}
  .pipe__name{padding:16px 0 10px}
  .pipe__row--cont{min-height:0}
  .pipe__row--cont .pipe__name{padding-top:4px}
  .pipe__name b{font-size:var(--fs-small)}
  .pipe__name span{font-size:var(--fs-label);letter-spacing:0;text-transform:none}
  .pipe__track{min-height:34px;align-items:flex-start}
  .pipe__bar{margin-left:0;width:var(--w)}
  .pipe__bar::after{left:0;top:100%;transform:translate(0,8px)}
}

/* Stagger the plates. background-position is relative to each element, so every white section
   would otherwise open on the identical top crop of the tile — the tile's empty first 24px as a
   blank strip under each section edge, and on /privacy/ and /pipeline/ a transparent hero showing
   tile-y 0 with the white section below it showing tile-y 0 again, a few hundred pixels apart.
   The tile repeats, so any offset is seamless. :nth-of-type counts SECTION siblings, not white
   ones, so this varies the offset WITHIN a page (a page with two white sections gets -400 and
   -1200); across pages the first white section is usually section 2 and so usually -400, which
   nobody sees side by side. */
.section--white:nth-of-type(4n+2){background-position:50% -400px}
.section--white:nth-of-type(4n+3){background-position:50% -800px}
.section--white:nth-of-type(4n){background-position:50% -1200px}
/* Below 1040px a 1440px tile shows only its quiet middle band, so the network thins out on a
   tablet and all but vanishes on a phone (measured on /news/ at 390: three dots and one arc).
   The tile is scaled rather than re-composed, so the same geometry reads at every width; the ink
   is unchanged, because the alpha lives on the tile group and cannot shift with scale. */
@media (max-width:1040px){body,.section--white{background-size:900px auto}}
/* A decorative network behind 12px text is exactly what these modes ask to be rid of. Chromium
   happens to paint no background image at all under forced-colors (measured under CDP: 17,935
   pattern pixels on /news/ become 0), but CSS Color Adjust 1 only forces NON-url() images to none,
   so the rule is written out rather than inferred. */
@media (prefers-contrast:more),(forced-colors:active){body,.section--white{background-image:none}}
@media print{body{background:var(--soft)}.section--white{background:var(--white)}
  .card,.quote,.figure,.avatar,.avatar--blank{box-shadow:none}}   /* the patterned tile is for the screen; print gets the flat grounds */

/* ---------- forced colours ----------
   Every legibility scrim in this build is a gradient, and forced-colours modes
   do not paint background images — so in that mode the scrims vanish while the
   photograph and the film canvas keep rendering, and system-coloured text is
   left over uncontrolled imagery. Give the surfaces that carry text a solid
   system ground instead. box-shadow spreads that ground past the text box
   without touching layout. */
@media (forced-colors: active){
  .header.on-film::before{background:Canvas;opacity:1}
  .film__readout::before,.pfilm__readout::before{background:Canvas}
  /* box-shadow is stripped in this mode, so the ground is widened with padding
     and cancelled with an equal negative margin — the text does not move. */
  .beat,.pbeat{background:Canvas;padding:12px;margin:-12px}
  .pipe__head{background:Canvas}
  /* the headshots are transparent cutouts on a CSS gradient ground, and
     forced-colors strips gradients. ButtonFace gives the cells a system
     surface, and a CanvasText border guarantees every cell a visible
     boundary in ANY forced theme — photos keep their natural colors in
     this mode, so a dark-haired portrait on a dark forced ground would
     otherwise lose its edge entirely. */
  .avatar,.avatar--blank{background:ButtonFace;border:1px solid CanvasText}
  /* the pipeline bars are data, not decoration: with their background stripped the
     chart kept only its status words. They take the text colour of whatever theme
     is active; bullets and marker dots keep a visible boundary. */
  .pipe__bar{forced-color-adjust:none;background:CanvasText}
  .timeline__item::before,.checklist li::before,.mk__dot{border:1px solid CanvasText}
  /* dark brand marks on a black forced canvas are invisible: give each a white plate */
  .logo-row img{forced-color-adjust:none;filter:none;background:#fff;height:46px;padding:6px 10px;border-radius:var(--r-sm);border:1px solid CanvasText}
  .logo-row img.logo--wide{height:32px}
}

/* ---------- footer ---------- */
.footer{background:var(--charcoal);color:var(--on-dark-2);padding:clamp(64px,8vw,104px) 0 40px}
.footer a:hover{color:#fff}
.footer__top{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:40px;padding-bottom:56px;border-bottom:1px solid var(--line-dark)}
.footer__brand img{height:48px;width:auto;margin-bottom:22px}
.footer__brand p{max-width:34ch;font-size:var(--fs-small);color:var(--on-dark-3)}
.footer h4{font-size:var(--fs-label);font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--on-dark-3);margin-bottom:18px}
.footer li+li{margin-top:10px}
.footer li a{font-size:var(--fs-small);color:var(--on-dark-2)}
.footer__bottom{display:flex;flex-wrap:wrap;gap:16px 32px;justify-content:space-between;align-items:center;padding-top:28px;font-size:var(--fs-micro);color:var(--on-dark-3)}
.footer__bottom ul{display:flex;gap:22px}
.footer__bottom li+li{margin:0}
.footer__social{display:inline-flex;align-items:center;gap:8px;color:var(--on-dark-2)}
.footer__social svg{width:18px;height:18px}
.disclaimer{font-size:var(--fs-micro);color:var(--on-dark-3);max-width:90ch;line-height:1.55;margin-top:22px}
@media (max-width:900px){.footer__top{grid-template-columns:1fr 1fr}}
@media (max-width:520px){.footer__top{grid-template-columns:1fr}.footer__bottom ul{flex-wrap:wrap;gap:8px 18px}.footer__bottom li a{white-space:nowrap}}

/* ---------- home after-film components ---------- */
.teaser-art{position:relative;aspect-ratio:1;max-width:560px;margin-inline:auto;width:100%;overflow:visible}
.section--dark,.section--soft,.section--white{overflow:hidden}
/* overflow:hidden makes an element a scroll container, which silently kills
   position:sticky for everything inside it — that is why the pipeline chart's
   phase scale scrolled away on mobile. overflow:clip clips identically
   without creating one. Guarded by @supports, so a browser without it keeps
   the hidden behaviour and simply loses the pinned scale. */
@supports (overflow:clip){.section--dark,.section--soft,.section--white{overflow:clip}}
.teaser-art img{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);height:auto}
.teaser-art__ring{width:118%;max-width:none;opacity:.9}
.teaser-art__mol{width:66%;filter:drop-shadow(0 30px 50px rgba(0,0,0,.45))}
.quote{background:var(--white);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-sm);padding:clamp(28px,4vw,48px)}
.quote blockquote{font-size:var(--fs-lead);font-weight:300;line-height:1.5;color:var(--ink);letter-spacing:-.005em}
.quote figcaption{display:flex;align-items:center;gap:20px;margin-top:28px;padding-top:24px;border-top:1px solid var(--line);font-size:var(--fs-small);color:var(--fg-2)}
.quote figcaption img{height:44px;width:auto}
.quote figcaption b{color:var(--ink);font-weight:500}
/* A figure with a ratio of its own crops the picture to it (object-fit:cover). That is right for a
   scene photo taller than its box — it loses sky, not subject. It is wrong for a picture WIDER than
   its box, because cover then crops the sides: the founders photo is 1126x654 (1.72:1) and a 4/3 box
   took 11.3% off each edge, cutting Jeremy's face at the left frame and Thach's at the right
   (session 19b). --asis lets the picture keep its own shape; use it for any photograph whose edges
   carry the subject. */
.figure--asis{aspect-ratio:auto}
.figure--asis img{height:auto}
.news-grid .card{display:flex;flex-direction:column}
.news-grid .card .h3{font-size:1.125rem;line-height:1.35;margin-top:10px;flex:1}

/* ---------- platform page components ---------- */
.steps{display:grid;grid-template-columns:1fr;gap:0}
.steps__phase{padding:28px 0 18px;border-top:1px solid var(--line)}
.steps__list{list-style:none;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(20px,3vw,40px);padding-bottom:44px} /* the 01–08 labels are the numbering; browser markers doubled them */
.steps__list li{position:relative;padding-top:18px;border-top:1px solid var(--line)}
.steps__list li b{display:block;font-size:var(--fs-label);font-weight:500;letter-spacing:.12em;color:var(--green-text);margin-bottom:14px}
.steps__list li .h3{font-size:1.125rem;margin-bottom:8px}
.steps__list li p{font-size:var(--fs-small);color:var(--fg-2)}
@media (max-width:900px){.steps__list{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:520px){.steps__list{grid-template-columns:1fr}}
.checklist{margin-top:14px}
.checklist li{position:relative;padding:10px 0 10px 28px;border-bottom:1px solid var(--line);font-size:var(--fs-body)}
.checklist li::before{content:"";position:absolute;left:2px;top:18px;width:10px;height:10px;border-radius:50%;background:var(--green)}
.refs{margin-top:20px;columns:2;column-gap:48px}
.refs li{font-size:var(--fs-small);line-height:1.5;padding:8px 0;border-bottom:1px solid var(--line);break-inside:avoid}
.refs a{color:var(--green-text)} /* teal #0097A7 measured 3.16:1 on the soft ground */
.refs a:hover{text-decoration:underline}
@media (max-width:760px){.refs{columns:1}}

/* ---------- people ---------- */
.subnav{display:flex;flex-wrap:wrap;gap:8px 22px;margin-top:36px}
.subnav a{font-size:var(--fs-small);font-weight:500;color:var(--fg-2);padding-bottom:4px;border-bottom:1px solid var(--line)}
.subnav a:hover{color:var(--ink);border-color:var(--ink)}
.people{display:grid;gap:clamp(24px,3vw,40px)}
.people--lead{grid-template-columns:repeat(3,minmax(0,1fr))}
.people--grid{grid-template-columns:repeat(4,minmax(0,1fr))}
.people--dense{grid-template-columns:repeat(6,minmax(0,1fr));gap:20px}
.person .avatar{border-radius:var(--r-lg)}
.avatar--blank{width:100%;aspect-ratio:1;border-radius:var(--r-lg);background:var(--white);box-shadow:var(--shadow-sm)}
.person__body{padding-top:16px}
.person__name{font-size:1.125rem;font-weight:500;line-height:1.3;color:var(--ink)}
.nowrap{white-space:nowrap}
.person--xs .person__name{font-size:.9375rem}
.person__li{display:inline-flex;vertical-align:-1px;margin-left:8px;color:var(--fg-3)}
.person__li svg{width:14px;height:14px}
.person__li:hover{color:var(--green-text)}
.person__title{font-size:var(--fs-small);color:var(--fg-2);margin-top:4px;line-height:1.45}
.person--xs .person__title{font-size:var(--fs-label);letter-spacing:0;text-transform:none}
.person__bio{margin-top:12px;color:var(--fg-1);line-height:1.55}
@media (max-width:1000px){.people--lead{grid-template-columns:repeat(2,minmax(0,1fr))}.people--grid{grid-template-columns:repeat(3,minmax(0,1fr))}.people--dense{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media (max-width:620px){.people--lead{grid-template-columns:1fr}.people--grid{grid-template-columns:repeat(2,minmax(0,1fr))}.people--dense{grid-template-columns:repeat(2,minmax(0,1fr))}}

/* ---------- news: year filter + publications index ---------- */
.filter{display:flex;flex-wrap:wrap;gap:8px}
.filter__btn{display:inline-flex;align-items:center;font-size:var(--fs-label);font-weight:500;letter-spacing:.06em;text-transform:uppercase;padding:8px 14px;border-radius:var(--r-pill);border:1px solid var(--line);color:var(--fg-2);background:var(--white);transition:border-color .25s,color .25s,background .25s}
.filter__btn:hover{border-color:var(--ink);color:var(--ink)}
.filter__btn[aria-pressed="true"]{border-color:var(--ink);background:var(--ink);color:#fff} /* ink, not green: a pressed pill is state, and the accent budget is two per viewport */
.pubs{margin-top:16px}
.pub{display:flex;flex-direction:column;gap:4px;padding:14px 0;border-top:1px solid var(--line)}
.pub__meta{font-size:var(--fs-label);font-weight:500;letter-spacing:.06em;text-transform:uppercase;color:var(--fg-2)}
.pub__title{font-size:var(--fs-body);line-height:1.45;color:var(--ink);font-weight:400}
.pub__title:hover{color:var(--green-text)}
.pub__title svg{display:inline;width:14px;height:14px;vertical-align:-2px;color:var(--fg-3)}
.pub__authors{font-size:var(--fs-small);color:var(--fg-2)}
.pubs--compact .pub{padding:10px 0}

/* ---------- news lists ---------- */
.newsyear{display:grid;grid-template-columns:120px 1fr;gap:24px;padding:28px 0;border-top:1px solid var(--line)}
.newsyear__y{font-size:var(--fs-h3);font-weight:300;color:var(--fg-2);letter-spacing:-.01em}
.newslist li+li{border-top:1px solid var(--line-soft)}
.newsitem a,.newsitem>div{display:grid;grid-template-columns:130px 1fr 18px;gap:18px;align-items:start;padding:14px 0;color:var(--ink)}
.newsitem a:hover .newsitem__title{color:var(--green-text)}
.newsitem svg{width:16px;height:16px;color:var(--fg-3);margin-top:4px}
.newsitem__date{font-size:var(--fs-small);color:var(--fg-2);padding-top:2px}
.newsitem__title{font-size:var(--fs-body);line-height:1.45;transition:color .25s}
@media (max-width:700px){.newsyear{grid-template-columns:1fr;gap:8px}.newsitem a,.newsitem>div{grid-template-columns:1fr 18px}.newsitem__date{grid-column:1/-1}}

/* ---------- timeline ---------- */
.timeline{border-left:1px solid var(--line);padding-left:22px}
.timeline__item{position:relative;padding:0 0 18px}
.timeline__item::before{content:"";position:absolute;left:-27px;top:8px;width:9px;height:9px;border-radius:50%;background:var(--fg-3)}
.timeline__item--now::before{background:var(--green);box-shadow:0 0 0 4px var(--tint)}
.timeline__item b{display:block;font-size:var(--fs-label);font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--fg-2);margin-bottom:4px}
.timeline__item--now b{color:var(--green-text)}
.timeline__item span{font-size:var(--fs-small);color:var(--fg-1);line-height:1.55}
.page-hero .subnav{margin-top:32px}

/* ---- deferred third-party map (loaded on request; see privacy policy) ---- */
.mapembed{display:block}
.mapembed__ph{display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:14px;min-height:360px;padding:32px;background:var(--panel);border-bottom:1px solid var(--line)}
/* measured 4.32:1 for fg-2 on the panel grey — the placeholder copy and its label take fg-1 (9.5:1) */
.mapembed__ph .small,.mapembed__ph .label--grey{color:var(--fg-1)}
.mapembed__ph .btn-row{margin-top:4px}
.mapembed iframe{border:0;display:block;width:100%;height:360px}
