/* =====================================================================
   Chory Lab site styles.

   Every selector is declared once, apart from 16 pairs that are split by
   a media query on the same selector (marked "cascade pair"). Do NOT
   append override blocks at the bottom of this file: edit the canonical
   rule in place, or the cascade stops being possible to reason about.
   Sizes come from the scale below, not from ad-hoc px values.

   Geometric display type matches the lab wordmark; flat full-bleed
   imagery, no radii or shadows; scroll path kept repaint-free.
   ===================================================================== */
:root {
  /* Brand color */
  --navy: #16244d;              /* header, footer, dark bands */
  --navy-deep: #0d1730;         /* deepest background */
  --navy-2: #1e3a6e;            /* gradient partner */
  --blue: #1272b8;              /* accent, matches logo blue */
  --blue-light: #7fb2e5;        /* highlights on dark */
  --ink: #131a2b;               /* body text */
  --muted: #5c6579;             /* secondary text */
  --line: #e2e7f0;              /* hairlines */
  --bg: #ffffff;                /* page background */
  --bg-soft: #f4f7fb;           /* alternating band */

  /* Dark-field ramp. Every dark band used to be the identical navy, so no
     page had a landmark to distinguish it. Same hue family, real value
     range: deepest for hero and footer, mid for split bands, lifted where
     a band has to separate from the dark band directly above it. */
  --navy-950: #080f21;
  --navy-900: #0d1730;
  --navy-800: #16244d;
  --navy-700: #1c3160;
  --navy-600: #24406f;

  /* Light-field ramp, so .alt is not the only alternative to white */
  --bg-tint: #f8fafd;
  --bg-soft-2: #eaf0f8;

  /* Type */
  --font-display: "Jost", "Century Gothic", "Futura", sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Type scale, ratio ~1.22. Sizes used to cluster between 14px and 21px,
     which left the page with almost no size contrast. These are the only
     sizes that should appear from here on. --fs-4 and up are fluid. */
  --fs-micro: 11px;                   /* counts, tags */
  --fs--2: 12.5px;                    /* all-caps labels */
  --fs--1: 13.5px;                    /* captions, meta, fine print */
  --fs-0: 15px;                       /* small body, card copy */
  --fs-1: 17px;                       /* body */
  --fs-2: 20px;                       /* large body, list titles */
  --fs-3: 24px;                       /* lead paragraph */
  --fs-4: clamp(21px, 2.3vw, 28px);   /* minor section title */
  --fs-5: clamp(27px, 3.4vw, 40px);   /* section title */
  --fs-6: clamp(31px, 4.4vw, 52px);   /* page title */
  --fs-7: clamp(36px, 5.6vw, 68px);   /* hero display */

  /* Weights. Large display reads better light; small caps need 500. */
  --fw-light: 300;
  --fw-book: 400;
  --fw-med: 500;
  --fw-semi: 600;

  /* Tracking */
  --tr-tight: -.025em;
  --tr-snug: -.015em;
  --tr-caps: .14em;             /* was .18em to .2em, which was shouty */

  /* Layout */
  --maxw: 1180px;
  --maxw-wide: 1340px;          /* figures that break out of the text column */
  --maxw-text: 720px;           /* comfortable measure for prose */
  --gutter: 28px;

  /* Vertical rhythm. A single 108px band everywhere made every page
     metronome; these give sections more than one weight to sit at. */
  --band: 74px;
  --band-lg: 100px;
  --band-sm: 48px;
  --band-xs: 32px;

  /* Motion */
  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  /* Reveal travel. Was 22px, which is far enough that an element is still
     sliding while the page itself is moving. Two competing motions at once is
     what reads as bumpy and is the usual cause of scroll-induced queasiness.
     8px still registers as "it arrived" without racing the scroll. */
  --reveal-shift: 8px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: var(--font-body); font-size: var(--fs-1); line-height: 1.7;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }

h1, h2, h3, .section-title, .brand {
  font-family: var(--font-display); font-weight: var(--fw-med);
  letter-spacing: var(--tr-snug); line-height: 1.12; color: var(--ink);
}

/* ===================== Section header components =====================
   One device, the small blue all-caps label sitting on a 2px navy bar,
   used to carry almost every section header on the site: ten separate
   near-identical implementations. At that density it stopped reading as
   emphasis and started reading as a template. Three tiers now, so the
   page has a hierarchy instead of one repeated note.

   .lbl-rule   group label on a hairline. The workhorse, but 1px and
               navy rather than 2px and blue, so it recedes.
   .lbl        the same label with no rule, for subordinate groupings.
   .lbl-strong retains the heavier treatment, reserved for the one
               header on a page that should actually announce itself.

   Existing class names are kept and pointed at these, so no generated
   page or template has to change.                                     */
.lbl, .lbl-rule, .lbl-strong,
.member-group h2, .funders h2, .pub-section-title, .cv-heading,
.news-section-label, .photo-year, .give h2, .useful-links h2,
.pi-section h2, .feed-head h2, .jobs h2, .acc-body h3, .cv-subheading {
  font-family: var(--font-display); font-size: var(--fs--2);
  font-weight: var(--fw-med); letter-spacing: var(--tr-caps);
  text-transform: uppercase;
}

/* Tier 2: label on a hairline. Applied to the page-structuring headers. */
.lbl-rule,
.member-group h2, .funders h2, .pub-section-title,
.cv-heading, .news-section-label, .photo-year {
  display: block; color: var(--navy); opacity: .92;
  padding-bottom: 11px; margin: 0 0 18px;
  border-bottom: 1px solid var(--line);
}

/* Tier 3: no rule at all. These sat inside a panel or a prose column,
   where a second horizontal line was just noise. */
.lbl,
.give h2, .useful-links h2, .pi-section h2, .feed-head h2,
.jobs h2, .acc-body h3, .cv-subheading {
  display: block; color: var(--blue); border-bottom: 0;
  padding-bottom: 0; margin: 0 0 14px;
}

/* Tier 1: reserved, opt-in. */
.lbl-strong {
  display: block; color: var(--blue);
  padding-bottom: 13px; margin: 0 0 20px;
  border-bottom: 2px solid var(--navy);
}

/* =========================== Header / nav =========================== */
/* Solid background: no backdrop-filter, no height change on scroll, so
   scrolling never triggers a repaint of the whole viewport. */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--navy); color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,.06);
  transition: box-shadow .3s var(--ease);
}
.site-header.scrolled { box-shadow: 0 8px 30px rgba(8, 15, 35, .32); }
.nav { display: flex; align-items: center; gap: 30px; height: 76px; }
.nav .brand { display: flex; align-items: center; flex-shrink: 0; }
.nav .brand img { height: 40px; width: auto; }
.nav .brand span { display: none; }        /* wordmark art replaces the text lockup */
.nav .links { display: flex; align-items: center; gap: 26px; }
.nav .links > a, .nav .links .dd-toggle {
  position: relative; padding: 6px 0;
  color: #ccd8ec; font-family: var(--font-display);
  font-size: var(--fs-0); font-weight: 400; letter-spacing: .01em;
  transition: color .25s var(--ease);
}
.nav .links > a:hover, .nav .links .dd-toggle:hover,
.nav .dropdown:hover .dd-toggle { color: #fff; text-decoration: none; }
.nav .links > a::after, .nav .links .dd-toggle::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1.5px;
  background: var(--blue-light); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .3s var(--ease);
}
.nav .links > a:hover::after, .nav .links > a.active::after,
.nav .dropdown:hover .dd-toggle::after, .dd-toggle.active::after { transform: scaleX(1); }
.nav .links > a.active, .dd-toggle.active { color: #fff; }
.nav .spacer { flex: 1; }
.nav .actions { display: flex; align-items: center; gap: 18px; }
.nav .actions a { color: #ccd8ec; font-size: var(--fs--1); transition: color .25s var(--ease); }
.nav .actions a:hover { color: #fff; text-decoration: none; }
.btn-donate {
  background: var(--blue); color: #fff !important; padding: 9px 20px;
  border-radius: 2px; font-weight: 500; font-family: var(--font-display);
  letter-spacing: .02em; transition: background .25s var(--ease);
}
.btn-donate:hover { background: var(--blue-light); color: var(--navy) !important; text-decoration: none; }
.nav-toggle { display: none; background: none; border: 0; color: #fff; font-size: 22px; cursor: pointer; }

/* Internal Portal is a door to a different site, not another public section,
   so it reads as a button rather than a fifth peer link. Outlined, not filled:
   the filled blue is Donate's, and two solid buttons side by side would fight.
   Padding is identical in every state, so nothing reflows on hover. */
.nav .links a.btn-portal, .nav .links .dd-toggle.btn-portal {
  padding: 8px 16px; border: 1px solid rgba(255,255,255,.34); border-radius: 2px;
  color: #dbe6f6; font-weight: 500;
  transition: background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease);
}
.nav .links a.btn-portal::after, .nav .links .dd-toggle.btn-portal::after { display: none; }
.nav .links a.btn-portal:hover,
.nav .links .dropdown:hover .dd-toggle.btn-portal,
.nav .links .dd-toggle.btn-portal.active {
  background: rgba(127,178,229,.16); border-color: var(--blue-light); color: #fff;
  text-decoration: none;
}

/* Dropdowns */
.nav .links .dropdown { position: relative; display: inline-flex; align-items: center; }
.nav .links .dd-toggle { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.nav .links .dd-toggle .chev { font-size: 9px; transition: transform .3s var(--ease); }
.nav .links .dropdown:hover .dd-toggle .chev { transform: rotate(180deg); }
.nav .links .dropdown-menu {
  position: absolute; top: 100%; left: -16px; min-width: 216px; padding: 10px;
  background: var(--navy-deep); border-top: 2px solid var(--blue);
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .25s var(--ease), transform .25s var(--ease), visibility .25s;
  z-index: 60;
}
.nav .links .dropdown:hover .dropdown-menu,
.nav .links .dropdown.open .dropdown-menu { opacity: 1; visibility: visible; transform: translateY(0); }
.nav .links .dropdown-menu a::after { display: none; }

/* Section labels inside a long dropdown (the Internal Portal menu). Sixteen
   undifferentiated rows had no shape; the labels give it one. The menu is also
   capped and scrollable, because on a laptop 16 rows plus labels is taller
   than the viewport below the header. */
.nav .links .dropdown-menu.dd-sectioned {
  max-height: calc(100vh - 96px); overflow-y: auto; overscroll-behavior: contain;
}
.nav .links .dropdown-menu .dd-group {
  display: block; margin-top: 8px; padding: 12px 14px 5px;
  border-top: 1px solid rgba(255,255,255,.10);
  font-family: var(--font-display); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--tr-caps); text-transform: uppercase; color: #8ea5c6;
}
.nav .links .dropdown-menu .dd-group:first-child {
  margin-top: 0; border-top: 0; padding-top: 4px;
}

/* Inline status on a menu item, e.g. Data Portal (coming soon). Muted enough
   to read as a note rather than part of the label. */
.nav .links .dropdown-menu a .dd-soon {
  color: #8ea5c6; font-size: var(--fs-micro); letter-spacing: .02em; margin-left: 4px;
}
.nav .links .dropdown-menu a:hover .dd-soon { color: #cfdcf0; }

/* One level of nesting inside a dropdown. Flies out to the right on desktop;
   below 820px the whole nav is a stacked list, so it just indents (see the
   820px block). Hover-only by design, matching the parent dropdown. */
.nav .links .submenu { position: relative; }
.nav .links .submenu > .submenu-toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.nav .links .submenu > .submenu-toggle .chev {
  font-size: 9px; transition: transform .3s var(--ease);
}
.nav .links .submenu-menu {
  position: absolute; top: -10px; left: 100%; min-width: 216px; padding: 10px;
  background: var(--navy-deep); border-top: 2px solid var(--blue);
  opacity: 0; visibility: hidden; transform: translateX(-6px);
  transition: opacity .25s var(--ease), transform .25s var(--ease), visibility .25s;
  z-index: 61;
}
.nav .links .submenu:hover > .submenu-menu,
.nav .links .submenu.open > .submenu-menu { opacity: 1; visibility: visible; transform: translateX(0); }
.nav .links .submenu:hover > .submenu-toggle { background: rgba(127,178,229,.12); color: #fff; }
.nav .links .dropdown-menu a:hover { background: rgba(127,178,229,.12); color: #fff; text-decoration: none; }

/* Scroll progress */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 100;
  background: var(--blue); transform: scaleX(0); transform-origin: 0 50%;
}

/* ================================ Hero ============================== */
.hero {
  position: relative; min-height: clamp(400px, 64vh, 620px); display: flex; align-items: center;
  justify-content: center; text-align: center; color: #fff;
  background: var(--navy-950); overflow: hidden;
}
.hero .bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .5; will-change: transform;
}
.hero video.bg { pointer-events: none; }
/* The credit sits over the footage, above the gradient. */
.hero .media-credit { z-index: 2; }
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(9,16,36,.55) 0%, rgba(9,16,36,.35) 45%, rgba(9,16,36,.85) 100%);
}
.hero h1 {
  font-size: clamp(34px, 5.6vw, 68px); font-weight: 400; letter-spacing: -.025em;
  line-height: 1.06; margin: 0 0 22px; color: #fff;
}
.hero .sub {
  font-family: var(--font-display); font-size: var(--fs--2); font-weight: 400;
  letter-spacing: .28em; text-transform: uppercase; color: var(--blue-light);
}
.hero-ready h1 { animation: rise .9s var(--ease-out) both; }
.hero-ready .sub { animation: rise .9s var(--ease-out) .15s both; }
@keyframes rise { from { opacity: 0; transform: translate3d(0, 24px, 0); } to { opacity: 1; transform: none; } }

/* Scroll cue */
.hero .scroll-cue {
  position: absolute; left: 50%; bottom: 34px; z-index: 2; margin-left: -9px;
  width: 18px; height: 30px; border: 1.5px solid rgba(255,255,255,.5); border-radius: 10px;
}
.hero .scroll-cue::after {
  content: ""; position: absolute; left: 50%; top: 7px; margin-left: -1.5px;
  width: 3px; height: 6px; background: #fff; border-radius: 2px;
  animation: cue 1.9s var(--ease) infinite;
}
@keyframes cue { 0% { opacity: 0; transform: translate3d(0,0,0); } 35% { opacity: 1; } 75% { opacity: 1; transform: translate3d(0,10px,0); } 100% { opacity: 0; transform: translate3d(0,10px,0); } }

/* ============================== Sections ============================ */
section.block { padding: var(--band) 0; border-bottom: 0; position: relative; }
section.block.alt { background: var(--bg-soft); }

/* Rhythm and field variants. Every section used to be one 108px band
   alternating white and --bg-soft, which made every page metronome at a
   fixed 1:1 beat. These let a page group two sections into one field, or
   run a tight section against a loose one. */
section.block.tight { padding: var(--band-sm) 0; }
section.block.loose { padding: var(--band-lg) 0; }
section.block.pad-top-0 { padding-top: 0; }
section.block.pad-bot-0 { padding-bottom: 0; }
section.block.tint { background: var(--bg-tint); }
section.block.soft-2 { background: var(--bg-soft-2); }

/* Section titles carry the contrast. They were 42px/400 against an 18.5px
   lead, a step too small to establish hierarchy; the jump is the point. */
.section-title {
  font-size: var(--fs-6); font-weight: var(--fw-light); margin: 0 0 20px;
  letter-spacing: var(--tr-tight);
}
/* Secondary tier, for a section that should not compete with the one above */
.section-title.minor {
  font-size: var(--fs-4); font-weight: var(--fw-book);
  letter-spacing: var(--tr-snug);
}

/* Supporting copy, one clear step above body without becoming a deck.
   Use .lede for an actual deck paragraph. */
.section-lead {
  color: var(--muted); font-size: clamp(16px, 1.45vw, 18.5px); font-weight: var(--fw-book);
  line-height: 1.55; letter-spacing: -.005em;
  max-width: var(--maxw-text); margin: 0 0 22px;
}

/* ===================== Asymmetric section head =======================
   Title stacked above a full-width lead, repeated down a page, gives
   every section the same silhouette. This sets the title in a narrow
   left column against the copy on the right, so the page gains a spine
   and the measure stays readable instead of running the full 1180px.
   Nothing here moves or reflows; it is a static two-column grid.      */
.sec-head {
  display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: 24px 72px; align-items: start; margin-bottom: 30px;
}
.sec-head > :first-child { min-width: 0; }
/* A title in the 4fr column is doing a different job from one running the full
   width, and at --fs-6 a four-word question wrapped to four lines and towered
   over the paragraph beside it. That got worse when .section-lead dropped from
   20px to fluid: the ratio went from 52/20 to 52/18.5. One step down restores
   it, and matches what .sec-head.stack already did. text-wrap: balance evens
   the lines out so a single short word is not left stranded on the last one. */
.sec-head .section-title {
  margin: 0; font-size: var(--fs-5); text-wrap: balance;
}
.sec-head .section-lead,
.sec-head .section-lead.wide { max-width: none; margin: 0 0 18px; }
.sec-head .section-lead:last-child { margin-bottom: 0; }
/* Hairline aligning the two columns on a shared baseline */
.sec-head.ruled { padding-top: 26px; border-top: 1px solid var(--line); }

/* Stacked variant. The split only works when the copy is about a paragraph;
   for several paragraphs against a short title the left column is left empty.
   Here the title is a touch smaller and the copy flows in two columns across
   the page, so it uses the width instead of clumping into a tall narrow block
   on the left. Collapses to one column below 760px. */
.sec-head.stack { grid-template-columns: 1fr; gap: 18px; }
.sec-head.stack .section-title { font-size: var(--fs-5); }
.sec-head.stack > :not(.section-title) {
  max-width: none; columns: 2 320px; column-gap: 60px;
}
.sec-head.stack .section-lead,
.sec-head.stack .section-lead.wide {
  max-width: none; margin: 0 0 16px; break-inside: avoid;
}

@media (max-width: 900px) {
  .sec-head { grid-template-columns: 1fr; gap: 18px; margin-bottom: 28px; }
}

/* Figure groups that break out past the text column. The figures were
   pinned to the 1180px wrap and floated in the middle at small scale,
   which wasted the page width and made diagrams hard to read. */
.bleed-wide {
  max-width: var(--maxw-wide); margin-left: auto; margin-right: auto;
  padding: 0 var(--gutter);
}
.centered { max-width: 800px; margin: 0 auto; text-align: center; }
.centered .section-lead { margin-left: auto; margin-right: auto; }

/* Editorial split. Images sit flat, no frame, no radius. */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 72px; align-items: center; }
.two-col img { border-radius: 0; box-shadow: none; width: 100%; }
.two-col.rev { grid-template-columns: 1fr 1fr; }
.two-col.rev > :first-child { order: 2; }
.two-col.rev > :last-child { order: 1; }

/* Group photo beside the Join us copy on the home page. */
.join-figure { margin: 0; }
.join-figure img { width: 100%; height: auto; display: block; }

/* CTA: flat, squared, understated */
.cta {
  display: inline-block; margin-top: 8px; padding: 13px 30px;
  background: var(--navy); color: #fff; border-radius: 2px;
  font-family: var(--font-display); font-size: var(--fs-0); font-weight: 500;
  letter-spacing: .02em;
  transition: background .28s var(--ease), transform .28s var(--ease);
}
.cta:hover { background: var(--blue); color: #fff; text-decoration: none; transform: translate3d(0,-2px,0); }

/* A row of two CTAs, e.g. a primary action next to a lighter secondary one. */
.cta-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin-top: 8px; }
.centered .cta-row { justify-content: center; }
.cta.cta-sm {
  padding: 9px 20px; font-size: var(--fs--1);
  background: none; color: var(--navy); border: 1px solid var(--line);
}
.cta.cta-sm:hover { background: var(--navy); color: #fff; border-color: var(--navy); }

/* Placeholder pages (Data portal, Learning resources). The badge says the page
   is intentionally empty rather than broken. */
.soon-badge {
  display: inline-block; margin-bottom: 16px; padding: 5px 12px;
  border: 1px solid var(--line); border-radius: 2px;
  font-family: var(--font-display); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--tr-caps); text-transform: uppercase; color: var(--blue);
}

/* Quiet hand-off at the foot of a section: "and the next thing is over here".
   A second filled .cta after a card grid competes with the cards; this reads
   as a footnote. Colour-only hover, so nothing reflows. */
.sec-more {
  margin: 34px 0 0; padding-top: 20px; border-top: 1px solid var(--line);
  text-align: right;
}
.sec-more a {
  font-family: var(--font-display); font-size: var(--fs-0); font-weight: 500;
  color: var(--navy); letter-spacing: .01em; transition: color .25s var(--ease);
}
.sec-more a:hover { color: var(--blue); text-decoration: none; }
.sec-more .chev-r { color: var(--blue); margin-left: 8px; }

/* Pull quote */
.quote {
  text-align: center; font-family: var(--font-display); font-size: clamp(22px, 3vw, 34px);
  font-weight: 300; font-style: normal; line-height: 1.35; letter-spacing: -.015em;
  max-width: 900px; margin: 0 auto; color: var(--ink);
}
.quote cite {
  display: block; margin-top: 20px; font-family: var(--font-body);
  font-size: var(--fs--2); font-style: normal; letter-spacing: .22em;
  text-transform: uppercase; color: var(--muted);
}

/* ===================== Full-bleed split band ========================
   Photos get a half-width bleed to the page edge on a solid dark field,
   with light text opposite. Diagrams stay contained on light sections.
   The image is oversized inside its frame and translated on scroll, so
   it drifts across the page without ever affecting layout.            */
.split {
  display: grid; grid-template-columns: 1fr 1fr; align-items: stretch;
  min-height: 520px; background: var(--navy-800); color: #fff; overflow: hidden;
}
/* Lifted field, for a split that sits directly against another dark band */
.split.deep { background: var(--navy-900); }
.split.lift { background: var(--navy-700); }
.split.rev .split-media { order: 2; }
.split-media { position: relative; overflow: hidden; min-height: 340px; }
.split-media img {
  position: absolute; left: 0; top: -12%;
  width: 100%; height: 124%; object-fit: cover;
  border-radius: 0; box-shadow: none; will-change: transform;
}
/* Soft seam so the photo melts into the color field instead of butting it */
.split-media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg, transparent 62%, rgba(22,36,77,.55) 100%);
}
.split.rev .split-media::after {
  background: linear-gradient(270deg, transparent 62%, rgba(22,36,77,.55) 100%);
}
.split-body {
  display: flex; align-items: center;
  padding: 64px clamp(26px, 4vw, 64px);
}
.split:not(.rev) .split-body { justify-content: flex-start; }
.split.rev .split-body { order: 1; justify-content: flex-end; }
.split-inner { max-width: 520px; }
.split .section-title { color: #fff; }
.split .section-lead { color: #b9c9e2; max-width: none; }
.split p { color: #b9c9e2; }
.split a:not(.cta) { color: var(--blue-light); }
.split .cta { background: var(--blue); color: #fff; }
.split .cta:hover { background: #fff; color: var(--navy); }
.split .eyebrow {
  display: block; font-family: var(--font-display); font-size: var(--fs--2);
  font-weight: 500; letter-spacing: .24em; text-transform: uppercase;
  color: var(--blue-light); margin: 0 0 14px;
}

/* Full-bleed image band */
.fullbleed { line-height: 0; overflow: hidden; }

/* Marquee ticker band */
.marquee {
  background: var(--navy-900); color: #fff; padding: 26px 0;
  overflow: hidden; white-space: nowrap;
}
.marquee-track { display: inline-flex; align-items: center; animation: slide 42s linear infinite; }
.marquee span {
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: 300;
  letter-spacing: .02em; padding: 0 30px; color: #dbe6f6;
}
.marquee span::after { content: "\00B7"; margin-left: 30px; color: var(--blue-light); }
@keyframes slide { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
.marquee:hover .marquee-track { animation-play-state: paused; }

/* ============================== Cards =============================== */
/* Flat: hairline rule instead of an outset box. */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 2px 44px; margin-top: 12px; }
.card {
  background: none; border: 0; border-top: 1.5px solid var(--line);
  border-radius: 0; padding: 22px 0 26px;
  transition: border-color .3s var(--ease);
}
.card:hover { border-top-color: var(--blue); transform: none; box-shadow: none; }
.card h3 {
  margin: 0 0 8px; font-size: var(--fs-2); font-weight: 500; color: var(--navy);
  letter-spacing: -.01em;
}
.card p { margin: 0; font-size: var(--fs-0); color: var(--muted); line-height: 1.65; }

/* Image cards: photo bleeds, caption sits underneath, no frame */
.card.imgcard { padding: 0; border-top: 0; overflow: hidden; }
.card.imgcard:hover img { transform: scale3d(1.05, 1.05, 1); }
.card.imgcard .body { padding: 18px 0 0; }
.card.imgcard h3 { margin: 0 0 4px; }
.imgcard-figure { overflow: hidden; }

/* Methods: round icons, flat */
.methods { display: grid; grid-template-columns: repeat(4, 1fr); gap: 40px; margin-top: 20px; }
.method { text-align: center; }
.method:hover img { transform: translate3d(0,-5px,0); }

/* ============================== People ==============================
   Each member is a horizontal record: portrait left, labeled detail
   fields right. Flat, no boxes, separated by hairlines.               */
.member-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 56px; }

.member-card {
  display: grid; grid-template-columns: 132px 1fr; gap: 26px;
  align-items: start; padding: 34px 0; border-bottom: 1px solid var(--line);
}
.member-photo { position: relative; }
.member-card:hover .headshot { transform: translate3d(0,-4px,0); }
.headshot.placeholder {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 40px; font-weight: 400;
  letter-spacing: .02em; color: #fff;
  background: linear-gradient(140deg, var(--navy-2), var(--navy));
}
.member-role {
  color: var(--blue); font-weight: 500; font-size: var(--fs--2);
  letter-spacing: .1em; text-transform: uppercase; margin: 0 0 14px;
}

/* Degrees: compact stacked list */
.member-degrees { list-style: none; padding: 0; margin: 0 0 14px; }
.member-degrees li {
  font-size: var(--fs--1); color: var(--muted); line-height: 1.5;
  padding-left: 14px; position: relative;
}
.member-degrees li::before {
  content: ""; position: absolute; left: 0; top: 9px;
  width: 5px; height: 5px; background: var(--blue-light); border-radius: 50%;
}

/* Fellowship / award callout */
/* Sits directly under the role now, so it needs a little air above it and
   less below, where the degree list follows. */
.member-award {
  display: inline-block; margin: 2px 0 12px; padding: 7px 13px;
  background: #eaf2fb; color: #10457a; border-left: 3px solid var(--blue);
  font-size: var(--fs--2); font-weight: 500; line-height: 1.45;
}

/* Labeled detail rows */
.member-field { margin: 0 0 11px; }
.member-field .field-label {
  display: block; font-family: var(--font-display); font-size: var(--fs-micro);
  font-weight: 500; letter-spacing: .16em; text-transform: uppercase;
  color: var(--navy); opacity: .55; margin-bottom: 3px;
}
.member-field .field-value { display: block; font-size: var(--fs--1); color: var(--muted); line-height: 1.6; }

/* Social links: explicit hyperlinks */
.socials { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.socials a {
  font-size: var(--fs--2); font-weight: 500; letter-spacing: .04em;
  color: var(--blue); padding: 5px 12px; border: 1px solid var(--line);
  transition: background .22s var(--ease), border-color .22s var(--ease), color .22s var(--ease);
}
.socials a:hover { background: var(--navy); border-color: var(--navy); color: #fff; text-decoration: none; }

/* Alumni: tighter, single detail line. Four across, not the roster's three:
   these cards carry only name, role and degrees, so three left a lot of dead
   horizontal space. The count is explicit rather than auto-fill so the
   last-row border rule further down has a stride it can count on. */
.alumni .member-grid { grid-template-columns: repeat(4, 1fr); gap: 0 32px; }
.alumni .member-card { grid-template-columns: 84px 1fr; gap: 18px; padding: 22px 0; }
.alumni .headshot { width: 84px; height: 84px; }
.alumni .headshot.placeholder { font-size: 26px; }
.alumni .member-name { font-size: var(--fs-1); }
.alumni .member-role { margin-bottom: 8px; }
.alumni .member-degrees { margin-bottom: 0; }

@media (max-width: 1080px) {
  .member-grid { grid-template-columns: 1fr; gap: 0; }
  .alumni .member-grid { grid-template-columns: repeat(2, 1fr); gap: 0 28px; }
}
@media (max-width: 640px) { .alumni .member-grid { grid-template-columns: 1fr; gap: 0; } }
@media (max-width: 560px) {
  .member-card { grid-template-columns: 1fr; gap: 16px; }
  .member-photo { max-width: 120px; }
}

/* ========================== Content pages =========================== */
.page-head {
  background: var(--navy-800); color: #fff; padding: 104px 0 88px;
  position: relative; overflow: hidden;
}
.page-head::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--blue), transparent);
}
.page-head h1 {
  margin: 0; font-size: clamp(36px, 5vw, 60px); font-weight: 400;
  letter-spacing: -.025em; color: #fff;
}
.page-head p { margin: 18px 0 0; color: #b9c9e2; font-size: var(--fs-2); max-width: 720px; }
.prose { max-width: 780px; padding: var(--band) 0; }
.prose h2 { font-size: var(--fs-4); font-weight: 500; margin-top: 48px; scroll-margin-top: 100px; }
.prose ul { padding-left: 20px; }

/* News + publications */
.news-item, .pub-item { padding: 26px 0; border-bottom: 1px solid var(--line); }
.news-item .date {
  color: var(--blue); font-weight: 500; font-size: var(--fs--2);
  letter-spacing: .14em; text-transform: uppercase;
}
.news-item h3 { margin: 8px 0 8px; font-size: var(--fs-3); font-weight: 500; }
.news-item p { margin: 0; color: var(--muted); }
.pub-item { font-size: var(--fs-0); }
.pub-item .authors { color: var(--muted); }
.pub-item .title { font-weight: 600; }
.pub-item .venue { font-style: italic; color: var(--muted); }
.pub-ol { padding-left: 24px; margin: 6px 0 34px; }
.pub-ol li.pub-item { padding: 0; border: 0; margin: 0 0 16px; line-height: 1.6; }
.pub-ol li.pub-item a { word-break: break-word; }
.pub-pdf { font-size: var(--fs--2); font-weight: 600; white-space: nowrap; }

/* Bio */
.bio { display: grid; grid-template-columns: 340px 1fr; gap: 56px; align-items: start; }
.bio .portrait { border-radius: 0; box-shadow: none; }
.bio .facts { margin-top: 24px; font-size: var(--fs-0); color: var(--muted); }
.bio .facts strong { color: var(--ink); }
.bio h2 { font-size: var(--fs-3); font-weight: 500; margin: 32px 0 10px; }

/* Contact */
.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; }
.contact-card { font-size: var(--fs-1); line-height: 1.9; }
.contact-card strong { display: block; color: var(--navy); margin-top: 16px; }
/* The form is much taller than the copy beside it, and .two-col centres its
   children, which left the heading floating halfway down the section. Beyond
   that, an even 1fr/1fr split gave three short lines of address the same width
   as a five-field form, so the bottom-left quarter of the section was empty.
   The copy column is narrower now and the form is capped, which closes the gap
   from both sides. */
#contact .two-col {
  align-items: start;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 56px;
}
#contact .section-title { font-size: var(--fs-5); }
#contact .contact-meta { margin: 0; color: var(--muted); line-height: 1.85; }
@media (max-width: 820px) { #contact .two-col { grid-template-columns: 1fr; gap: 32px; } }

/* Field spacing was label + 8px + a 13px-padded input + 18px, so every field
   stood ~46px taller than its content and five of them added up to a form far
   taller than anything beside it. */
.contact-form { max-width: 560px; }
.contact-form label { display: block; margin: 0 0 12px; font-size: var(--fs--2); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.contact-form input, .contact-form textarea {
  width: 100%; padding: 9px 12px; margin-top: 4px;
  border: 0; border-bottom: 1.5px solid var(--line); background: transparent;
  border-radius: 0; font: inherit; font-size: var(--fs-1); color: var(--ink);
  text-transform: none; letter-spacing: normal;
  transition: border-color .25s var(--ease);
}
.contact-form input:focus, .contact-form textarea:focus { outline: 0; border-bottom-color: var(--blue); }
.contact-form .row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.contact-form button.cta { border: 0; cursor: pointer; }

/* Social + photo grids */
.social-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; margin-top: 8px; }
.photo-grid { columns: 3 300px; column-gap: 16px; margin-top: 8px; }
.photo-grid .photo { break-inside: avoid; margin: 0 0 16px; }
.photo-grid .photo img {
  width: 100%; border-radius: 0; cursor: zoom-in; box-shadow: none;
  background: var(--bg-soft); display: block;
  transition: opacity .3s var(--ease);
}
.photo-grid .photo img:hover { opacity: .88; }
.photo-grid figcaption { font-size: var(--fs--2); color: var(--muted); margin-top: 6px; }
.lightbox {
  display: none; position: fixed; inset: 0; z-index: 200; background: rgba(9,14,30,.95);
  align-items: center; justify-content: center; cursor: zoom-out; padding: 24px;
}
.lightbox.open { display: flex; }
.lightbox img { max-width: 95vw; max-height: 92vh; border-radius: 0; }

/* Stacked figures */
.stacked { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.stacked img { border-radius: 0; }
.stacked .logo-mark { max-width: 280px; }

/* ============================== Footer ============================== */
.site-footer { background: var(--navy-950); color: #a9bad4; padding: 72px 0 56px; font-size: var(--fs--1); }
.site-footer .footer-mark { height: 38px; width: auto; margin-bottom: 26px; }
.site-footer .row { display: flex; flex-wrap: wrap; gap: 22px; align-items: center; justify-content: space-between; }
.site-footer a { color: var(--blue-light); transition: color .2s var(--ease); }
.site-footer a:hover { color: #fff; }

/* ========================== Scroll reveal =========================== */
/* Transform + opacity only, so reveals never trigger layout. */
.reveal {
  opacity: 0; transform: translate3d(0, var(--reveal-shift), 0);
  /* .55s, not .8s: an .8s reveal is still running two-thirds of a second after
     it starts, so on a normal scroll several sections animate at once and the
     whole page appears to wobble. The shorter transform settles before the
     next element enters. Opacity runs slightly longer so the fade still feels
     unhurried while the movement is already over. */
  transition: opacity .6s var(--ease-out), transform .5s var(--ease-out);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* ============================ Responsive ============================ */
@media (max-width: 980px) {
  :root { --band: 60px; }
  .two-col { gap: 44px; }
  .methods { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 820px) {
  .nav { height: 66px; }
  .nav .brand img { height: 32px; }
  .nav .links, .nav .actions a:not(.btn-donate) { display: none; }
  .nav-toggle { display: block; }
  .nav.open .links {
    display: flex; position: absolute; top: 66px; left: 0; right: 0;
    flex-direction: column; align-items: flex-start; gap: 4px;
    background: var(--navy-deep); padding: 20px var(--gutter) 24px;
  }
  .nav.open .links .dropdown { display: block; width: 100%; }
  .nav .links .dropdown-menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    background: transparent; border-top: 0; padding: 0 0 0 16px; display: none;
  }
  .nav .links .dropdown.open .dropdown-menu { display: block; }
  .nav .links .submenu-menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    background: transparent; border-top: 0; padding: 0 0 0 16px; display: none;
  }
  .nav .links .submenu.open > .submenu-menu { display: block; }
  .nav .links .submenu > .submenu-toggle .chev { transform: rotate(90deg); }
  .nav .links .submenu.open > .submenu-toggle .chev { transform: rotate(-90deg); }
  .split, .split.rev { grid-template-columns: 1fr; min-height: 0; }
  .split .split-media, .split.rev .split-media { order: 1; height: 320px; min-height: 0; }
  .split .split-body, .split.rev .split-body { order: 2; justify-content: flex-start; padding: 56px var(--gutter) 64px; }
  .split-media img { top: 0; height: 100%; transform: none !important; }
  .split-media::after, .split.rev .split-media::after { background: none; }
  .two-col, .two-col.rev { grid-template-columns: 1fr; }
  .two-col.rev > :first-child, .two-col.rev > :last-child { order: 0; }
  .bio { grid-template-columns: 1fr; }
  .bio .portrait { max-width: 300px; }
  .contact-grid, .social-grid { grid-template-columns: 1fr; }
  .hero { min-height: clamp(340px, 54vh, 480px); }
  .page-head { padding: 72px 0 60px; }
}
@media (max-width: 700px) {
  body { font-size: 16px; }          /* was var(--fs-1), i.e. a no-op restating the default */
  .photo-grid { columns: 2 160px; }
  .cards { gap: 2px 24px; }
}
@media (max-width: 620px) { .contact-form .row2 { grid-template-columns: 1fr; } }

/* ======================== Reduced motion ============================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1 !important; transform: none !important; }
  .hero-ready h1, .hero-ready .sub, .hero .scroll-cue::after { animation: none; }
  .marquee-track { animation: none; }
  .split-media img, .video-band-media, .hero .bg { transform: none !important; }
  * { transition-duration: .01ms !important; }
}

/* Tool list inside a split band */
.tool-list { list-style: none; padding: 0; margin: 0 0 28px; }
.tool-list li { padding: 12px 0; border-top: 1px solid rgba(255,255,255,.14); }
.tool-list li:last-child { border-bottom: 1px solid rgba(255,255,255,.14); }
.tool-list a {
  font-family: var(--font-display); font-size: var(--fs-1); font-weight: 500;
  color: #fff !important; letter-spacing: .01em;
}
.tool-list a:hover { color: var(--blue-light) !important; }
.tool-list span { display: block; font-size: var(--fs--1); color: #9fb3d2; margin-top: 2px; }

/* Current sub-page marker inside a dropdown */
.nav .links .dropdown-menu a.here { color: #fff; background: rgba(127,178,229,.10); }
.nav .links .dropdown-menu a.here::before {
  content: ""; display: inline-block; width: 3px; height: 12px;
  background: var(--blue); margin-right: 9px; vertical-align: -2px;
}

/* ===================== Repository / resource cards ==================
   Flat rows with a hairline top rule, matching the card system.      */
.repo-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 0 48px; }
.repo {
  display: block; padding: 24px 0 26px; border-top: 1.5px solid var(--line);
  color: inherit; transition: border-color .3s var(--ease);
}
.repo:hover { border-top-color: var(--blue); text-decoration: none; }
.repo:hover .repo-name { color: var(--blue); }
.repo-desc { margin: 0 0 12px; font-size: var(--fs-0); color: var(--muted); line-height: 1.65; }
.repo-meta { display: flex; flex-wrap: wrap; gap: 8px; }
.repo-meta span {
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .06em; color: var(--muted);
  padding: 4px 10px; background: var(--bg-soft); border: 1px solid var(--line);
}
section.block.alt .repo-meta span { background: #fff; }
/* Featured platform rows read a little larger */
.repo-feature .repo-name { font-size: var(--fs-3); }
.repo-feature .repo-desc { font-size: var(--fs-1); }
@media (max-width: 700px) { .repo-list { gap: 0 24px; } }

/* Attribution + citation inside a resource card */
.repo-credit {
  margin: 0 0 14px; font-size: var(--fs--1); color: var(--muted);
  padding-left: 14px; border-left: 2px solid var(--line);
}
.repo-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.repo-links a {
  font-size: var(--fs--2); font-weight: 500; letter-spacing: .03em; color: var(--blue);
  padding: 6px 14px; border: 1px solid var(--line);
  transition: background .22s var(--ease), border-color .22s var(--ease), color .22s var(--ease);
}
.repo-links a:hover { background: var(--navy); border-color: var(--navy); color: #fff; text-decoration: none; }
.repo-cite {
  font-size: var(--fs--2); line-height: 1.6; color: var(--muted);
  background: var(--bg-soft); border-top: 2px solid var(--blue); padding: 14px 16px;
}
section.block.alt .repo-cite { background: #fff; }
.repo-cite .cite-label {
  display: block; font-family: var(--font-display); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--navy);
  opacity: .6; margin-bottom: 5px;
}
.repo-cite a { word-break: break-word; }
/* Bolded authors in a Cite as block are lab members; this quiet line says so.
   Sits at the foot of the software section, generated by sync_osr.py. */
.cite-note { margin: 28px 0 0; }

/* ===================== Lab handbook: live synced page ==============
   The handbook is generated from the live Google Doc into a navigable page:
   a sticky sidebar table of contents (scroll-spy) beside clean prose. A slim
   bar above carries the contents toggle (mobile) and PDF fallbacks. */
.hb-bar {
  position: sticky; top: 76px; z-index: 30;
  background: var(--navy); color: #fff;
}
.hb-bar .wrap {
  display: flex; flex-wrap: nowrap; align-items: center; justify-content: space-between;
  gap: 12px; height: 46px;
}
@media (max-width: 820px) { .hb-bar .wrap { height: 42px; } }
.hb-bar-label {
  font-family: var(--font-display); font-size: var(--fs-0); font-weight: var(--fw-med);
}
.hb-bar-links { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.hb-bar-links a, .hb-toc-toggle {
  font-family: var(--font-body); font-size: var(--fs--1); font-weight: var(--fw-med);
  letter-spacing: .03em; color: #fff; padding: 6px 14px;
  border: 1px solid rgba(255,255,255,.28); background: none; cursor: pointer;
  transition: background .22s var(--ease), border-color .22s var(--ease);
}
.hb-bar-links a:hover, .hb-toc-toggle:hover { background: var(--blue); border-color: var(--blue); text-decoration: none; }
.hb-toc-toggle { display: none; }          /* only shown on narrow screens */

.hb-wrap { padding: 40px 0 var(--band); max-width: 1220px; }
.hb-layout { display: grid; grid-template-columns: 256px minmax(0, 1fr); gap: 56px; align-items: start; }

/* Sidebar contents: sticky, independently scrollable, scroll-spy highlight */
.hb-toc {
  position: sticky; top: 134px; align-self: start;
  max-height: calc(100vh - 154px); overflow-y: auto; overscroll-behavior: contain;
  padding-right: 10px;
}
.hb-toc .toc-list, .hb-toc .toc-sub { list-style: none; margin: 0; padding: 0; }
.hb-toc .toc-list { border-left: 1px solid var(--line); }
.hb-toc a {
  display: block; padding: 5px 0 5px 16px; margin-left: -1px;
  border-left: 2px solid transparent; color: var(--muted);
  font-size: var(--fs--1); line-height: 1.4; transition: color .18s var(--ease), border-color .18s var(--ease);
}
.hb-toc a:hover { color: var(--navy); text-decoration: none; }
.hb-toc a.active { color: var(--blue); border-left-color: var(--blue); }

/* Top-section row: caret + link. Children (toc-sub) collapse until the section
   is expanded (by caret click or scroll-spy on the active section). */
.hb-toc .toc-sec-head { display: flex; align-items: flex-start; }
.hb-toc .toc-l1 { flex: 1; color: var(--navy); font-weight: var(--fw-med); margin-top: 4px; padding-left: 6px; }
.hb-toc .toc-caret {
  flex: 0 0 auto; width: 18px; height: 26px; margin-top: 4px; padding: 0;
  background: none; border: 0; cursor: pointer; color: var(--muted);
  position: relative;
}
.hb-toc .toc-caret::before {
  content: ""; position: absolute; left: 5px; top: 10px;
  border-left: 4px solid currentColor; border-top: 3px solid transparent; border-bottom: 3px solid transparent;
  transition: transform .18s var(--ease); transform-origin: 2px 3px;
}
.hb-toc .toc-caret[aria-expanded="true"]::before { transform: rotate(90deg); }
.hb-toc .toc-caret-none { flex: 0 0 auto; width: 18px; }
.hb-toc .toc-sub { display: none; }
.hb-toc .toc-sec.open > .toc-sub { display: block; }
.hb-toc .toc-l2 { padding-left: 30px; }

/* Content column: clean, readable prose */
.hb-content { max-width: 880px; font-size: var(--fs-1); color: var(--ink); }

/* Collapsible top sections. Each doc H1 section folds via <details>; the H2
   sits in the summary with a caret, and the section divider is the details
   border so it does not double up with the heading's own rule. */
.hb-sec { border-top: 2px solid var(--navy); }
.hb-sec:first-of-type { border-top: 0; }
.hb-sec-summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 12px;
  padding: 18px 0 2px;
}
.hb-sec-summary::-webkit-details-marker { display: none; }
.hb-sec-summary h2 {
  border-top: 0; margin: 0; padding-top: 0; flex: 1;
  font-family: var(--font-display); font-size: var(--fs-4); font-weight: var(--fw-med);
  color: var(--navy); letter-spacing: var(--tr-snug); line-height: 1.2;
  scroll-margin-top: 150px;
}
.hb-sec-summary::after {
  content: ""; flex: 0 0 auto; margin-top: 4px;
  border-left: 6px solid var(--muted); border-top: 5px solid transparent; border-bottom: 5px solid transparent;
  transition: transform .2s var(--ease);
}
.hb-sec[open] > .hb-sec-summary::after { transform: rotate(90deg); }
.hb-sec-summary:hover h2 { color: var(--blue); }
.hb-sec-body { padding: 6px 0 26px; }

.hb-content h2 {
  font-family: var(--font-display); font-size: var(--fs-4); font-weight: var(--fw-med);
  color: var(--navy); letter-spacing: var(--tr-snug); line-height: 1.2;
  margin: 46px 0 14px; padding-top: 16px; border-top: 2px solid var(--navy);
  scroll-margin-top: 150px;
}
.hb-content > h2:first-child { margin-top: 0; }
/* The section heading lives inside <summary>, where the divider is already
   drawn by .hb-sec's own border-top. Without this the rule above repaints it
   and every section break shows two navy lines. */
.hb-content .hb-sec-summary h2 { border-top: 0; padding-top: 0; margin-top: 0; }
/* Heading ladder. h3 and h4 were 24px and 20px of the same display face in
   near-identical colours, so a sub-heading read as a peer of its parent. Each
   level now differs on three axes at once (rule, typeface, size) rather than
   on size alone: h2 sits on a 2px navy rule, h3 on a hairline in the display
   face, h4 is the body face at body size, h5 is smaller and grey. Longest h4
   in the handbook runs to 80 characters, so no all-caps treatment here. */
.hb-content h3 {
  font-family: var(--font-display); font-size: var(--fs-3); font-weight: var(--fw-med);
  color: var(--navy); letter-spacing: var(--tr-snug);
  margin: 48px 0 12px; padding-top: 15px; border-top: 1px solid var(--line);
  scroll-margin-top: 150px;
}
.hb-content h4 {
  font-family: var(--font-body); font-size: var(--fs-1); font-weight: var(--fw-semi);
  color: var(--navy); letter-spacing: 0; line-height: 1.4;
  margin: 32px 0 8px; scroll-margin-top: 150px;
}
.hb-content h5, .hb-content h6 {
  font-family: var(--font-body); font-size: var(--fs--1); font-weight: var(--fw-semi);
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
  margin: 24px 0 6px; scroll-margin-top: 150px;
}
/* A heading straight after its parent should not carry the full gap */
.hb-content h2 + h3, .hb-content h3 + h4, .hb-content h4 + h5 { margin-top: 18px; }
.hb-content h2 + h3 { padding-top: 0; border-top: 0; }
.hb-content p { margin: 0 0 16px; line-height: 1.7; color: var(--muted); }
/* Links: always underlined (no hover toggle that repaints), and lifted above
   any highlight-span background so the whole run is one stable click target,
   which stops the cursor flickering on hover. */
.hb-content a {
  color: var(--blue); overflow-wrap: break-word;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
  position: relative; z-index: 1;
}
.hb-content a:hover { color: var(--navy); }
/* A highlighted run that IS a link should not paint its background over the
   link's hit area unevenly. */
.hb-content [class*="hb-hl-"] > a { background: transparent; }
/* Pull quotes and their attribution, centered. */
.hb-content .hb-quote { text-align: center; }
.hb-content .hb-quote-cite { text-align: center; }
.hb-content strong { color: var(--ink); font-weight: 600; }
.hb-content ul, .hb-content ol { margin: 0 0 18px; padding-left: 22px; }
.hb-content li { margin: 0 0 7px; line-height: 1.65; color: var(--muted); }
.hb-content li > ul, .hb-content li > ol { margin: 8px 0 4px; }
/* Sub-bullets. The Google export does not nest its <ul>s: a sub-list is a
   sibling list and the depth is carried in the item's margin-left, so
   sync_handbook.py reads that and tags the item with its level. Without these
   every sub-point sat at the same indent as its parent and read as a peer. */
.hb-content li.hb-lvl-1 { margin-left: 26px; }
.hb-content li.hb-lvl-2 { margin-left: 52px; }
.hb-content li.hb-lvl-3 { margin-left: 78px; }
.hb-content li.hb-lvl-4 { margin-left: 104px; }
.hb-content li.hb-lvl-1::marker { content: "\25E6  "; }   /* hollow bullet */
.hb-content li.hb-lvl-2::marker,
.hb-content li.hb-lvl-3::marker,
.hb-content li.hb-lvl-4::marker { content: "\25AA  "; }   /* small square */
@media (max-width: 640px) {
  .hb-content li.hb-lvl-1 { margin-left: 14px; }
  .hb-content li.hb-lvl-2 { margin-left: 28px; }
  .hb-content li.hb-lvl-3 { margin-left: 42px; }
  .hb-content li.hb-lvl-4 { margin-left: 56px; }
}
.hb-figure { margin: 22px 0; }
.hb-content img { max-width: 100%; height: auto; }   /* also caps images inline in paragraphs */
.hb-table { overflow-x: auto; margin: 0 0 22px; }
.hb-table table { border-collapse: collapse; width: 100%; font-size: var(--fs-0); }
.hb-table td, .hb-table th {
  border: 1px solid var(--line); padding: 9px 12px; text-align: left; vertical-align: top;
  color: var(--muted);
}
.hb-table th { background: var(--bg-soft); color: var(--ink); font-weight: 600; }

/* Footnotes. The doc's numbered notes land at the foot of the References
   section; the label keeps them from reading as more bibliography. */
.hb-notes-label {
  margin: 30px 0 12px; padding-bottom: 9px; border-bottom: 1px solid var(--line);
  font-family: var(--font-display); font-size: var(--fs--2); font-weight: var(--fw-med);
  letter-spacing: var(--tr-caps); text-transform: uppercase; color: var(--navy);
}
.hb-content .hb-note { font-size: var(--fs-0); margin: 0 0 9px; }

/* Footnotes. The definitions used to sit in a Notes list at the foot of the
   page, so reading one meant losing your place. sync_handbook.py now inlines
   the text into the marker and this shows it on hover. tabindex + :focus-within
   means keyboard and touch get it too, not just a mouse, and the print rule
   puts the text back in the flow so a printed handbook still carries it. */
.hb-content .hb-fn { position: relative; display: inline; cursor: help; }
.hb-content .hb-fn-mark {
  color: var(--blue); font-weight: var(--fw-semi); font-size: .72em;
  padding: 0 1px 0 2px; vertical-align: super; line-height: 0;
  border-bottom: 1px dotted var(--blue);
}
.hb-content .hb-fn:hover .hb-fn-mark,
.hb-content .hb-fn:focus-visible .hb-fn-mark { color: var(--navy); }
.hb-content .hb-fn-pop {
  position: absolute; z-index: 30; left: 50%; transform: translateX(-50%);
  top: calc(100% + 9px); width: max-content; max-width: min(380px, 78vw);
  background: var(--navy-900); color: #dbe5f2; text-align: left;
  font-size: var(--fs--1); font-weight: var(--fw-book); line-height: 1.6;
  padding: 13px 16px; box-shadow: 0 10px 30px rgba(8, 15, 33, .3);
  opacity: 0; visibility: hidden; transition: opacity .14s var(--ease);
}
.hb-content .hb-fn:hover .hb-fn-pop,
.hb-content .hb-fn:focus .hb-fn-pop,
.hb-content .hb-fn:focus-within .hb-fn-pop { opacity: 1; visibility: visible; }
.hb-content .hb-fn-pop .hb-fn-num {
  display: inline-block; margin-right: 8px; color: var(--blue-light);
  font-weight: var(--fw-semi);
}
.hb-content .hb-fn-pop a { color: var(--blue-light); }
.hb-content .hb-fn-pop a:hover { color: #fff; }
.hb-content .hb-fn-pop span { color: inherit; }   /* doc colours would vanish on navy */
@media (max-width: 640px) {
  /* Centred on a narrow screen a popup anchored to the marker falls off the
     edge, so pin it to the viewport instead. */
  .hb-content .hb-fn-pop {
    position: fixed; left: 12px; right: 12px; bottom: 12px; top: auto;
    transform: none; width: auto; max-width: none;
  }
}
@media print {
  .hb-content .hb-fn-pop {
    position: static; opacity: 1; visibility: visible; display: block;
    background: none; color: #000; box-shadow: none; padding: 4px 0 4px 14px;
    max-width: none; width: auto; transform: none; font-style: italic;
  }
}
.hb-content sup { font-size: .72em; line-height: 0; }
.hb-content sup a { font-weight: var(--fw-med); }

/* City guide ("Things to do in Durham"). Eighty "name. one line" entries read
   as an undifferentiated wall as bullets, so they set two across with the name
   carrying the link and the copy underneath. Flat and hairline-separated to
   match the roster, no boxes. Generated by render_places in sync_handbook.py. */
.hb-guide-nav { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 26px; }
.hb-guide-nav a {
  padding: 5px 11px; border: 1px solid var(--line); background: var(--bg-tint);
  font-size: var(--fs--1); color: var(--muted); text-decoration: none;
}
.hb-guide-nav a:hover { border-color: var(--blue); color: var(--blue); background: #fff; }
.hb-content ul.hb-places {
  list-style: none; display: grid; grid-template-columns: 1fr 1fr;
  gap: 0 40px; margin: 0 0 26px; padding: 0;
}
.hb-content .hb-place {
  margin: 0; padding: 13px 0 14px; border-bottom: 1px solid var(--line);
  font-size: var(--fs-0); line-height: 1.55;
}
/* the name stays inline so a short aside or tag sits on the same line; the
   description is the block that starts the next line */
.hb-place-name { color: var(--ink); font-weight: 600; }
.hb-place-name a { color: var(--navy); }
.hb-place-name a:hover { color: var(--blue); }
.hb-place-aside { margin-left: .4em; color: var(--muted); font-size: var(--fs--1); }
.hb-place-desc { display: block; margin-top: 3px; color: var(--muted); }
.hb-place-tag {
  display: inline-block; margin: 0 0 0 7px; padding: 1px 7px; vertical-align: 1px;
  font-size: var(--fs-micro); font-weight: var(--fw-med); letter-spacing: .07em;
  text-transform: uppercase; color: var(--blue); border: 1px solid var(--line);
  background: var(--bg-tint);
}
/* an entry the doc wrote as one sentence ("Durham Geeks on Meetup for board
   games") keeps the name and the copy on the same line */
.hb-place.run .hb-place-desc { display: inline; margin-left: .3em; }

/* Inline formatting carried over from the doc, collapsed to a consistent set of
   site-aligned buckets (see color_bucket / hl_bucket in sync_handbook.py). */
.hb-content .hb-b { font-weight: 600; color: var(--ink); }
.hb-content .hb-i { font-style: italic; }
.hb-content .hb-u { text-decoration: underline; text-underline-offset: 2px; }
.hb-content .hb-c-red   { color: #c0392b; }
.hb-content .hb-c-blue  { color: var(--blue); }
.hb-content .hb-c-green { color: #1e7a52; }
.hb-content .hb-c-amber { color: #b26a00; }
.hb-content .hb-c-ink   { color: var(--ink); }
.hb-content .hb-c-muted { color: var(--muted); }
.hb-content .hb-hl-yellow { background: #fff3bf; padding: .05em .18em; border-radius: 2px; }
.hb-content .hb-hl-blue   { background: #e2edfb; padding: .05em .18em; border-radius: 2px; }
.hb-content .hb-hl-green  { background: #e4f5ea; padding: .05em .18em; border-radius: 2px; }
.hb-content .hb-hl-grey   { background: var(--bg-soft); padding: .05em .18em; border-radius: 2px; }
/* a bolded coloured run keeps its colour, not the default ink of .hb-b */
.hb-content .hb-b.hb-c-red { color: #c0392b; }
.hb-content .hb-b.hb-c-blue { color: var(--blue); }
.hb-content .hb-b.hb-c-green { color: #1e7a52; }
.hb-content .hb-b.hb-c-amber { color: #b26a00; }

/* Internal (all-links) handbook badge in the bar */
.hb-internal-badge {
  display: inline-block; margin-left: 8px; padding: 2px 9px;
  font-family: var(--font-body); font-size: var(--fs-micro); font-weight: var(--fw-med);
  letter-spacing: .08em; text-transform: uppercase;
  color: #fff; background: var(--blue); border-radius: 2px; vertical-align: 2px;
}

@media (max-width: 900px) {
  .hb-toc-toggle { display: inline-block; }
  /* minmax(0,...), not 1fr: a plain 1fr cannot shrink below the widest
     item's min-content, which pushed the whole page 115px wider than the
     phone viewport and let the handbook scroll sideways. */
  .hb-layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  /* cascade pair: the guide entries drop to one column */
  .hb-content ul.hb-places { grid-template-columns: 1fr; gap: 0; }
  /* TOC collapses behind the Contents toggle on narrow screens */
  .hb-toc {
    position: static; max-height: none; overflow: visible;
    display: none; margin-bottom: 28px; padding: 4px 0 0;
  }
  body.hb-toc-open .hb-toc { display: block; }
}
/* Feature cards carry more content, so give them room to breathe */
.repo-feature { padding-bottom: 34px; }

/* ===================== Scroll-scrubbed video hero ===================
   The section is tall; the media pins inside it and the video's playback
   position is driven by scroll progress. Only currentTime is written,
   never layout.                                                       */
.video-hero { position: relative; height: 200vh; background: var(--navy-deep); }
.video-hero-sticky {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: flex; align-items: center;
}
.video-hero-media {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .48;
}
.video-hero-sticky::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,16,36,.62) 0%, rgba(9,16,36,.34) 45%, rgba(9,16,36,.86) 100%);
}
.video-hero-inner { position: relative; z-index: 2; width: 100%; color: #fff; }
.video-hero-inner h1 {
  margin: 0; color: #fff; font-size: clamp(38px, 6vw, 72px);
  font-weight: 400; letter-spacing: -.025em; line-height: 1.05;
}
.video-hero-inner p { margin: 20px 0 0; color: #c3d2e8; font-size: var(--fs-2); max-width: 660px; }
.video-hero-cue {
  position: absolute; left: 50%; bottom: 34px; z-index: 2; margin-left: -9px;
  width: 18px; height: 30px; border: 1.5px solid rgba(255,255,255,.45); border-radius: 10px;
}
.video-hero-cue::after {
  content: ""; position: absolute; left: 50%; top: 7px; margin-left: -1.5px;
  width: 3px; height: 6px; background: #fff; border-radius: 2px;
  animation: cue 1.9s var(--ease) infinite;
}
@media (max-width: 820px) { .video-hero { height: 150vh; } }

/* ===================== Bleed header + sticky title ==================
   Used on Publications. The tall header scrolls away while a slim bar
   keeps the page title on screen.                                     */
.page-head.bleed { position: relative; overflow: hidden; padding: 132px 0 108px; background: var(--navy-950); }
.page-head.bleed .bleed-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .42; will-change: transform;
}
.page-head.bleed::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,16,36,.6), rgba(9,16,36,.85));
}
.page-head.bleed .wrap { position: relative; z-index: 2; }
/* The page title used to appear twice at the top: once large over the photo
   band and again in a slim bar pinned under it. Emma called that redundant and
   chose to keep the real header and pin THAT, so the slim bar is gone and
   .page-head.bleed.compact.pinned sticks under the nav instead.

   Not applied to the handbook, forms or portal pages: those already pin a
   document bar at the same offset and the two would collide. */
.page-head.bleed.compact.pinned {
  position: sticky; top: 76px; z-index: 39;
}
@media (max-width: 820px) {
  .page-head.bleed.compact.pinned { top: 66px; }
}

/* ===================== Platform cards with hover figure =============
   PACE / PRANCE / TurboPRANCE. Figure sits above the text and swaps in
   on hover; whole card links to the paper.                            */
.platforms { display: grid; grid-template-columns: repeat(4, 1fr); gap: 30px; margin-top: 16px; }
.platform {
  display: block; color: inherit; border-top: 1.5px solid var(--line);
  padding-top: 20px; transition: border-color .3s var(--ease);
}
.platform:hover { border-top-color: var(--blue); text-decoration: none; }
.platform-figure {
  position: relative; height: 190px; margin-bottom: 18px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-soft); overflow: hidden;
}
.platform-figure img {
  max-width: 88%; max-height: 88%; width: auto; height: auto;
  object-fit: contain; transition: transform .5s var(--ease), opacity .4s var(--ease);
}
.platform:hover .platform-figure img { transform: scale3d(1.06,1.06,1); }
.platform h3 {
  margin: 0 0 6px; font-family: var(--font-display); font-size: var(--fs-3); font-weight: 500;
  color: var(--navy); transition: color .25s var(--ease);
}
.platform:hover h3 { color: var(--blue); }
.platform .platform-full {
  display: block; font-size: var(--fs-micro); letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px;
}
.platform p { margin: 0 0 12px; font-size: var(--fs-0); color: var(--muted); line-height: 1.6; }
.platform .platform-cite {
  font-size: var(--fs--2); font-weight: 500; letter-spacing: .04em; color: var(--blue);
}
.platform:hover .platform-cite { text-decoration: underline; }
@media (max-width: 1080px) { .platforms { grid-template-columns: repeat(2, 1fr); gap: 30px 28px; } }
@media (max-width: 560px)  { .platforms { grid-template-columns: 1fr; gap: 28px; } }

/* ===================== Figure cards: never crop the artwork ========= */
.card.imgcard .imgcard-figure {
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-soft); height: 230px; padding: 16px;
}
.card.imgcard img { border-radius: 0; margin: 0;
  transition: transform .7s var(--ease); will-change: transform;
  width: auto; height: auto; max-width: 100%; max-height: 100%;
  object-fit: contain;
}

/* Larger method icons */
.methods { gap: 44px; }
.method img { margin: 0 auto 20px; border-radius: 50%;
  background: var(--bg-soft); box-shadow: none;
  transition: transform .45s var(--ease); will-change: transform; width: 190px; height: 190px; }
@media (max-width: 980px) { .method img { width: 160px; height: 160px; } }

/* Home banner: half height, reads as a band rather than a hero */

/* ===================== People: 3 across + full-width PI =============
   Overrides the earlier two-column record layout.                     */
.page-head.people { padding: 64px 0 56px; }
.page-head.people h1 { font-size: clamp(30px, 3.6vw, 44px); }

/* Lab quote above the roster */
/* The quote is 76 characters. Capped at 820px and up to 27px it always broke
   across two lines, which for a single sentence reads as an accident. It now
   uses the full text column at a smaller fluid size so it sits on one line from
   tablet width up, and is allowed to wrap below 820px where one line would mean
   unreadably small type. */
.people-quote {
  max-width: none; margin: 0 auto; padding: 52px 0 46px; text-align: center;
}
.people-quote p {
  margin: 0; font-family: var(--font-display); font-size: clamp(16px, 1.9vw, 23px);
  font-weight: 300; font-style: italic; line-height: 1.4; color: var(--ink);
  letter-spacing: -.01em;
}
@media (min-width: 820px) { .people-quote p { white-space: nowrap; } }
.people-quote cite {
  display: block; margin-top: 16px; font-family: var(--font-body); font-style: normal;
  font-size: var(--fs--2); letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}

.member-group { padding: 0 0 56px; }
/* type and rule come from .lbl-rule */
.member-group h2 { margin-bottom: 6px; }

/* Default roster: three across, portrait stacked above the details */
.member-grid { grid-template-columns: repeat(3, 1fr); gap: 0 40px; }
.member-card {
  display: block; padding: 30px 0 32px; border-bottom: 1px solid var(--line);
}

/* Drop the divider under the last row of each group, so the boundary between
   two groups is a single rule (the next group heading's) rather than the card
   line plus the heading line stacked. The last-row selector is scoped per
   column count with min/max widths so the breakpoints do not overlap and
   strip borders from interior rows. Column counts: 3 (>=1081), 2 (641-1080),
   1 (<=640); the PI group is one full-width card and is covered by all three. */
@media (min-width: 1081px) {
  .member-group:not(.alumni) .member-grid > .member-card:nth-child(3n+1):nth-last-child(-n+3),
  .member-group:not(.alumni) .member-grid > .member-card:nth-child(3n+1):nth-last-child(-n+3) ~ .member-card {
    border-bottom: 0;
  }
  /* Alumni run four across, so the stride is 4. The rule above is scoped with
     :not(.alumni) rather than re-asserted here, because a plain
     .member-group.alumni selector loses on specificity to a 3n rule carrying
     two pseudo-classes. */
  .member-group.alumni .member-grid > .member-card:nth-child(4n+1):nth-last-child(-n+4),
  .member-group.alumni .member-grid > .member-card:nth-child(4n+1):nth-last-child(-n+4) ~ .member-card {
    border-bottom: 0;
  }
}
@media (min-width: 641px) and (max-width: 1080px) {
  .member-group .member-grid > .member-card:nth-child(2n+1):nth-last-child(-n+2),
  .member-group .member-grid > .member-card:nth-child(2n+1):nth-last-child(-n+2) ~ .member-card {
    border-bottom: 0;
  }
}
@media (max-width: 640px) {
  .member-group .member-grid > .member-card:last-child { border-bottom: 0; }
}

/* Principal investigator: full width, slimmer, details in two columns */
.member-group.pi .member-grid { grid-template-columns: 1fr; }
.member-group.pi .member-card {
  display: grid; grid-template-columns: 150px minmax(0,1fr); gap: 34px;
  align-items: start; padding: 30px 0 34px;
}
.member-group.pi .member-photo { margin-bottom: 0; }
.member-group.pi .member-name { font-size: var(--fs-3); }
.member-group.pi .member-body { display: block; }

/* Two columns of detail, as two independent blocks. A single grid coupled the
   row heights, so the tall Research paragraph on the right dragged "Beyond the
   bench" on the left down past it and left a hole in the card. */
.pi-detail {
  display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: 0 44px; align-items: start; margin-top: 4px;
}
.pi-detail-col > *:last-child { margin-bottom: 0; }
.member-group.pi .member-degrees { margin-bottom: 18px; }
.member-group.pi .socials { margin-top: 20px; }

@media (max-width: 1080px) {
  .member-grid { grid-template-columns: repeat(2, 1fr); gap: 0 32px; }
}
@media (max-width: 820px) {
  .pi-detail { grid-template-columns: 1fr; gap: 0; }
  .pi-detail-col > *:last-child { margin-bottom: 14px; }
}
@media (max-width: 640px) {
  .member-grid { grid-template-columns: 1fr; }
  .member-group.pi .member-card { grid-template-columns: 1fr; gap: 18px; }
}

/* ==================== Frame-sequence scroll hero ====================
   Preloaded JPEG frames drawn to a canvas. Replaces scroll-scrubbed
   <video>, which stalls because browsers throttle rapid seeking.      */
.frame-hero { position: relative; height: 240vh; background: var(--navy-deep); }
.frame-hero-sticky {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: flex; align-items: center;
}
.frame-hero-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .5;
}
.frame-hero-sticky::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(9,16,36,.62) 0%, rgba(9,16,36,.32) 45%, rgba(9,16,36,.86) 100%);
}
.frame-hero-inner { position: relative; z-index: 2; width: 100%; color: #fff; }
.frame-hero-inner h1 {
  margin: 0; color: #fff; font-size: clamp(38px, 6vw, 72px);
  font-weight: 400; letter-spacing: -.025em; line-height: 1.05;
}
.frame-hero-inner p { margin: 20px 0 0; color: #c3d2e8; font-size: var(--fs-2); max-width: 640px; }
@media (max-width: 820px) { .frame-hero { height: 170vh; } }

/* ==================== Research page building blocks ================= */
/* Intro: copy left, round figure right */
.lede-split { display: grid; grid-template-columns: 1.55fr .95fr; gap: 64px; align-items: center; }
.lede {
  font-family: var(--font-display); font-size: clamp(20px, 2.3vw, 27px);
  font-weight: 400; line-height: 1.35; letter-spacing: -.01em;
  color: var(--ink); margin: 0 0 22px;
}
.lede-split p:not(.lede) { color: var(--muted); font-size: var(--fs-1); margin: 0; }
.figure-round { margin: 0; display: flex; justify-content: center; }
.figure-round img { max-width: 340px; width: 100%; height: auto; }

/* Wide lead paragraph under a heading */
.section-lead.wide { max-width: 900px; }

/* A single large figure, never cropped */
.figure-wide { margin: 18px 0 0; text-align: center; }

/* Method icons get captions only, no body copy */

/* Wide banner figures (Applications / Models / Expertise) keep their
   native ~3:1 proportions instead of being cropped into squares. */
.banner-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 44px; margin-top: 14px; }
.banner-card figcaption {
  margin-top: 16px; font-family: var(--font-display); font-size: var(--fs-2);
  font-weight: var(--fw-med); color: var(--navy); letter-spacing: var(--tr-snug);
}
@media (max-width: 900px) { .banner-grid { grid-template-columns: 1fr; gap: 32px; } }

/* Project figures: large round artwork, caption below */
.project-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 48px 64px; margin-top: 20px; }
.project-card { margin: 0; text-align: center; }
.project-card:hover img { transform: translate3d(0,-5px,0); }
@media (max-width: 820px) {
  .project-grid { grid-template-columns: 1fr; gap: 44px; }
  .lede-split { grid-template-columns: 1fr; gap: 36px; }
}

/* ========================= Lab photo gallery ========================
   Randomized mosaic. Tile weights vary so the grid never looks like a
   uniform contact sheet.                                              */
.gallery-wrap { padding: 40px 0 var(--band); max-width: 1320px; }
.gallery-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding-bottom: 20px; margin-bottom: 26px;
  border-bottom: 1px solid var(--line);
}
.gallery-count {
  font-family: var(--font-display); font-size: var(--fs--2); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted);
}
.gallery-shuffle {
  font-family: var(--font-display); font-size: var(--fs--1); font-weight: 500;
  letter-spacing: .05em; color: var(--navy); background: none; cursor: pointer;
  border: 1px solid var(--line); padding: 9px 20px; border-radius: 0;
  transition: background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.gallery-shuffle:hover { background: var(--navy); border-color: var(--navy); color: #fff; }
.gallery-status { color: var(--muted); font-size: var(--fs-1); padding: 40px 0; }

.gallery {
  display: grid; grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 210px; gap: 14px;
}
.gphoto.wide { grid-column: span 2; }
.gphoto.tall { grid-row: span 2; }
/* caption slides up from the bottom edge on hover */
.gphoto figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 26px 16px 14px; font-size: var(--fs--1); color: #fff;
  background: linear-gradient(180deg, transparent, rgba(9,14,30,.82));
  opacity: 0; transform: translate3d(0,10px,0);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.gphoto:hover figcaption { opacity: 1; transform: none; }

@media (max-width: 1100px) { .gallery { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 190px; } }
@media (max-width: 760px) {
  .gallery { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 150px; gap: 10px; }
  .gphoto.wide { grid-column: span 2; }
  .gphoto.tall { grid-row: span 1; }
}

/* ---- Lightbox ---- */
.lightbox2 {
  display: none; position: fixed; inset: 0; z-index: 200;
  background: rgba(8,13,28,.96); align-items: center; justify-content: center; padding: 40px 72px;
}
.lightbox2.open { display: flex; }
.lb-figure { margin: 0; max-width: 100%; max-height: 100%; text-align: center; }
.lb-figure img {
  max-width: 100%; max-height: 82vh; width: auto; height: auto;
  display: block; margin: 0 auto; animation: lbIn .32s var(--ease-out) both;
}
@keyframes lbIn { from { opacity: 0; transform: scale(.985); } to { opacity: 1; transform: none; } }
.lb-figure figcaption { margin-top: 16px; color: #c3d2e8; font-size: var(--fs--1); }
.lb-close, .lb-nav {
  position: absolute; background: none; border: 0; color: #fff; cursor: pointer;
  line-height: 1; opacity: .65; transition: opacity .2s var(--ease), transform .2s var(--ease);
}
.lb-close:hover, .lb-nav:hover { opacity: 1; }
.lb-close { top: 22px; right: 26px; font-size: 34px; }
.lb-nav { top: 50%; margin-top: -28px; font-size: 52px; padding: 0 18px; }
.lb-prev { left: 8px; }
.lb-next { right: 8px; }
.lb-nav:hover { transform: scale(1.12); }
.lb-counter {
  position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-display); font-size: var(--fs--2); letter-spacing: .16em;
  color: #8ea5c6;
}
@media (max-width: 760px) {
  .lightbox2 { padding: 20px 12px; }
  .lb-nav { font-size: 38px; padding: 0 8px; }
}

/* ========================== Join us page ===========================
   Accordion built on native details/summary so it works without JS
   and stays keyboard accessible.                                     */
.join-wrap { max-width: 900px; padding: 48px 0 var(--band); }
.join-intro { font-size: var(--fs-1); color: var(--muted); margin: 0 0 40px; }

/* Capacity notice: the thing applicants most need to read */
.notice {
  border-left: 3px solid var(--blue); background: var(--bg-soft);
  padding: 22px 26px; margin: 0 0 28px;
}
.notice p { margin: 0 0 12px; font-size: var(--fs-1); color: var(--ink); }
.notice p:last-child { margin-bottom: 0; }

.accordion { border-top: 1px solid var(--line); }
.acc { border-bottom: 1px solid var(--line); }
.acc summary {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 26px 0; cursor: pointer; list-style: none;
  font-family: var(--font-display); font-size: clamp(18px, 2.1vw, 22px);
  font-weight: 500; color: var(--navy); letter-spacing: -.01em;
  transition: color .25s var(--ease);
}
.acc summary::-webkit-details-marker { display: none; }
.acc summary:hover { color: var(--blue); }
/* plus / minus indicator */
.acc summary::after {
  content: ""; flex: 0 0 auto; width: 16px; height: 16px; position: relative;
  background:
    linear-gradient(var(--blue), var(--blue)) center/16px 2px no-repeat,
    linear-gradient(var(--blue), var(--blue)) center/2px 16px no-repeat;
  transition: transform .3s var(--ease);
}
.acc[open] summary::after {
  background: linear-gradient(var(--blue), var(--blue)) center/16px 2px no-repeat;
  transform: rotate(180deg);
}
.acc-body { padding: 0 0 34px; animation: accIn .35s var(--ease-out) both; }
@keyframes accIn { from { opacity: 0; transform: translate3d(0,-6px,0); } to { opacity: 1; transform: none; } }
.acc-body > p { font-size: var(--fs-1); color: var(--muted); margin: 0 0 16px; line-height: 1.7; }
.acc-body h3 { margin-top: 30px; }

/* Numbered application steps */
.steps { list-style: none; counter-reset: step; padding: 0; margin: 0 0 20px; }
.steps li {
  counter-increment: step; position: relative; padding: 0 0 20px 52px;
  font-size: var(--fs-1); color: var(--muted); line-height: 1.7;
}
.steps li::before {
  content: counter(step); position: absolute; left: 0; top: 1px;
  width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  background: var(--navy); color: #fff; border-radius: 50%;
  font-family: var(--font-display); font-size: var(--fs--1); font-weight: 500;
}

/* Requirement / note bullets */
.req-list { list-style: none; padding: 0; margin: 0 0 20px; }
.req-list li {
  position: relative; padding: 0 0 14px 22px;
  font-size: var(--fs-1); color: var(--muted); line-height: 1.7;
}
.req-list li::before {
  content: ""; position: absolute; left: 0; top: 10px;
  width: 6px; height: 6px; background: var(--blue); border-radius: 50%;
}
.req-list li strong { color: var(--ink); }

.callout {
  background: #eaf2fb; border-left: 3px solid var(--blue);
  padding: 16px 20px; margin: 4px 0 18px;
}
.callout p { margin: 0; font-size: var(--fs-0); color: #10457a; }
.fineprint { font-size: var(--fs--1); color: var(--muted); margin: 0; }

/* Obfuscated address, kept as written so scrapers do not harvest it */
.email {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: var(--fs--1); background: var(--bg-soft); padding: 3px 8px;
  border: 1px solid var(--line); color: var(--ink); white-space: nowrap;
}

/* Useful links */
.useful-links { margin-top: 56px; padding-top: 34px; border-top: 2px solid var(--navy); }
.useful-links h2 { margin-bottom: 20px; }
.link-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 32px; }
.link-grid a {
  display: block; padding: 15px 0; border-bottom: 1px solid var(--line);
  font-size: var(--fs-1); color: var(--navy); transition: color .22s var(--ease);
}
/* Colour only. The old rule added padding-left on hover, which shifted the
   link text 8px and reflowed the row. */
.link-grid a:hover { color: var(--blue); text-decoration: none; }
@media (max-width: 700px) {
  .link-grid { grid-template-columns: 1fr; }
  .steps li { padding-left: 44px; }
  .email { white-space: normal; }
}

/* ========================= Social media page ======================== */
.social-wrap { padding: 44px 0 var(--band); max-width: 1180px; }

/* Channel cards */
.channels { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px 40px; margin-bottom: 72px; }
.channel {
  display: flex; flex-direction: column; color: inherit;
  border-top: 1.5px solid var(--line); padding: 22px 0 26px;
  transition: border-color .3s var(--ease);
}
a.channel:hover { border-top-color: var(--blue); text-decoration: none; }
.channel-net {
  font-family: var(--font-display); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--blue); margin-bottom: 8px;
}
.channel-handle {
  font-family: var(--font-display); font-size: var(--fs-3); font-weight: 500;
  color: var(--navy); letter-spacing: -.01em; transition: color .25s var(--ease);
}
a.channel:hover .channel-handle { color: var(--blue); }
.channel-desc { font-size: var(--fs-0); color: var(--muted); margin: 6px 0 14px; line-height: 1.6; flex: 1; }
.channel-go {
  align-self: flex-start; font-size: var(--fs--2); font-weight: 500; letter-spacing: .06em;
  color: var(--blue); border-bottom: 1px solid currentColor; padding-bottom: 2px;
}
.channel-sub iframe { width: 100%; height: 92px; border: 0; margin-top: 4px; }

/* Feed */
.feed-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 20px;
  padding-bottom: 18px; margin-bottom: 28px; border-bottom: 2px solid var(--navy);
}
.feed-head h2 { margin: 0; }
.feed-head a { font-size: var(--fs--1); font-weight: 500; }

/* Masonry-ish columns so posts of different lengths pack tightly */
.feed { columns: 3 330px; column-gap: 26px; }
.post {
  break-inside: avoid; margin: 0 0 26px; padding: 22px;
  background: #fff; border: 1px solid var(--line);
  transition: border-color .3s var(--ease), transform .3s var(--ease);
}
.post:hover { border-color: var(--blue); transform: translate3d(0,-2px,0); }
.post-repost {
  font-size: var(--fs-micro); color: var(--muted); margin-bottom: 12px;
  letter-spacing: .04em; padding-bottom: 10px; border-bottom: 1px dashed var(--line);
}
.post-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.post-avatar { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.post-who { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.post-who strong { font-size: var(--fs--1); color: var(--ink); font-weight: 600; }
.post-who span { font-size: var(--fs--2); color: var(--muted); overflow: hidden; text-overflow: ellipsis; }
.post-time { margin-left: auto; font-size: var(--fs-micro); color: var(--muted); flex: 0 0 auto; }
.post-text { font-size: var(--fs-0); line-height: 1.6; color: var(--ink); word-wrap: break-word; }
.post-text a { color: var(--blue); }

.post-images { display: grid; gap: 4px; margin-top: 14px; }
.post-images.one { grid-template-columns: 1fr; }
.post-images.two { grid-template-columns: 1fr 1fr; }
.post-images.many { grid-template-columns: 1fr 1fr; }
.post-images img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-images.one img { max-height: 340px; }
.post-images.two img, .post-images.many img { height: 130px; }

.post-link {
  display: flex; gap: 12px; margin-top: 14px; padding: 12px;
  border: 1px solid var(--line); color: inherit; align-items: center;
}
.post-link:hover { border-color: var(--blue); text-decoration: none; }
.post-link img { width: 62px; height: 62px; object-fit: cover; flex: 0 0 auto; }
.post-link-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.post-link-body strong { font-size: var(--fs--1); color: var(--navy); line-height: 1.35; }
.post-link-body span { font-size: var(--fs--2); color: var(--muted); line-height: 1.4; }

.post-meta {
  display: flex; gap: 14px; align-items: center; margin-top: 16px;
  padding-top: 12px; border-top: 1px solid var(--line);
  font-size: var(--fs-micro); color: var(--muted); letter-spacing: .02em;
}
.post-meta a { margin-left: auto; font-weight: 500; color: var(--blue); }

@media (max-width: 1000px) { .channels { grid-template-columns: repeat(2, 1fr); gap: 2px 28px; } }
@media (max-width: 640px) {
  .channels { grid-template-columns: 1fr; }
  .feed { columns: 1; }
}

/* ==================== Home page adjustments ========================= */
/* Hero: shorter so content starts sooner */
.hero { min-height: 62vh; }
.hero .hero-inner { position: relative; z-index: 2; max-width: 1000px; padding: 72px var(--gutter); }
@media (max-width: 820px) { .hero { min-height: 56vh; } }

/* Quote banner: brighter blue, sits between the two navy split bands */
.quote-banner {
  background: linear-gradient(100deg, var(--blue), #0f5e99);
  color: #fff; padding: 76px 0;
}
.quote-banner .quote { color: #fff; max-width: 940px; }
.quote-banner .quote cite { color: #bcdcf7; margin-top: 22px; }

/* Full-bleed people banner: bias the crop upward so faces are not cut off */

/* Closing full-bleed banner: it ends the page, so give it real presence */
.fullbleed img { width: 100%; object-fit: cover; border-radius: 0; max-height: 620px; object-position: 50% 28%; }
@media (max-width: 820px) { .fullbleed img { max-height: 340px; } }

/* ================= Fixes: sticky scroll, figures, layout =============
   overflow-x:hidden on body creates a scroll container, which silently
   disables position:sticky everywhere. overflow-x:clip prevents the
   sideways scrollbar without breaking sticky.                          */
body { overflow-x: clip; }

/* Specialize banners already carry a border in the artwork, so drop ours */
.banner-card img {
  width: 100%; height: auto; display: block;
  transition: border-color .3s var(--ease); border: 0; padding: 0; background: transparent; }
.banner-card { margin: 0; transition: transform .35s var(--ease); }
.banner-card:hover { transform: translate3d(0,-3px,0); }

/* Project figures: all four across in one row */
.project-grid { grid-template-columns: repeat(4, 1fr); gap: 40px 34px; }
.project-card img {
  width: 100%; height: auto; margin: 0 auto 18px;
  transition: transform .45s var(--ease); will-change: transform; max-width: 240px; margin-bottom: 14px; }
.project-card figcaption { color: var(--muted); margin: 0 auto; font-size: var(--fs-0); max-width: 300px; line-height: 1.6; }
@media (max-width: 1080px) { .project-grid { grid-template-columns: repeat(2, 1fr); gap: 40px 28px; } }
@media (max-width: 620px)  { .project-grid { grid-template-columns: 1fr; } }

/* Repo cards: stop the language label colliding with long repo names */
.repo-head { display: flex; justify-content: space-between; gap: 14px; margin-bottom: 8px; flex-wrap: wrap; align-items: baseline; row-gap: 4px; }
.repo-name {
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: 500;
  color: var(--navy); letter-spacing: -.01em; transition: color .25s var(--ease); min-width: 0; overflow-wrap: anywhere; }
.repo-lang {
  flex-shrink: 0; font-size: var(--fs-micro); font-weight: 500; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-left: auto; }

/* Attribution line under a video or frame sequence */
.media-credit {
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: rgba(255,255,255,.55); position: absolute; right: var(--gutter);
  bottom: 14px; z-index: 3;
}
.media-credit.on-light { color: var(--muted); position: static; text-align: right; margin-top: 10px; }

/* "Coming soon" affordance for links that are not live yet */
.soon {
  color: var(--muted) !important; cursor: default; border: 0;
  text-decoration: none !important;
}
.soon::after {
  content: "Coming soon"; display: inline-block; margin-left: 8px;
  font-family: var(--font-body); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  background: rgba(255,255,255,.14); color: #cfe0f5;
  padding: 3px 8px; vertical-align: 2px;
}
.on-light .soon::after, section.block .soon::after {
  background: var(--bg-soft); color: var(--muted); border: 1px solid var(--line);
}

/* OLH hardware band: same frame-sequence mechanics, shorter scroll run */
.olh-hero { height: 190vh; }
.olh-hero .frame-hero-inner h2 {
  margin: 0; color: #fff; font-size: clamp(30px, 4.4vw, 54px);
  font-weight: 400; letter-spacing: -.025em; line-height: 1.08;
}
.olh-hero .frame-hero-inner .eyebrow {
  display: block; font-family: var(--font-display); font-size: var(--fs--2);
  font-weight: 500; letter-spacing: .24em; text-transform: uppercase;
  color: var(--blue-light); margin: 0 0 14px;
}
.olh-hero .frame-hero-inner p { max-width: 620px; }
.olh-hero .frame-hero-inner .cta { margin-top: 26px; background: var(--blue); }
.olh-hero .frame-hero-inner .cta:hover { background: #fff; color: var(--navy); }
@media (max-width: 820px) { .olh-hero { height: 150vh; } }

/* ========================= Support / funders ======================== */
.funders { margin-top: 48px; }
.funders h2 { margin-bottom: 6px; }
.funder-intro { font-size: var(--fs-0); color: var(--muted); margin: 16px 0 0; }
.funder-list { list-style: none; padding: 0; margin: 0; }
.funder-list li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 20px;
  padding: 18px 0; border-bottom: 1px solid var(--line);
}
.funder-name {
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: 500;
  color: var(--navy); letter-spacing: -.01em;
}
.funder-note { font-size: var(--fs--1); color: var(--muted); margin-left: auto; text-align: right; }
.give { margin-top: 56px; padding-top: 34px; border-top: 2px solid var(--navy); }
/* .give h2 takes .lbl wholesale */
.give p { font-size: var(--fs-1); color: var(--muted); margin: 0 0 20px; max-width: 700px; }
.give .fineprint { margin-top: 22px; }
@media (max-width: 640px) { .funder-note { margin-left: 0; text-align: left; } }

/* ============================ News page ============================= */
.news-wrap { padding: 44px 0 var(--band); max-width: 1180px; }
.news-section-label { margin-top: 40px; }

/* Featured story: big image left, copy right */
.news-card.featured {
  display: grid; grid-template-columns: 1.15fr 1fr; gap: 0;
  border: 1px solid var(--line); margin-bottom: 8px;
  transition: border-color .3s var(--ease);
}
.news-card.featured:hover { border-color: var(--blue); }
.news-card.featured .news-thumb { height: 100%; min-height: 320px; }
.news-card.featured .news-body { padding: 40px 44px; display: flex; flex-direction: column; justify-content: center; }
.news-card.featured .news-title { font-size: clamp(23px, 2.6vw, 32px); }
.news-card.featured .news-summary { font-size: var(--fs-1); }

/* Filters */
.news-filter-label {
  font-family: var(--font-display); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted); margin-right: 8px;
}
.news-filter {
  font-family: var(--font-body); font-size: var(--fs--1); font-weight: 500;
  color: var(--navy); background: none; border: 1px solid var(--line);
  padding: 8px 16px; cursor: pointer; border-radius: 0;
  transition: background .22s var(--ease), color .22s var(--ease), border-color .22s var(--ease);
}
.news-filter:hover { border-color: var(--blue); color: var(--blue); }
.news-filter.active { background: var(--navy); border-color: var(--navy); color: #fff; }

/* Card grid */
.news-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px 34px; }
.news-card {
  display: flex; flex-direction: column; color: inherit; background: #fff;
  border: 1px solid var(--line);
  transition: border-color .3s var(--ease), transform .3s var(--ease);
}
/* The filter sets the `hidden` attribute to drop non-matching cards, but the
   explicit display above (and `grid` on featured cards) overrides the default
   [hidden] display:none, so a filtered card stayed on the page. Force it. */
.news-card[hidden] { display: none !important; }
.news-card:hover { border-color: var(--blue); text-decoration: none; transform: translate3d(0,-3px,0); }
.news-thumb { overflow: hidden; background: var(--bg-soft); height: 190px; flex: 0 0 auto; }
.news-thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .7s var(--ease); will-change: transform;
}
.news-card:hover .news-thumb img { transform: scale3d(1.05,1.05,1); }
.news-body { padding: 22px 24px 26px; display: flex; flex-direction: column; flex: 1; }
.news-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.news-tag {
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  color: var(--blue); background: #eaf2fb; padding: 4px 10px;
}
.news-title {
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: 500;
  line-height: 1.3; letter-spacing: -.01em; color: var(--navy); margin: 0 0 10px;
}
.news-card:hover .news-title { color: var(--blue); }
.news-summary { font-size: var(--fs--1); color: var(--muted); line-height: 1.6; margin: 0 0 16px; flex: 1; }
.news-meta {
  font-size: var(--fs-micro); letter-spacing: .06em; color: var(--muted);
  padding-top: 14px; border-top: 1px solid var(--line);
}
.news-empty { color: var(--muted); padding: 40px 0; font-size: var(--fs-1); }
.news-foot { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); color: var(--muted); font-size: var(--fs-0); }

@media (max-width: 1000px) {
  .news-grid { grid-template-columns: repeat(2, 1fr); gap: 32px 26px; }
  .news-card.featured { grid-template-columns: 1fr; }
  .news-card.featured .news-thumb { min-height: 240px; height: 240px; }
  .news-card.featured .news-body { padding: 28px 26px 32px; }
}
@media (max-width: 620px) { .news-grid { grid-template-columns: 1fr; } }

/* ============ Frame sequence: scroll-through, not pinned ============
   The earlier version pinned the section for 2+ viewports, so the page
   appeared to stall while the frames advanced. Now the band is a normal
   height and the frames advance as it travels through the viewport, so
   the page keeps moving and the footage progresses at the same time.  */
.frame-hero, .olh-hero { height: auto; }
@media (max-width: 820px) {
  .frame-hero .frame-hero-sticky, .olh-hero .frame-hero-sticky { height: 74vh; min-height: 420px; }
}

/* ======================== Publications page ========================= */
/* Shorter header */
.page-head.bleed.compact { padding: 34px 0 30px; }
.page-head.bleed.compact h1 { font-size: clamp(25px, 2.9vw, 35px); }
.page-head.bleed.compact p { font-size: var(--fs--1); margin-top: 7px; max-width: 640px; }
@media (max-width: 820px) {
  .page-head.bleed.compact { padding: 24px 0 22px; }
  .page-head.bleed.compact p { display: none; }   /* the title alone on a phone */
}

/* Full-width Google Scholar bar directly under the header */
.scholar-bar {
  display: block; background: var(--blue); color: #fff;
  transition: background .25s var(--ease);
}
.scholar-bar:hover { background: var(--navy); text-decoration: none; }
.scholar-bar .wrap {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  height: 52px;
}
.scholar-bar-text {
  font-family: var(--font-display); font-size: var(--fs--1); font-weight: 500;
  letter-spacing: .02em; color: #fff;
}
.scholar-bar-go { font-size: var(--fs--2); font-weight: 500; letter-spacing: .08em; color: #dbeafe; }
.scholar-bar:hover .scholar-bar-go { color: #fff; }

.pubs-wrap { max-width: 900px; padding: 56px 0 var(--band); }

.pub-section { margin-bottom: 64px; }
.pub-section-title { display: flex; align-items: baseline; gap: 12px; }
.pub-count {
  font-size: var(--fs-micro); letter-spacing: .1em; color: var(--muted);
  background: var(--bg-soft); padding: 3px 9px; border: 1px solid var(--line);
}

/* One publication per row: number, then a stacked block.
   Structured lines instead of a run-on citation, so nothing wraps oddly. */
.pub {
  display: grid; grid-template-columns: 38px minmax(0, 1fr); gap: 18px;
  padding: 26px 0; border-bottom: 1px solid var(--line);
}
.pub-num {
  font-family: var(--font-display); font-size: var(--fs--2); font-weight: 500;
  color: var(--muted); padding-top: 4px;
}
.pub-main { min-width: 0; }
.pub-title {
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: 500;
  line-height: 1.35; letter-spacing: -.01em; margin: 0 0 8px;
  color: var(--navy); overflow-wrap: break-word;
}
.pub-title a { color: inherit; }
.pub-title a:hover { color: var(--blue); text-decoration: none; }
.pub-authors {
  margin: 0 0 8px; font-size: var(--fs--1); line-height: 1.6; color: var(--muted);
  overflow-wrap: break-word;
}
.pub-authors strong { color: var(--ink); font-weight: 600; }
.pub-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; font-size: var(--fs--1); }
.pub-journal { font-style: italic; color: var(--ink); }
.pub-year { color: var(--muted); }
.pub-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.pub-links a {
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .05em; color: var(--blue);
  padding: 5px 12px; border: 1px solid var(--line);
  transition: background .22s var(--ease), border-color .22s var(--ease), color .22s var(--ease);
}
.pub-links a:hover { background: var(--navy); border-color: var(--navy); color: #fff; text-decoration: none; }
@media (max-width: 640px) {
  .pub { grid-template-columns: 1fr; gap: 6px; }
  .pub-num { display: none; }
  .scholar-bar .wrap { height: auto; padding-top: 12px; padding-bottom: 12px; }
  .scholar-bar-text { font-size: var(--fs--1); }
}

/* Per-project funder acknowledgement */
.funder-credit {
  margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: var(--fs--1); color: var(--muted);
}
.funder-credit strong { color: var(--ink); font-weight: 600; }
.split .funder-credit { border-top-color: rgba(255,255,255,.18); color: #9fb3d2; }
.split .funder-credit strong { color: #fff; }

/* ============================= PI page ============================== */
.pi-wrap { max-width: 1040px; padding: 52px 0 var(--band); }
.pi-top { display: grid; grid-template-columns: 300px minmax(0,1fr); gap: 52px; align-items: start; margin-bottom: 56px; }
.pi-portrait { margin: 0; }
.pi-portrait img { width: 100%; height: auto; display: block; }
.pi-role {
  font-family: var(--font-display); font-size: var(--fs--2); font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--blue); margin: 0 0 16px;
}
.pi-intro .lede { margin: 0 0 22px; }
.pi-links { display: flex; flex-wrap: wrap; gap: 8px; }
.pi-links a {
  font-size: var(--fs--2); font-weight: 500; letter-spacing: .04em; color: var(--blue);
  padding: 8px 16px; border: 1px solid var(--line);
  transition: background .22s var(--ease), border-color .22s var(--ease), color .22s var(--ease);
}
.pi-links a:hover { background: var(--navy); border-color: var(--navy); color: #fff; text-decoration: none; }

.pi-body { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 8px 56px; }
.pi-section { padding: 28px 0; border-top: 1px solid var(--line); }
.pi-section:first-child, .pi-section:nth-child(2) { border-top: 2px solid var(--navy); }
/* .pi-section h2 takes .lbl wholesale */
.pi-section p { font-size: var(--fs-0); color: var(--muted); line-height: 1.7; margin: 0; }
.pi-list { list-style: none; padding: 0; margin: 0; }
.pi-list li {
  position: relative; padding: 0 0 10px 18px; font-size: var(--fs-0); color: var(--muted); line-height: 1.6;
}
.pi-list li::before {
  content: ""; position: absolute; left: 0; top: 9px;
  width: 5px; height: 5px; background: var(--blue-light); border-radius: 50%;
}
.pi-list li strong { color: var(--ink); }
.pi-contact { margin-bottom: 18px !important; }
@media (max-width: 860px) {
  .pi-top { grid-template-columns: 1fr; gap: 28px; }
  .pi-portrait { max-width: 260px; }
  .pi-body { grid-template-columns: 1fr; }
  .pi-section:nth-child(2) { border-top: 1px solid var(--line); }
}

/* Subscribe popout */
.channel-btn {
  background: none; border: 0; border-top: 1.5px solid var(--line);
  text-align: left; cursor: pointer; font: inherit; padding: 22px 0 26px;
}
.channel-btn:hover { border-top-color: var(--blue); }
.channel-btn:hover .channel-handle { color: var(--blue); }
.sub-modal {
  display: none; position: fixed; inset: 0; z-index: 200;
  background: rgba(8,13,28,.78); align-items: center; justify-content: center; padding: 24px;
}
.sub-modal.open { display: flex; }
.sub-panel {
  position: relative; background: #fff; max-width: 520px; width: 100%;
  max-height: 88vh; overflow-y: auto; padding: 40px 40px 36px;
  animation: lbIn .28s var(--ease-out) both;
}
.sub-panel h2 {
  font-family: var(--font-display); font-size: var(--fs-4); font-weight: 500;
  margin: 0 0 26px; letter-spacing: -.015em;
}
.sub-close {
  position: absolute; top: 14px; right: 18px; background: none; border: 0;
  font-size: 30px; line-height: 1; color: var(--muted); cursor: pointer;
}
.sub-close:hover { color: var(--ink); }
.sub-block:first-of-type { border-top: 2px solid var(--navy); }
.sub-block h3 {
  font-family: var(--font-display); font-size: var(--fs-1); font-weight: 500;
  margin: 0 0 6px; color: var(--navy);
}
.sub-block p { font-size: var(--fs--1); color: var(--muted); margin: 0 0 14px; line-height: 1.6; }
@media (max-width: 560px) { .sub-panel { padding: 34px 22px 28px; } }

/* ==================== Funding & support: funder tiles ===============
   Grouped by funder. The awards stay tucked away until hover or focus so
   grant titles are not shouting at the reader.                        */
.give-top {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 24px; margin: 36px 0 12px; padding: 28px 32px;
  background: var(--navy); border: 0;
}
.give-top .give-body { max-width: 560px; }
.give-top h2 { color: var(--blue-light); margin: 0 0 10px; }
.give-top p { color: #b9c9e2; margin: 0 0 8px; font-size: var(--fs-0); }
.give-top .fineprint { color: #8ea5c6; font-size: var(--fs--1); margin: 0; }
.give-top .fineprint a { color: var(--blue-light); }
.give-top .cta { flex: 0 0 auto; background: var(--blue); margin: 0; }
.give-top .cta:hover { background: #fff; color: var(--navy); }

.funder-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 32px; margin-top: 12px;
}
/* Awards are always visible; see the canonical .funder-detail rule below.
   The previous 0fr -> 1fr hover expansion reflowed the whole page, which is
   why it was abandoned. Do not reintroduce it. */
.funder-detail-inner { overflow: hidden; }
.funder-detail li:last-child { margin-bottom: 0; }
.fp-inst, .fp-tag, .fp-year {
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .09em; text-transform: uppercase;
}
.fp-inst { color: var(--blue); }
.fp-tag { color: var(--muted); background: var(--bg-soft); padding: 3px 8px; border: 1px solid var(--line); }
@media (max-width: 760px) {
  .funder-grid { grid-template-columns: 1fr; }
  .give-top { padding: 24px; }
}

/* Bluesky mark in the nav instead of a text link */
.nav-bsky { display: inline-flex; align-items: center; }
.nav-bsky:hover img { opacity: 1; transform: translate3d(0,-1px,0); }

/* Open positions on Join Us */
.jobs { margin: 34px 0 40px; padding: 26px 28px; background: var(--bg-soft); border-left: 3px solid var(--blue); }
.jobs h2 { margin-bottom: 10px; }
.jobs-intro, .jobs-empty { font-size: var(--fs-0); color: var(--muted); margin: 0 0 18px; line-height: 1.65; }
.jobs-empty { margin-bottom: 0; }
.job-list { list-style: none; padding: 0; margin: 0 0 16px; }
.job {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px;
  padding: 16px 0; border-top: 1px solid var(--line);
}
.job-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.job-title { font-family: var(--font-display); font-size: var(--fs-1); font-weight: 500; color: var(--navy); }
.job-meta { font-size: var(--fs--2); color: var(--muted); letter-spacing: .02em; }
.job-apply {
  flex: 0 0 auto; font-size: var(--fs--2); font-weight: 500; letter-spacing: .04em;
  color: #fff; background: var(--navy); padding: 9px 20px;
  transition: background .22s var(--ease);
}
.job-apply:hover { background: var(--blue); text-decoration: none; }

/* =============== Lab photos: no cropping, true masonry ==============
   The grid version forced every photo into a fixed-height tile with
   object-fit: cover, which sliced heads off group shots. CSS columns let
   each image keep its own aspect ratio, so nothing is cut.            */
.gallery { display: block; }
.gallery-columns { columns: 3 300px; column-gap: 16px; }
.gphoto {
  break-inside: avoid; display: block; margin: 0 0 16px; width: 100%;
  position: relative; overflow: hidden; cursor: zoom-in; background: var(--bg-soft);
  opacity: 0; transform: translate3d(0,16px,0);
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
}
.gphoto.in { opacity: 1; transform: none; }
.gphoto img {
  will-change: transform;
  width: 100%; height: auto; display: block;      /* natural proportions */
  object-fit: initial;
  transition: transform .7s var(--ease), filter .4s var(--ease);
}
.gphoto:hover img { transform: scale3d(1.03,1.03,1); }
.gphoto.wide, .gphoto.tall { grid-column: auto; grid-row: auto; }

/* Year headings when the album exposes dates */
.photo-year { margin-top: 40px; }
.photo-year:first-child { margin-top: 0; }

@media (max-width: 900px) { .gallery-columns { columns: 2 220px; column-gap: 12px; } }
@media (max-width: 560px) { .gallery-columns { columns: 1; } }

/* Frame bands: taller, so the footage stays on screen longer while you scroll
   and the motion reads clearly rather than flashing past. */
.frame-hero .frame-hero-sticky {
  position: relative; top: auto;
  overflow: hidden; display: flex; align-items: center;
  height: 118vh; min-height: 660px; max-height: 1100px;
}
.olh-hero .frame-hero-sticky {
  height: 108vh; min-height: 600px; max-height: 980px;
}
@media (max-width: 820px) {
  .frame-hero .frame-hero-sticky { height: 86vh; min-height: 460px; }
  .olh-hero .frame-hero-sticky   { height: 82vh; min-height: 440px; }
}

/* ============ Publications: flowing citations, phase sections ======= */
.pub-sub {
  font-family: var(--font-display); font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
  margin: 28px 0 12px;
}
.pub-list { padding: 0; counter-reset: pub; list-style: decimal; padding-left: 26px; margin: 0 0 8px; }
.pub::marker { color: var(--muted); font-size: var(--fs--2); }
.pub strong { color: var(--ink); font-weight: 600; }
.pub .pub-title { font-weight: 500; color: var(--navy); }
a.pub-title:hover { color: var(--blue); }
.pub .pub-pmcid { font-size: var(--fs--2); white-space: nowrap; }

/* ================== Research: How we do it, figures ================= */
.method img { width: 230px; height: 230px; }
.method h3 { font-weight: var(--fw-med); font-size: var(--fs-2); margin: 0 0 8px; letter-spacing: var(--tr-snug); }
.method p { font-size: var(--fs-0); color: var(--muted); margin: 0 auto; max-width: 250px; line-height: 1.6; }
@media (max-width: 980px) { .method img { width: 180px; height: 180px; } }

/* Directed evolution figure was overwhelming the section */
/* Cap the height so the whole "What is directed evolution?" section (title,
   lead, and this diagram) fits within one laptop viewport instead of forcing a
   scroll. width:auto lets it shrink to satisfy both constraints. */
.figure-wide img {
  display: inline-block; width: auto; height: auto;
  max-width: 100%; max-height: 50vh;   /* 100% keeps the height cap from
                                          forcing horizontal overflow on mobile */
}

/* ================= Nav: dropdown wide enough for one line ========== */
.nav .links .dropdown-menu { min-width: max-content; white-space: nowrap; }
.nav .links .dropdown-menu a {
  display: block; padding: 10px 14px; color: #cfdcf0; font-size: var(--fs--1);
  transition: background .2s var(--ease), color .2s var(--ease); white-space: nowrap; }

/* Bluesky mark: the source art is dark, so invert it on the navy bar */
.nav-bsky img {
  height: 20px; width: auto; display: block;
  opacity: .8; transition: opacity .25s var(--ease), transform .25s var(--ease); filter: brightness(0) invert(1); }

/* ============== Open-source resources: header + light OLH ==========
   The intro used to sit in a skinny white band between the dark header and the
   dark OLH split, which read as a disjointed light stripe. It now lives on the
   header (right side, white over the image), and the OLH split is a light-blue
   panel, so the page reads as one dark header into one light section.        */
.osr-head .osr-head-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 20px 56px; align-items: end;
}
.osr-head-intro {
  margin: 0; align-self: end; color: #dbe6f6;
  font-size: var(--fs-2); line-height: 1.5; font-weight: var(--fw-book);
}
@media (max-width: 820px) {
  .osr-head .osr-head-grid { grid-template-columns: 1fr; align-items: start; }
  .osr-head-intro { font-size: var(--fs-1); }
}

/* Light-blue split variant: pale blue field, dark text. Used for the OLH so it
   contrasts the dark header instead of extending it. */
.split.light { background: #e6eff9; color: var(--ink); }
.split.light .section-title { color: var(--navy); }
.split.light .section-lead, .split.light p { color: var(--muted); }
.split.light .eyebrow { color: var(--blue); }
.split.light .tool-list li { border-color: rgba(22,36,77,.14); }
.split.light .tool-list a { color: var(--navy) !important; }
.split.light .tool-list a:hover { color: var(--blue) !important; }
.split.light .tool-list span { color: var(--muted); }
.split.light .funder-credit { color: var(--muted); border-top-color: rgba(22,36,77,.14); }
.split.light .funder-credit strong { color: var(--ink); }
.split.light .soon::after { background: #fff; color: var(--muted); border: 1px solid var(--line); }
.split.light .split-media::after { background: none; }   /* no dark seam on a light field */
/* Light fade at the top of the OLH image, so it does not blend into the dark
   header image sitting directly above it. */
.split.light .split-media::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(230,239,249,.85) 0%, rgba(230,239,249,0) 24%);
}

/* Two feature cards read as halves, not thirds (no third-column gap). */
.repo-list.two-up { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 700px) { .repo-list.two-up { grid-template-columns: 1fr; } }

/* ===================== Funders: calmer reveal ====================== */

/* ================= People: larger member photos ==================== */
.headshot { border-radius: 50%; object-fit: cover;
  background: var(--bg-soft); box-shadow: none; display: block;
  transition: transform .4s var(--ease); will-change: transform; width: 168px; height: 168px; }
.member-group.pi .headshot { width: 200px; height: 200px; }
.member-group.pi .member-card { grid-template-columns: 200px minmax(0,1fr); }
.member-card .member-photo { margin-bottom: 18px; }
.member-name {
  font-family: var(--font-display); font-weight: 500;
  margin: 0 0 4px; letter-spacing: -.01em; font-size: var(--fs-2); }
@media (max-width: 1080px) { .headshot { width: 150px; height: 150px; } }

/* ============= Social: compact channel strip, not tall cards ======== */
.channel-strip {
  display: flex; flex-wrap: wrap; gap: 10px;
  padding: 34px 0 8px; margin-bottom: 40px;
}
.chip {
  display: inline-flex; align-items: baseline; gap: 10px;
  padding: 11px 18px; border: 1px solid var(--line); background: #fff;
  color: inherit; font: inherit; cursor: pointer;
  transition: border-color .22s var(--ease), background .22s var(--ease);
}
.chip:hover { border-color: var(--blue); background: var(--bg-soft); text-decoration: none; }
.chip-net {
  font-size: var(--fs-micro); font-weight: 500; letter-spacing: .16em;
  text-transform: uppercase; color: var(--blue);
}
.chip-handle {
  font-family: var(--font-display); font-size: var(--fs-0); font-weight: 500; color: var(--navy);
}
@media (max-width: 620px) { .chip { flex: 1 1 100%; justify-content: space-between; } }

/* Join Us subheader */
.join-subhead {
  font-family: var(--font-display); font-size: clamp(20px, 2.4vw, 27px);
  font-weight: 400; color: var(--ink); letter-spacing: -.015em;
  margin: 44px 0 20px;
}

/* Featured news: lead card at two thirds, nothing beside it */
.news-card.featured { max-width: 66.6%; }
@media (max-width: 1000px) { .news-card.featured { max-width: 100%; } }

/* Lab handbook highlight band */
.handbook-band {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 20px; padding: 30px 34px; background: var(--navy); color: #fff; margin: 8px 0 0;
}
.handbook-band .hb-body { max-width: 640px; }
.handbook-band h2 {
  font-family: var(--font-display); font-size: var(--fs-3); font-weight: 500;
  margin: 0 0 8px; color: #fff; letter-spacing: -.01em;
}
.handbook-band p { margin: 0; font-size: var(--fs-0); color: #b9c9e2; line-height: 1.6; }
.handbook-band .cta { flex: 0 0 auto; background: var(--blue); margin: 0; }
.handbook-band .cta:hover { background: #fff; color: var(--navy); }

/* ========== Publications: citation reads as one continuous line =====
   An earlier heading-style rule for .pub-title was still applying, which
   made the title sit at 19.5px against 15.5px author text and pushed the
   trailing journal/year onto their own line.                          */
/* Title in the accent blue so it stands out from the authors while scrolling;
   journal in bold italic navy, matching the bolded author colour. */
.pub .pub-title,
.pub a.pub-title {
  display: inline; font-family: var(--font-body); font-size: inherit;
  font-weight: 600; line-height: inherit; margin: 0; letter-spacing: 0;
  color: var(--blue);
}
.pub a.pub-title:hover { color: var(--navy); text-decoration: underline; }
.pub .pub-tail { white-space: nowrap; }
.pub .pub-journal { font-style: italic; font-weight: 600; color: var(--navy); }
.pub .pub-year { color: var(--muted); }
.pub-section > .pub-sub:first-child { margin-top: 0; }

/* ============ News: filters first, 2/3 + 1/3 featured row ========== */
.news-filters {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-bottom: 20px; border-bottom: 1px solid var(--line); margin: 34px 0 26px; }
.news-featured-wrap { margin-bottom: 44px; }
.news-featured-row {
  display: grid; grid-template-columns: 2fr 1fr; gap: 26px; align-items: stretch;
}
.news-card.featured { max-width: none; grid-template-columns: 1fr 1fr; }
.news-card.featured .news-thumb { min-height: 300px; height: 100%; }
.news-featured-row > .news-card:not(.featured) .news-thumb { height: 200px; }
@media (max-width: 1000px) {
  .news-featured-row { grid-template-columns: 1fr; }
  .news-card.featured { grid-template-columns: 1fr; }
}

/* Subscribe popup: give the Substack embed room so it is not clipped */
.sub-panel { max-width: 560px; }
.sub-block iframe {
  width: 100%; height: 150px; border: 0; display: block;
  background: var(--bg-soft);
}
.sub-block { border-top: 1px solid var(--line); padding: 24px 0 26px; }
.sub-block:last-of-type { padding-bottom: 4px; }
.sub-block .cta { margin-top: 4px; }

/* ==================== Looping video bands ==========================
   Replaces the canvas frame-sequence. A scroll-scrubbed sequence can only
   advance as fast as the user scrolls, so it always reads as steppy; native
   video plays at full frame rate and is hardware decoded. The clips are
   palindromes (forward then reversed) so looping is seamless.        */
.video-band { position: relative; background: var(--navy-950); }
.video-band-inner {
  position: relative; overflow: hidden;
  height: 84vh; min-height: 560px; max-height: 900px;
  display: flex; align-items: center;
}
.video-band-media {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: .68; z-index: 0;   /* raised from .5: footage was hard to read */
  will-change: transform;                       /* gentle parallax, set from JS */
}
.video-band-inner::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  /* Lightened the mid-band so the video reads, while keeping top/bottom dark
     enough for the white headline and the scroll cue to stay legible. */
  background: linear-gradient(180deg, rgba(9,16,36,.55) 0%, rgba(9,16,36,.20) 45%, rgba(9,16,36,.82) 100%);
}
.video-band-copy { position: relative; z-index: 2; width: 100%; color: #fff; }
.video-band-copy h1 {
  margin: 0; color: #fff; font-size: clamp(38px, 6vw, 72px);
  font-weight: 400; letter-spacing: -.025em; line-height: 1.05;
}
.video-band-copy h2 {
  margin: 0; color: #fff; font-size: clamp(30px, 4.4vw, 54px);
  font-weight: 400; letter-spacing: -.025em; line-height: 1.08;
}
.video-band-copy p { margin: 20px 0 0; color: #c3d2e8; font-size: var(--fs-2); max-width: 640px; }
.video-band-copy .eyebrow {
  display: block; font-family: var(--font-display); font-size: var(--fs--2);
  font-weight: 500; letter-spacing: .24em; text-transform: uppercase;
  color: var(--blue-light); margin: 0 0 14px;
}
.video-band-copy .cta { margin-top: 26px; background: var(--blue); }
.video-band-copy .cta:hover { background: #fff; color: var(--navy); }
.olh-band .video-band-inner { height: 78vh; min-height: 520px; max-height: 820px; }
/* The Research header is a portrait-scale photo of a person, not footage of a
   machine, so the full-bleed 84vh band that suited the clip crops hard into the
   subject and opens the page with a face at close to life size. Half the
   viewport, header included, keeps it a header rather than a portrait, and at
   this height the 2500x843 source barely needs cropping at all. */
#researchHero .video-band-inner { height: 42vh; min-height: 300px; max-height: 520px; }
@media (max-width: 820px) {
  .video-band-inner { height: 70vh; min-height: 440px; }
  .olh-band .video-band-inner { height: 66vh; min-height: 420px; }
  #researchHero .video-band-inner { height: 40vh; min-height: 260px; }
}
/* Users who ask for less motion get a still frame */
@media (prefers-reduced-motion: reduce) {
  video.video-band-media { display: none; }
  .video-band-inner {
    background-image: var(--poster); background-size: cover; background-position: center;
  }
}

/* Repo card that is not itself a link (LABEEs credits another lab) */
.repo-plain { cursor: default; }
.repo-plain:hover { border-top-color: var(--line); }
.repo-plain .repo-name { color: var(--navy); }
.repo-plain .repo-links { margin: 14px 0 12px; }

/* Citation stays on one flowing line even if a reference-manager extension
   injects an icon next to a link */
.pub { grid-template-columns: none; gap: 0;
  padding: 9px 0; border-bottom: 0;
  font-size: var(--fs-0); line-height: 1.65; color: var(--muted); overflow-wrap: normal; word-break: normal; display: list-item; }
.pub > .pub-title { white-space: normal; }
.pub img, .pub svg { display: none !important; }   /* stray injected glyphs */

/* ============ Funders: static, no hover expansion =================
   Expanding a tile on hover reflowed everything around it, which reads
   as the whole page twitching. Awards are simply always visible now,
   set small and muted so they stay quiet. Nothing moves.            */
.funder { cursor: default; outline: none; transition: background .25s var(--ease), border-color .25s var(--ease); border-top: 1.5px solid var(--line); padding: 0 0 4px; background: none; }
.funder:hover, .funder:focus-within { background: none; border-top-color: var(--line); }
.funder-face { align-items: baseline; justify-content: space-between; gap: 14px; display: block; padding: 18px 0 6px; }
.funder-title {
  font-family: var(--font-display); font-weight: 500; letter-spacing: -.01em; line-height: 1.3; transition: none; display: block; font-size: var(--fs-2); color: var(--navy); }
.funder:hover .funder-title, .funder:focus-within .funder-title { color: var(--navy); }
.funder-count {
  flex: 0 0 auto; font-weight: 500;
  display: block; margin-top: 4px; font-size: var(--fs-micro); letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
/* always open, no transition, no grid-template-rows animation */
.funder-detail {
  display: block; grid-template-rows: none; opacity: 1; transition: none;
}
.funder-detail ul { list-style: none; padding: 0 0 16px; margin: 0; }
.funder-detail li {
  margin-bottom: 8px;
  padding: 6px 0 6px 12px; border-left: 2px solid var(--line); margin: 0 0 6px;
}
.fp-title { display: block; font-size: var(--fs--1); color: var(--muted); line-height: 1.5; }
.fp-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 3px; }
.fp-year { color: var(--muted); margin-left: 0; }
.funder-grid { gap: 0 40px; }

/* Funder tile heading as a link when a Funder URL is set. Keeps the navy
   weight of the plain heading; only the hover colour marks it clickable. */
a.funder-title { color: var(--navy); transition: color .22s var(--ease); }
a.funder-title:hover { color: var(--blue); text-decoration: none; }

/* Collapsed fellowship block: all of a funder's training awards under one
   "Trainee fellowships" heading, each row naming the recipient. The outer
   <li> already carries the hairline rule; the inner list is flush. */
.fp-fellows > .fp-title { margin-bottom: 6px; }
.fellow-list { list-style: none; padding: 0; margin: 0; }
.fellow-list .fellow-row {
  border-left: 0; padding: 0; margin: 0 0 7px;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
}
.fellow-list .fellow-row:last-child { margin-bottom: 0; }
.fellow-name { font-size: var(--fs-0); color: var(--ink); }
.fellow-list .fp-meta { margin-top: 0; }

/* Trainee fellowships: a clean flat list, two columns, no funder tiles or
   annotations. Each row is a name with a small institute/funder tag and the
   period, so NIH, NSF and roster-held awards all sit together plainly. */
.fellow-flat {
  list-style: none; margin: 8px 0 0; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 56px;
}
.fellow-flat .fellow-flat-row {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px;
  padding: 13px 0; border-bottom: 1px solid var(--line);
}
.fellow-flat .fellow-name { font-size: var(--fs-1); color: var(--ink); }
.fellow-flat .fp-meta { margin-top: 0; }
.funders-fellows { margin-bottom: 28px; }
@media (max-width: 760px) { .fellow-flat { grid-template-columns: 1fr; gap: 0; } }

/* Past funding grid: quieter than the current one, so completed awards read
   as an archive rather than competing with active support. */
/* Past funding read as a stray fragment tacked onto the fellowship list: only
   8px of separation from it, the same label tier as the section above, and an
   intro line pinned between its own hairline and the first tile's top border.
   With one completed award the tile filled half a two-column grid, so that
   border stopped dead in the middle of the page and the whole thing looked
   unfinished rather than quiet. Now a self-contained closing panel. */
.funders-past {
  margin-top: 56px; padding: 28px 32px 32px;
  background: var(--bg-tint); border: 1px solid var(--line);
}
.funders-past > h2 { margin-top: 0; border-bottom-color: #d8e0ed; }
.funders-past .funder-intro { margin: 0 0 20px; }
.funders-past .funder-grid { margin-top: 0; }
/* A lone tile spans the panel, so its rule runs the full width instead of
   halfway. */
.funders-past .funder-grid > .funder:only-child { grid-column: 1 / -1; }
.funders-past .funder { border-top-color: #d8e0ed; }
.funders-past .funder-title, .funders-past a.funder-title { color: var(--muted); }
.funders-past a.funder-title:hover { color: var(--navy); }
@media (max-width: 700px) { .funders-past { padding: 22px 20px 24px; } }

/* ============================== CV page ============================
   A CV is a table of dates against entries, so it is set as one: a fixed
   date rail, the entry, and the place set right. Every document line used
   to be an <li> of the same weight with a hairline under it, which turned
   28 talks into a wall and left an institution name looking like a course
   code. Rules now divide GROUPS, not lines; the rail does the scanning.
   Markup comes from scripts/sync_cv.py, which classifies each line.     */
.cv-layout {
  display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 52px;
  align-items: start; padding: 40px 0 var(--band);
}
.cv-body { min-width: 0; max-width: 900px; }
.cv-note {
  font-size: var(--fs--1); color: var(--muted); padding: 0 0 26px; margin: 0 0 8px;
  border-bottom: 1px solid var(--line);
}
.cv-section { margin-top: 54px; scroll-margin-top: 132px; }
.cv-section:first-of-type { margin-top: 0; }
/* .cv-heading takes .lbl-rule wholesale */
.cv-list { list-style: none; padding: 0; margin: 0; }
.cv-list strong { color: var(--ink); font-weight: 600; }
.cv-list em { font-style: italic; }
.cv-list a { color: var(--blue); overflow-wrap: anywhere; }

/* Section links: a sticky rail, same idiom as the handbook contents. Static,
   no scroll-spy, so nothing on the page changes while it is being read. */
.cv-toc {
  position: sticky; top: 134px; align-self: start;
  max-height: calc(100vh - 164px); overflow-y: auto; overscroll-behavior: contain;
  border-left: 1px solid var(--line);
}
.cv-toc a {
  display: block; padding: 5px 0 5px 16px; margin-left: -1px;
  border-left: 2px solid transparent; color: var(--muted);
  font-size: var(--fs--1); line-height: 1.4;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.cv-toc a:hover { color: var(--navy); border-left-color: var(--line); text-decoration: none; }
.cv-toc .cv-toc-l1 { color: var(--navy); }
.cv-toc .cv-toc-l2 { padding-left: 30px; font-size: var(--fs--2); }

/* Subsections inside a grouped heading (pre-prints, reviews, patents). */
.cv-subheading { margin: 40px 0 10px; scroll-margin-top: 132px; }
.cv-section > .cv-subheading:first-of-type { margin-top: 6px; }

/* One entry: date rail | entry | place. */
.cv-row {
  display: grid; grid-template-columns: 104px minmax(0, 1fr) auto;
  gap: 0 22px; align-items: baseline;
  padding: 7px 0; font-size: var(--fs-0); line-height: 1.6; color: var(--ink);
}
.cv-date {
  grid-column: 1; font-family: var(--font-display); font-size: var(--fs--1);
  font-weight: 500; letter-spacing: .02em; color: var(--navy); white-space: nowrap;
}
.cv-main { grid-column: 2; min-width: 0; overflow-wrap: break-word; }
.cv-where {
  grid-column: 3; font-size: var(--fs--1); color: var(--muted);
  text-align: right; max-width: 30ch;
}
.cv-role { color: var(--muted); margin-right: .5em; }   /* "Invited Talk" */
.cv-code { color: var(--muted); }                       /* "[CHEMENG300]" */
/* A line with no date and no emphasis is subordinate to the one above it:
   an advisor, a department, a minor. */
.cv-row.quiet { color: var(--muted); font-size: var(--fs--1); padding: 3px 0; }
/* An entry's indented description, folded in from the doc as a sub-line
   rather than its own bullet. */
.cv-desc {
  display: block; margin: 4px 0 2px; max-width: 68ch;
  font-size: var(--fs--1); color: var(--muted); line-height: 1.55;
}
.cv-row.has-desc { padding: 14px 0; border-bottom: 1px solid var(--line); }
.cv-list > .cv-row.has-desc:last-child { border-bottom: 0; }

/* Institution or block header: the only rule inside a section. */
.cv-group {
  display: flex; align-items: baseline; justify-content: space-between; gap: 18px;
  margin: 30px 0 6px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
.cv-list > .cv-group:first-child { margin-top: 0; }
.cv-group-name {
  font-family: var(--font-display); font-size: var(--fs-1); font-weight: 500;
  letter-spacing: .01em; color: var(--navy);
}
.cv-group-where { font-size: var(--fs--1); color: var(--muted); white-space: nowrap; }

/* Reference lists keep the document's own "1)." numbers (never renumbered),
   so there is no CSS counter here: the number hangs in the rail as text. */
.cv-ref {
  display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 0 16px;
  padding: 13px 0; font-size: var(--fs-0); line-height: 1.62; color: var(--muted);
  border-bottom: 1px solid var(--line);
}
.cv-refs > .cv-ref:last-child { border-bottom: 0; }
.cv-num {
  grid-column: 1; font-family: var(--font-display); font-size: var(--fs--1);
  color: var(--muted);
}
.cv-ref .cv-main { color: var(--muted); }
/* same emphasis as /publications: the quoted title carries the row */
.cv-ref em { color: var(--navy); }

/* Fallback: a cache written before the column layout still carries these. */
.cv-lead { color: var(--ink); }
.cv-bit { color: var(--muted); }
.cv-bit::before { content: " \00B7 "; color: var(--line); }

/* cascade pair: no room for a side rail. minmax(0, 1fr), not 1fr: a plain 1fr
   cannot shrink below its widest item, which is what let the handbook scroll
   sideways on a phone. */
@media (max-width: 900px) {
  .cv-layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .cv-toc { display: none; }               /* the sticky title bar carries the page */
}

/* cascade pair: the rail cannot hold a column on a phone. */
@media (max-width: 720px) {
  .cv-row {
    grid-template-columns: minmax(0, 1fr); gap: 0;
    padding: 11px 0; border-bottom: 1px solid var(--line);
  }
  .cv-date, .cv-main, .cv-where { grid-column: 1; }
  .cv-date { margin-bottom: 2px; }
  .cv-where { text-align: left; white-space: normal; margin-top: 2px; }
  .cv-list > li:last-child { border-bottom: 0; }
  .cv-ref { grid-template-columns: 30px minmax(0, 1fr); gap: 0 10px; }
  .cv-nav .wrap { gap: 5px; padding-top: 11px; padding-bottom: 11px; }
}

/* Join Us: only the step title is a block; other bold runs stay inline so
   phrases like "two admission cycles:" do not orphan their punctuation */
.steps li strong { color: var(--ink); margin-bottom: 3px; display: inline; }
.steps li > strong:first-child { display: block; margin-bottom: 3px; }
.policy-note {
  display: block; margin: 10px 0; padding: 12px 16px;
  background: var(--bg-soft); border-left: 3px solid var(--blue);
  font-size: var(--fs-0); color: var(--ink);
}
.deadlines { margin-top: 10px; }
/* section heading matched to the accordion summaries */
.join-subhead.accordion-scale {
  font-size: clamp(18px, 2.1vw, 22px); font-weight: 500; color: var(--navy);
  margin: 48px 0 14px;
}
