/* ==========================================================================
   MemoryAnchors — visual system matched to flex-pi.github.io
   Dark tokens are the authored base; a full [data-theme="day"] layer
   overrides them, and the page SHIPS "day" (cream #f6f6ef paper, #0c0c0c
   ink) by default, exactly like the reference. IBM Plex Sans for body and
   headings, IBM Plex Serif for metadata/small text, a muted teal accent, 4px radii.
   ========================================================================== */

/* ---------- base (night) tokens ---------- */
:root {
  /* midnight-blue night, mirroring the day layer's aqua/teal-navy pairing
     rather than the reference's neutral near-black. Ink and overlay tokens
     carry the same cool tint (#dbe7f5) so borders and surfaces read as part
     of the blue family instead of a neutral gray film over it. */
  --bg:            #0d1524;
  --bg-raise:      #121c2e;
  --muted:         #18233a;
  --fg:            #f2f6fc;
  --fg-muted:      rgba(219,231,245,.76);
  --fg-dim:        rgba(219,231,245,.58);
  --fg-faint:      rgba(219,231,245,.40);
  --border:        rgba(219,231,245,.22);
  --border-soft:   rgba(219,231,245,.13);
  --border-faint:  rgba(219,231,245,.08);
  --surface:       rgba(219,231,245,.035);
  --surface-2:     rgba(219,231,245,.07);
  --surface-3:     rgba(219,231,245,.13);

  /* most figures are PNGs/SVGs authored with dark text on a light ground,
     so their frame stays light even in the dark theme rather than following
     --muted into near-black (which would make the dark text unreadable) */
  --media-bg:      #eef3f7;
  /* caption/code text sitting inside a --media-bg frame: that frame is
     always light in both themes, so this stays a fixed dark tone rather
     than following --fg-faint (which turns white in the dark theme and
     disappears against the light frame) */
  --media-fg:      rgba(12, 16, 16, .68);

  --primary:       var(--palette-teal);
  --primary-ink:   color-mix(in srgb, var(--palette-teal), white 40%);
  --primary-soft:  color-mix(in srgb, var(--palette-teal) 18%, transparent);

  /* extended palette — not all in use yet, kept for future accents */
  --palette-sage:   #8cb369;
  --palette-olive:  #c0cb77;
  --palette-butter: #f4e285;
  --palette-orange: #f4a259;
  --palette-khaki:  #a8986b;
  --palette-teal:   #5b8e7d;
  --palette-mauve:  #8c6d67;
  --palette-red:    #bc4b51;

  --ff-body:    "IBM Plex Sans", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --ff-display: "IBM Plex Sans", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --ff-mono:    "IBM Plex Serif", Georgia, "Times New Roman", serif;

  --fs-meta: 11px;
  --ls-meta: .08em;
  --fs-fine: 13px;

  --col-text: 812px;
  --col-mid:  940px;
  --col-wide: 1140px;
  --col-full: 1340px;
  --pad:      clamp(18px, 4vw, 44px);
  --measure:  calc(var(--col-text) - 2 * var(--pad));
  --gap-sec:  clamp(60px, 7.5vw, 112px);

  --radius:      4px;
  --radius-pill: 999px;
  --ease: cubic-bezier(.22,.61,.36,1);

  --rail-w: 176px; --rail-gap: 44px; --rail-shift: 0px;
}

/* ---------- day layer: the shipped theme ---------- */
[data-theme="day"] {
  /* ocean/tropical daylight paper: pale aqua ground, deep teal-navy ink,
     instead of the neutral cream/black pairing */
  --bg:            #e9f5f7;
  --bg-raise:      #ffffff;
  --muted:         #dceef1;
  --media-bg:      var(--muted);
  --fg:            #0b2027;
  --fg-muted:      rgba(11,32,39,.78);
  --fg-dim:        rgba(11,32,39,.60);
  --fg-faint:      rgba(11,32,39,.42);
  --border:        rgba(11,32,39,.20);
  --border-soft:   rgba(11,32,39,.12);
  --border-faint:  rgba(11,32,39,.08);
  --surface:       rgba(11,32,39,.03);
  --surface-2:     rgba(11,32,39,.055);
  --surface-3:     rgba(11,32,39,.10);

  --primary:       color-mix(in srgb, var(--palette-teal), black 18%);
  --primary-ink:   color-mix(in srgb, var(--palette-teal), black 18%);
  --primary-soft:  color-mix(in srgb, var(--palette-teal) 10%, transparent);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  background: var(--bg); color: var(--fg);
  font-family: var(--ff-body);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 76px;
}
body {
  margin: 0; min-width: 320px;
  background: var(--bg); color: var(--fg);
  font-size: 19px; line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1,h2,h3,h4,h5,h6 { margin: 0; font-weight: 600; font-family: var(--ff-display); }
sup { font-size: .68em; line-height: 0; }
/* no rule here previously, so inline code fell back to the browser's default
   UA monospace — jarring next to the body's serif/sans prose. Keep the body
   face, just dial size/weight/background down so it reads as a quiet inline
   tag rather than a code snippet. */
code {
  font-family: var(--ff-body); font-size: .88em; font-weight: 500;
  background: var(--surface-2); padding: .05em .4em; border-radius: 4px;
  color: var(--fg);
}
p { margin: 0 0 1.05em; }
p:last-child { margin-bottom: 0; }
a { color: inherit; }
img, video { max-width: 100%; display: block; }
::selection { background: var(--primary-soft); }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 2px; }

/* ---------- layout primitives ---------- */
.wrap  { width: 100%; max-width: var(--col-text); margin-inline: auto; padding-inline: var(--pad); }
.wrap--mid  { max-width: var(--col-mid); }
.wrap--wide { max-width: var(--col-wide); }
.wrap--full { max-width: var(--col-full); }
.container { width: 100%; max-width: var(--col-mid); margin-inline: auto; padding-inline: var(--pad); }

section[id], .hero[id] { scroll-margin-top: 80px; }

.eyebrow {
  font-family: var(--ff-mono);
  font-size: var(--fs-meta); letter-spacing: var(--ls-meta); text-transform: uppercase;
  color: var(--fg-faint); margin-bottom: 16px;
}

/* ==========================================================================
   nav
   ========================================================================== */
.nav {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--border-faint);
}
.nav__in {
  max-width: var(--col-full); margin-inline: auto; padding: 10px var(--pad);
  display: flex; align-items: center; gap: 14px;
}
.nav__brand {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--primary-ink);
  font-size: 17px; font-weight: 600; text-decoration: none;
  letter-spacing: -.01em; white-space: nowrap;
}
.nav__brand-icon { width: 13px; height: auto; flex: none; }
.nav__brand-icon path { fill: currentColor; }
.nav__title {
  font-size: 14.5px; color: var(--fg-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding-left: 14px; border-left: 1px solid var(--border-soft);
  display: none;
}
.nav__actions {
  display: flex; align-items: center; gap: 2px; margin-left: auto;
  min-width: 0; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
}
.nav__actions::-webkit-scrollbar { display: none; }
.navbtn {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  padding: 6px 10px; border-radius: var(--radius); text-decoration: none;
  font-size: 14.5px; color: var(--fg-dim);
  transition: color .18s var(--ease), background .18s var(--ease);
}
.navbtn:hover { color: var(--fg); background: var(--surface-2); }
.navbtn svg { width: 14px; height: 14px; flex: none; }
/* the "Code" nav item is a <button> (it opens a note rather than navigating),
   so strip the UA button chrome to keep it identical to its <a> siblings */
/* no font-size here on purpose: .navbtn's own 14.5px already beats the UA
   button default, and re-declaring it would fork the two from each other */
button.navbtn {
  border: 0; background: none; cursor: pointer;
  font-family: inherit; font-weight: inherit; line-height: inherit;
}
@media (min-width: 1024px) {
  .nav__title { display: block; flex: 1 1 auto; min-width: 0; }
}

.themebtn {
  margin-left: 6px; flex: none; width: 30px; height: 30px;
  display: grid; place-items: center; cursor: pointer; padding: 0;
  border: 1px solid var(--border-soft); border-radius: var(--radius);
  background: var(--surface); color: var(--fg-muted);
  font-size: 15px; line-height: 1;
  transition: background .18s var(--ease), color .18s var(--ease);
}
.themebtn:hover { background: var(--surface-2); color: var(--fg); }

/* ==========================================================================
   outline rail
   ========================================================================== */
.rail { display: none; }
@media (min-width: 1024px) {
  :root { --rail-shift: calc(var(--rail-w) + var(--rail-gap)); }
  main > * { padding-left: var(--rail-shift); }
  .site-footer { padding-left: var(--rail-shift); }

  .rail {
    display: block; position: fixed; z-index: 50;
    top: 108px; width: var(--rail-w);
    left: max(20px, calc((100vw - var(--rail-shift) - var(--col-wide)) / 2));
    padding-left: 15px; border-left: 1px solid var(--border);
  }
}
.rail__links { display: grid; gap: 0; }
.rail__links a {
  display: block; position: relative; text-decoration: none;
  padding: 9px 0; font-size: 14.5px; line-height: 1.28;
  color: var(--fg-dim); transition: color .16s var(--ease);
}
.rail__links a::before {
  content: ""; position: absolute; left: -15px; top: 50%;
  width: 2px; height: 0; transform: translateY(-50%);
  background: var(--fg-dim); transition: height .16s var(--ease);
}
.rail__links a:hover, .rail__links a:focus-visible { color: var(--fg); }
.rail__links a:hover::before, .rail__links a:focus-visible::before { height: 18px; }
.rail__links a[aria-current="true"] { color: var(--fg); }
.rail__links a[aria-current="true"]::before { height: 20px; background: var(--primary); }
.rail__links a[data-level="2"] {
  padding: 5px 0 5px 12px; font-size: 13px; color: var(--fg-faint);
}
/* the part you are inside stays lit while you read through its subsections */
.rail__links a[data-in="true"] { color: var(--fg-muted); }

/* ==========================================================================
   hero
   ========================================================================== */
/* padding-block, not the `padding` shorthand: a shorthand here would reset the
   padding-left that `main > *` uses to clear the outline rail, leaving the hero
   centered on the viewport while every other block centers on the rail-offset column. */
.hero { padding-block: clamp(56px, 9vw, 96px) clamp(40px, 6vw, 64px); text-align: center; }
.hero .links { justify-content: center; }
.hero__title {
  font-size: clamp(28px, 3.4vw, 48px);
  font-weight: 700;
  line-height: 1.16; letter-spacing: -.008em;
  text-wrap: balance; margin-bottom: .34em;
}
.hero__title .mark { color: var(--primary-ink); font-style: normal; }
.hero__title + .authors { margin-top: clamp(20px, 2.6vw, 30px); }
.hero__tagline {
  font-size: clamp(18px, 2.3vw, 23px);
  line-height: 1.45; color: var(--fg-muted);
  max-width: 52ch; margin-inline: auto; text-wrap: balance;
}

/* abstract — the old About section folded into the hero. The byline above stays
   centered; the prose drops to a left-aligned reading measure, because centered
   ragged text is unreadable past a couple of lines. A hairline keeps the two
   halves legible as separate units without adding a second heading. */
.hero__abstract {
  text-align: left;
  margin-top: clamp(34px, 4.4vw, 52px);
  padding-top: clamp(28px, 3.6vw, 40px);
  border-top: 1px solid var(--border-faint);
}
.hero__abstract-label {
  text-align: center;
  margin-bottom: clamp(18px, 2.4vw, 26px);
}
.hero__abstract .disclosure { margin-top: clamp(18px, 2.4vw, 26px); }

/* control panel — groups the ER-buffer picker and the training-stage slider
   into one surface, so it reads as a single control driving the figures
   below rather than two disconnected widgets */
.stagepanel {
  border: 1px solid var(--border-soft); border-radius: var(--radius);
  background: var(--bg-raise); padding: clamp(16px, 2.4vw, 22px);
  margin-top: 24px; display: grid; gap: 16px;
}
.stagepanel__row {
  display: grid; grid-template-columns: 128px 1fr auto; gap: 8px 18px; align-items: center;
}
.stagepanel__row:first-child { grid-template-columns: 128px 1fr; }
.stagepanel__row + .stagepanel__row { padding-top: 16px; border-top: 1px solid var(--border-faint); }
.stagepanel__key {
  font-family: var(--ff-mono); font-size: var(--fs-meta); letter-spacing: var(--ls-meta);
  text-transform: uppercase; color: var(--fg-faint); white-space: nowrap;
}
@media (max-width: 640px) {
  .stagepanel__row, .stagepanel__row:first-child { grid-template-columns: 1fr; }
}

/* setting switcher — picks which asset folder the stage player reads from */
.settings-toggle { display: flex; flex-wrap: wrap; gap: 8px; }
.settings-toggle__btn {
  font-family: var(--ff-body); font-size: 13.5px;
  padding: 7px 14px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface); color: var(--fg-dim);
  cursor: pointer; transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.settings-toggle__btn:hover { color: var(--fg); background: var(--surface-2); }
.settings-toggle__btn[aria-pressed="true"] {
  color: var(--bg); background: var(--primary); border-color: var(--primary);
}

/* same pill-toggle look as .settings-toggle, kept as its own class: main.js's
   initStagePlayer() queries .settings-toggle__btn globally (not scoped to its
   own panel), so reusing that class for an unrelated image switcher would
   pull it into the ER-buffer-size handler */
.viewer-toggle { display: flex; flex-wrap: wrap; gap: 8px; }
/* .viewer-toggle's own display:flex outranks the UA stylesheet's [hidden]
   rule (author styles beat UA styles regardless of specificity), so the
   toggle-group switcher needs this to actually hide the inactive group */
.viewer-toggle[hidden] { display: none; }
.viewer-toggle__btn {
  font-family: var(--ff-body); font-size: 13.5px;
  padding: 7px 14px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface); color: var(--fg-dim);
  cursor: pointer; transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.viewer-toggle__btn:hover { color: var(--fg); background: var(--surface-2); }
.viewer-toggle__btn[aria-pressed="true"] {
  color: var(--bg); background: var(--primary); border-color: var(--primary);
}

/* link buttons */
.links { display: flex; flex-wrap: wrap; gap: 9px; margin-top: clamp(26px, 4vw, 40px); }
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 16px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface);
  color: var(--fg); text-decoration: none;
  font-size: 15px; white-space: nowrap;
  transition: background .18s var(--ease), border-color .18s var(--ease), transform .18s var(--ease);
}
.btn:hover { background: var(--surface-3); border-color: var(--fg-dim); transform: translateY(-1px); }
.btn svg { width: 14px; height: 14px; flex: none; }

/* authorship block */
.authors { margin-bottom: 10px; font-size: 17px; line-height: 1.8; }
.authors .sep { color: var(--fg-faint); }
.authors a { color: inherit; text-decoration: none; transition: color .18s var(--ease); }
.authors a:hover { color: var(--primary-ink); }
.affils {
  font-size: 14.5px; color: var(--fg-muted); line-height: 1.7;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 2px 18px; margin-bottom: 6px;
}
.affils span { white-space: nowrap; }
.affils sup, .authors sup { color: var(--primary-ink); font-weight: 600; padding-right: 1px; }
.eqc { font-size: 13.5px; color: var(--fg-faint); margin-bottom: 0; }

/* ==========================================================================
   sections and prose
   ========================================================================== */
.section { padding-block: var(--gap-sec); }
.sec__title {
  font-size: clamp(26px, 2.9vw, 34px);
  line-height: 1.18; letter-spacing: -.012em;
  margin-bottom: .5em; text-wrap: balance;
}
.sec__sub {
  font-size: clamp(17px, 1.8vw, 20px);
  color: var(--fg-muted); line-height: 1.58; max-width: var(--measure);
  margin-bottom: 1.5em;
}
.sec__sub--list { list-style: decimal; padding-left: 1.4em; }
.sec__sub--list li { margin: .5em 0; }
.sec__sub--list li b { color: var(--fg); font-weight: 600; }
.hl-new { color: var(--palette-orange); font-weight: 600; }
.hl-old { color: var(--palette-teal); font-weight: 600; }
.sec__sub--full { max-width: none; }

/* subsections within a section — anchor targets for the rail's data-level="2" links */
.sub { margin-top: clamp(28px, 4vw, 44px); scroll-margin-top: 96px; }
.sub__title {
  font-size: clamp(19px, 1.9vw, 23px);
  line-height: 1.28; margin: 0 0 .45em; letter-spacing: -.008em;
}
/* a .sub can stack several of these as mid-block dividers; the first one
   gets its top space from .sub's own margin, but later ones sit flush
   against whatever content precedes them without this */
.sub__title:not(:first-child) { margin-top: clamp(32px, 5vw, 48px); }
/* no max-width here: .sub blocks live inside wrap--wide sections that pair
   this lede with a full-width display (stagepanel, card grid, ...) below it,
   so the paragraph should fill the same width as that container rather than
   wrapping at the narrower reading measure and ending short of it */
.sub__lede { font-size: 18px; line-height: 1.62; color: var(--fg-muted); margin: 0; }
.sub__lede--gap { margin-top: 22px; }

/* callout for a section's central claim. Borrows the site's established
   highlight language (soft primary tint over --bg-raise, primary-derived
   border) from .vlacard--highlight, but thinned toward the background and
   given a left accent spine so it reads as an emphasized statement rather
   than another data card competing with the figures around it. */
.claimbox {
  margin-top: 22px;
  padding: clamp(15px, 2vw, 20px) clamp(18px, 2.2vw, 24px);
  border: 1px solid color-mix(in srgb, var(--primary), var(--border-soft) 70%);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--primary-soft), var(--bg-raise) 55%);
}
/* .sub__lede zeroes its own margins, but keep a stray trailing <p> from
   pushing the box open if a second paragraph is ever added */
.claimbox > :last-child { margin-bottom: 0; }

/* ---------- stage player: scrub through a numbered image sequence ---------- */
.stagesplit {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(20px, 3vw, 44px); align-items: start; margin-top: 22px;
}
@media (max-width: 760px) { .stagesplit { grid-template-columns: 1fr; } }
.stagesplit--gap { margin-top: clamp(32px, 5vw, 48px); }
.stagesplit__prose { padding-top: clamp(2px, .6vw, 10px); }
/* .stagesplit's 22px top margin assumes it follows body content. Directly
   under a .sub__title it instead wins the margin collapse against the
   heading's own .45em bottom margin, and the prose column's alignment
   padding stacks on top of that — so the heading-to-text gap came out ~3x
   the one a plain .sub__lede gets under the same heading. Drop both here so
   the first line starts where a lede would. */
.sub__title + .stagesplit { margin-top: 0; }
.sub__title + .stagesplit .stagesplit__prose { padding-top: 0; }
/* .prose's own 19px is sized for the standalone reading column in About;
   inside a .sub these paragraphs sit right next to .sub__lede blocks, where
   that extra 1px (and the ~1.6px of line-height it drags along) reads as an
   inconsistency. Match .sub__lede here without touching the About block.
   Both classes land on the same element, so this has to be the compound
   selector — a bare .stagesplit__prose ties with .prose on specificity and
   loses to it on source order (.prose is defined further down). */
.stagesplit__prose.prose { font-size: 18px; }
/* small heading for a stagesplit column, used when a pair of columns needs
   its own title to visually balance against its sibling */
.splitcol__title {
  font-size: 17px; font-weight: 600; color: var(--fg);
  letter-spacing: -.006em; margin: 0 0 14px;
}

.stageplayer { max-width: var(--col-wide); }
.stageplayer--full { width: 100%; max-width: none; margin-top: clamp(20px, 3vw, 32px); }
.stageplayer__frame {
  background: var(--media-bg); border: 1px solid var(--border-faint); border-radius: var(--radius);
  padding: clamp(10px, 2vw, 20px);
}
.stageplayer > * + * { margin-top: 14px; }
.stageplayer__frame img { width: 100%; height: auto; display: block; margin-inline: auto; }
.stageplayer__credit {
  margin: 8px 0 0; font-size: var(--fs-fine); color: var(--fg-faint); text-align: right;
}
.stageplayer__credit--center { text-align: center; }
.stageplayer__credit a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--border); }
.stageplayer__credit a:hover { color: var(--primary-ink); border-bottom-color: var(--primary); }
/* the frame's background is always light (--media-bg), so its caption and
   any inline code need fixed dark text instead of the theme's usual tone */
.stageplayer__frame .stageplayer__credit { color: var(--media-fg); }
.stageplayer__frame .stageplayer__credit a { border-bottom-color: rgba(12,16,16,.3); }
.stageplayer__frame code { color: var(--media-fg); background: rgba(12,16,16,.08); }

/* ---------- overlap panel: one bordered card (same shell as .stagepanel,
   the ER-buffer/stage-slider control up in Sequential Task Learning) holds
   both reference images and the resample demo, so there's a single outer
   box instead of a separate card around each image ---------- */
.overlappanel__media {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2.4vw, 24px);
}
@media (max-width: 640px) { .overlappanel__media { grid-template-columns: 1fr; } }
.overlappanel__interaction {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding-top: 16px; border-top: 1px solid var(--border-faint);
}
@media (max-width: 560px) { .overlappanel__interaction { flex-direction: column; align-items: stretch; } }
.overlappanel__interaction .overlapdemo__info { text-align: left; }
.overlappanel__interaction .overlapdemo__btn { margin: 0; flex: none; align-self: flex-start; }

.overlapdemo__imgwrap { position: relative; border-radius: var(--radius); overflow: hidden; }
/* matches .overlapdemo__label below the images (same size, weight and normal
   casing) so the panel's image titles and its readout title read as one set,
   rather than the tags being uppercase small-caps and the label sentence case */
.overlapdemo__tag {
  margin: 0 0 8px; font-size: 17px; font-weight: 600;
  color: var(--fg); text-align: center;
  background: var(--bg-raise);
}
.overlapdemo__img { width: 100%; height: auto; display: block; background: var(--media-bg); border-radius: var(--radius); }

/* plain photo on a fixed pure-white backdrop (not --media-bg — this photo
   reads better against true white than the theme's off-white/aqua frame
   tone) in both themes, rather than the near-black night-theme page bg */
.realrobot__frame {
  margin-top: 20px;
  background: #ffffff; border: 1px solid var(--border-faint); border-radius: var(--radius);
  padding: clamp(10px, 2vw, 20px);
}
.realrobot__img { width: 100%; height: auto; display: block; border-radius: var(--radius); }
.overlapdemo__info { text-align: center; }
.overlapdemo__label {
  font-size: 17px; font-weight: 600; color: var(--fg); margin-bottom: .35em;
  transition: color .18s var(--ease);
}
/* Inside/outside is the categorical value that flips when you resample, so it
   carries the accent. Orange is the site's "the subset we're after" accent
   (same as .hl-new / AnchorER), and the discarded half drops to muted ink —
   deliberately not the teal/khaki/red trio, which now reads as success-rate
   tiers further down the page. */
.overlapdemo__label--in { color: var(--palette-orange); }
.overlapdemo__label--out { color: var(--fg-dim); }
.overlapdemo__text { font-size: 15px; line-height: 1.55; color: var(--fg-muted); margin-bottom: 12px; }
.overlapdemo__count {
  font-family: var(--ff-mono); font-size: var(--fs-fine); color: var(--fg-faint); margin-bottom: 0;
}
.overlapdemo__btn {
  display: block; margin: 16px auto 0;
  font-family: var(--ff-mono); font-size: 12px; letter-spacing: var(--ls-meta); text-transform: uppercase;
  padding: 7px 14px; border-radius: var(--radius-pill);
  border: 1px solid var(--primary); background: var(--primary); color: var(--bg);
  cursor: pointer; transition: background .18s var(--ease), border-color .18s var(--ease), transform .18s var(--ease);
}
.overlapdemo__btn:hover { background: var(--primary-ink); border-color: var(--primary-ink); transform: translateY(-1px); }

/* sits directly on the video's own (assumed white) bottom margin, so plain
   dark text reads fine without a translucent scrim behind it */
.overlapdemo__legend {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; justify-content: center; gap: 16px;
  padding: 7px 12px;
}
.overlapdemo__legend-item {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--ff-mono); font-size: var(--fs-meta); letter-spacing: var(--ls-meta);
  text-transform: uppercase; color: #171717;
}
.overlapdemo__swatch { width: 9px; height: 9px; border-radius: 2px; }
.overlapdemo__swatch--pred { background: var(--palette-red); }
.overlapdemo__swatch--gt { background: #000; }

/* ---------- task-ordering filmstrip: horizontally scrollable, drag or scroll ---------- */
.orderings { margin-top: 20px; }
.orderings__track {
  display: flex; gap: clamp(14px, 2vw, 20px);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: 12px;
  scrollbar-width: thin; scrollbar-color: var(--border) transparent;
}
.orderings__track:focus-visible { outline-offset: 4px; }
.orderings__track::-webkit-scrollbar { height: 8px; }
.orderings__track::-webkit-scrollbar-track { background: transparent; }
.orderings__track::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.orderings__card {
  flex: 0 0 clamp(220px, 32vw, 320px); scroll-snap-align: start; margin: 0;
}
.orderings__frame {
  background: var(--media-bg); border: 1px solid var(--border-faint); border-radius: var(--radius);
  padding: clamp(10px, 1.6vw, 16px);
}
.orderings__frame img { width: 100%; height: auto; display: block; }
.orderings__caption {
  margin-top: 8px; font-family: var(--ff-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-meta); text-transform: uppercase; color: var(--fg-dim); text-align: center;
}

/* ---------- sampled-frame carousel: auto-scrolls slowly, pauses on
   hover/focus; each card's caption/explanation surfaces in the
   .framestrip__detail box below rather than on the image itself, so
   hover/focus here just gives the frame a subtle highlight ---------- */
.framestrip { margin-top: 20px; }
.framestrip__track {
  display: flex; gap: clamp(10px, 1.4vw, 16px);
  overflow-x: auto; overscroll-behavior-x: contain;
  padding-top: 8px; padding-bottom: 12px;
  scrollbar-width: thin; scrollbar-color: var(--border) transparent;
}
.framestrip__track:focus-visible { outline-offset: 4px; }
.framestrip__track::-webkit-scrollbar { height: 8px; }
.framestrip__track::-webkit-scrollbar-track { background: transparent; }
.framestrip__track::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.framestrip__card {
  position: relative; flex: 0 0 clamp(130px, 16vw, 180px); margin: 0; cursor: default;
}
.framestrip__frame {
  background: var(--media-bg); border: 1px solid var(--border-faint); border-radius: var(--radius);
  overflow: hidden;
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease), transform .18s var(--ease);
}
.framestrip__frame img { width: 100%; height: auto; display: block; }
.framestrip__card:hover .framestrip__frame,
.framestrip__card:focus-visible .framestrip__frame {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 20%, transparent);
  transform: translateY(-2px);
}
.framestrip__tooltip {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.framestrip__detail {
  margin-top: 14px; padding: clamp(14px, 2vw, 18px) clamp(16px, 2vw, 20px);
  border: 1px solid var(--border-soft); border-radius: var(--radius); background: var(--bg-raise);
}
.framestrip__detail-label {
  font-family: var(--ff-body); font-size: var(--fs-meta); letter-spacing: var(--ls-meta);
  text-transform: uppercase; color: var(--fg-dim); margin: 0 0 8px;
}
.framestrip__detail-text { font-size: 15px; line-height: 1.6; color: var(--fg-muted); margin: 0; }

/* ---------- inline dropdown disclosure, reusable per section ("Show
   Experiment Details", FAQ entries, ...) — native <details>/<summary>,
   no JS required */
.disclosure { margin: 8px 0; }
/* .disclosure's 8px is tuned for stacking rows against each other; where a
   lede introduces the stack it needs a clearer break from the prose above */
.sub__lede + .disclosure { margin-top: 18px; }
.disclosure__summary {
  display: inline-flex; align-items: center; gap: 7px; width: fit-content;
  font-family: var(--ff-mono); font-size: var(--fs-meta); letter-spacing: var(--ls-meta);
  text-transform: uppercase; color: var(--fg-dim);
  border-bottom: 1px solid var(--border); padding-bottom: 2px; cursor: pointer;
  list-style: none; transition: color .18s var(--ease), border-color .18s var(--ease);
}
.disclosure__summary::-webkit-details-marker { display: none; }
.disclosure__summary::after {
  content: '+'; font-family: var(--ff-body); font-size: 14px; line-height: 1; flex: none;
  transition: transform .18s var(--ease);
}
.disclosure[open] > .disclosure__summary::after { transform: rotate(45deg); }
.disclosure__summary:hover { color: var(--fg); border-bottom-color: var(--primary); }
.disclosure__body {
  margin-top: 10px; padding: clamp(14px, 2vw, 18px) clamp(16px, 2vw, 20px);
  border: 1px solid var(--border-soft); border-radius: var(--radius); background: var(--bg-raise);
}
.disclosure__body p { font-size: 15px; line-height: 1.6; color: var(--fg-muted); margin: 0; }
.disclosure__body p + p { margin-top: .8em; }
/* the global `a { color: inherit }` would leave links in here indistinguishable
   from the surrounding muted text — give them the same accent + underline
   treatment that .prose a uses for links in body copy */
.disclosure__body a { color: var(--primary-ink); text-decoration: none; border-bottom: 1px solid var(--border); }
.disclosure__body a:hover { border-bottom-color: var(--primary); }
/* full-width figure inside a disclosure. No light .stageplayer__frame wrapper
   here: these contact sheets carry their own dark backdrop, so a light frame
   would ring them with a bright border instead of framing them. */
.disclosure__figure {
  display: block; width: 100%; height: auto;
  margin-top: 14px; border-radius: var(--radius);
}
.disclosure__body p:first-child + .disclosure__figure { margin-top: 12px; }

/* responsive frame for a hosted video embed (YouTube/Vimeo). aspect-ratio
   holds the 16:9 shape at any column width, so the iframe can just fill it
   instead of needing the old padding-top percentage hack. The iframe's
   loading="lazy" pairs with this: a closed <details> is display:none, so
   nothing is fetched from the video host until someone opens the dropdown. */
.videoembed {
  width: 100%; aspect-ratio: 16 / 9;
  border-radius: var(--radius); overflow: hidden; background: var(--muted);
}
.videoembed iframe { width: 100%; height: 100%; display: block; border: 0; }

/* ---------- side-by-side synced video comparison, sized as a figure, not a full column ---------- */
.videocompare { max-width: 640px; margin: 20px auto 0; }
/* multi-clip rows need more room per video, but the scrub bar should stay
   the same width as the other one on this page rather than stretching */
.videocompare--wide { max-width: 900px; }
.videocompare--wide .scrubbar { max-width: 640px; margin-inline: auto; }
.videocompare__media { display: flex; gap: 14px; align-items: start; }
/* Columns grow in proportion to --clip-ar (the clip's own width/height), set
   per item in the markup. Since rendered height is width / aspect-ratio,
   making width track the ratio leaves every clip in the row the same height
   — equal-width columns would instead render a 2:1 clip half as tall as a
   1:1 one. Defaults to 1 so rows of same-shaped clips need no annotation. */
.videocompare__item { flex: var(--clip-ar, 1) 1 0; min-width: 0; }
.videocompare__video {
  width: 100%; height: auto; display: block;
  background: var(--muted); border: 1px solid var(--border-faint); border-radius: var(--radius);
}
.videocompare__caption {
  margin-top: 10px; font-family: var(--ff-body); font-size: 15px; font-weight: 600;
  letter-spacing: var(--ls-meta); text-transform: uppercase; color: var(--fg); text-align: center;
}
/* These clips sit directly on the page rather than in a .stageplayer__frame,
   so their captions miss the frame's --media-fg override and fall back to
   .stageplayer__credit's much lighter --fg-faint. --fg-dim is the closest
   theme token to that override's weight and, unlike the fixed --media-fg,
   still inverts correctly against the dark theme's page background. */
.videocompare .stageplayer__credit { color: var(--fg-dim); }
@media (max-width: 480px) { .videocompare__media { flex-direction: column; } }

/* ---------- three-up video grid: a looping demo clip per card, with its
   own title + description underneath (no scrubbar — just autoplay/loop) ---------- */
.jargrid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2.4vw, 28px); margin-top: 22px;
}
@media (max-width: 760px) { .jargrid { grid-template-columns: 1fr; max-width: 420px; margin-inline: auto; } }
.jarcard__video {
  width: 100%; height: auto; display: block;
  background: var(--muted); border: 1px solid var(--border-faint); border-radius: var(--radius);
}
.jarcard__title { margin: 14px 0 6px; font-size: 17px; font-weight: 600; color: var(--fg); text-align: center; }
.jarcard__text { margin: 0; font-size: 15px; line-height: 1.55; color: var(--fg-muted); text-align: center; }

/* ---------- cross-task video matrix: two side-by-side triangular grids
   (one per method), row = eval task, column = train task, present only
   where train >= eval (a task can only be checked once it or a later task
   has been trained). Hover/focus enlarges a clip and drives the shared
   info box below, mirroring .framestrip's carousel + detail-box pattern. ---------- */
.taskgrids {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 4vw, 48px);
  margin-top: 22px;
}
@media (max-width: 640px) { .taskgrids { grid-template-columns: 1fr; gap: 40px; } }
.taskgrids__title { font-size: 17px; font-weight: 700; margin: 0 0 16px; text-align: center; }
.taskgrid {
  display: grid; grid-template-columns: auto repeat(3, 1fr); grid-template-rows: repeat(3, 1fr) auto;
  gap: 10px; align-items: center; justify-items: center;
}
.taskgrid__rowlabel {
  font-size: 12px; color: var(--fg-dim); white-space: nowrap;
  writing-mode: vertical-rl; transform: rotate(180deg);
}
.taskgrid__collabel { font-size: 12px; color: var(--fg-dim); margin-top: 4px; white-space: nowrap; }
/* wraps each clip so a pass/fail badge can be pinned to its corner; carries
   the grid-column/grid-row placement that used to live on the video itself.
   The hover-zoom transform now lives here (not on the video) so the badge
   scales and moves together with its clip instead of staying pinned to the
   clip's original, pre-zoom position. */
.taskgrid__cell { position: relative; width: 100%; transition: transform .22s var(--ease); }
.taskgrid__cell:hover, .taskgrid__cell:focus-within { transform: scale(1.9); z-index: 5; }
.taskgrid__video {
  width: 100%; height: auto; display: block; border-radius: var(--radius);
  border: 2px solid var(--border-faint); background: var(--muted); cursor: pointer;
  transition: box-shadow .22s var(--ease), border-color .22s var(--ease);
}
.taskgrid__cell:hover .taskgrid__video, .taskgrid__cell:focus-within .taskgrid__video {
  box-shadow: 0 14px 34px rgba(0,0,0,.32); outline: none;
}
.taskgrid--ours .taskgrid__video { border-color: color-mix(in srgb, var(--palette-orange) 50%, var(--border-faint)); }
.taskgrid--ours .taskgrid__video:hover, .taskgrid--ours .taskgrid__video:focus-visible { border-color: var(--palette-orange); }
.taskgrid--base .taskgrid__video { border-color: color-mix(in srgb, #338467 50%, var(--border-faint)); }
.taskgrid--base .taskgrid__video:hover, .taskgrid--base .taskgrid__video:focus-visible { border-color: #338467; }
/* Each clip's success rate, pinned to its top-left corner: a muted chip so it
   reads as a data label rather than decoration, with tabular figures to stop
   the digits jittering between clips. Scales with its clip on hover since it
   lives inside .taskgrid__cell, which owns the zoom transform. Built by
   initTaskGridRateChips(). */
.taskgrid__ratechip {
  position: absolute; top: 5px; left: 5px; z-index: 1;
  padding: 1.5px 5px; border-radius: var(--radius);
  font-family: var(--ff-body); font-size: 10.5px; font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.45; white-space: nowrap;
  background: color-mix(in srgb, var(--bg-raise) 88%, transparent);
  border: 1px solid var(--border-soft);
  pointer-events: none;
}
.taskgrid__ratechip--pass { color: var(--palette-teal); }
.taskgrid__ratechip--fail { color: var(--palette-red); }
.taskgrid__ratechip--partial { color: var(--palette-khaki); }
/* success-rate readout in the shared detail box below the grid — same
   65%/30% tiers and colors as the clip's own corner badge, always bold so
   the number reads as a highlighted stat rather than running prose */
.taskgrid__rate { font-weight: 700; }
.taskgrid__rate--pass { color: var(--palette-teal); }
.taskgrid__rate--fail { color: var(--palette-red); }
.taskgrid__rate--partial { color: var(--palette-khaki); }

/* shared scrub bar: two coloured segments (state similarity), a dimming
   overlay marks what's already played, a handle marks the exact position.
   Native-range semantics (role="slider") but custom-built so the two
   segment colors can live side by side, which input[type=range] can't do. */
.scrubbar {
  position: relative; display: flex; align-items: center;
  margin-top: 16px; height: 22px; cursor: pointer; touch-action: none;
  outline-offset: 4px;
}
.scrubbar__track {
  position: relative; width: 100%; height: 8px;
  border-radius: var(--radius-pill); overflow: hidden;
}
.scrubbar__segment { position: absolute; top: 0; bottom: 0; }
.scrubbar__segment--a { left: 0; width: var(--split, 50%); background: color-mix(in srgb, var(--palette-teal) 55%, var(--muted)); }
.scrubbar__segment--b { left: var(--split, 50%); right: 0; background: color-mix(in srgb, var(--palette-orange) 55%, var(--muted)); }
/* plain variant: no similar/different segments to call out, just one neutral track */
.scrubbar--plain .scrubbar__segment--a,
.scrubbar--plain .scrubbar__segment--b { background: var(--border-soft); }
.scrubbar__played {
  position: absolute; top: 0; bottom: 0; left: 0; width: 0;
  background: rgba(0,0,0,.18); pointer-events: none;
}
[data-theme="day"] .scrubbar__played { background: rgba(255,255,255,.32); }
.scrubbar__handle {
  position: absolute; top: 50%; left: 0; width: 14px; height: 14px; margin-left: -7px;
  transform: translateY(-50%); border-radius: 50%;
  background: var(--bg-raise); border: 2px solid var(--fg);
  box-shadow: 0 1px 4px rgba(0,0,0,.3); pointer-events: none;
}
.scrubbar__legend { display: flex; gap: 18px; margin-top: 10px; }
.scrubbar__legend-item {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--ff-mono); font-size: var(--fs-meta); letter-spacing: var(--ls-meta);
  text-transform: uppercase; color: var(--fg-dim);
}
.scrubbar__swatch { width: 9px; height: 9px; border-radius: 2px; }
.scrubbar__swatch--a { background: color-mix(in srgb, var(--palette-teal) 55%, var(--muted)); }
.scrubbar__swatch--b { background: color-mix(in srgb, var(--palette-orange) 55%, var(--muted)); }
.stageplayer__slider {
  width: 100%; display: block; appearance: none; -webkit-appearance: none;
  height: 4px; border-radius: var(--radius-pill);
  background: var(--border-soft); outline: none; cursor: pointer;
}
.stageplayer__slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--primary); border: 2px solid var(--bg-raise);
  box-shadow: 0 0 0 1px var(--border); cursor: pointer;
  transition: transform .15s var(--ease);
}
.stageplayer__slider::-webkit-slider-thumb:hover { transform: scale(1.12); }
.stageplayer__slider::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--bg-raise);
  background: var(--primary); box-shadow: 0 0 0 1px var(--border); cursor: pointer;
}
.stageplayer__slider::-moz-range-track { height: 4px; border-radius: var(--radius-pill); background: var(--border-soft); }
.stageplayer__ticks {
  display: flex; justify-content: space-between;
  font-family: var(--ff-mono); font-size: 10.5px; color: var(--fg-faint);
  padding: 7px 1px 0; letter-spacing: var(--ls-meta);
}
.stageplayer__label {
  font-family: var(--ff-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-meta); text-transform: uppercase; color: var(--fg-dim);
}
.prose { font-size: 19px; line-height: 1.62; color: var(--fg-muted); }
.prose strong { color: var(--fg); font-weight: 600; }
.prose a { color: var(--primary-ink); text-decoration: none; border-bottom: 1px solid var(--border); }
.prose a:hover { border-bottom-color: var(--primary); }

/* live readout tied to the settings-toggle above the stage player */
.nbt-readout {
  margin-top: 4px; padding-top: 14px; border-top: 1px solid var(--border-faint);
  font-size: 20px; color: var(--fg);
}
.nbt-readout__value { font-family: var(--ff-mono); font-weight: 700; color: var(--primary-ink); }

/* ---------- results cards: same bordered-box shell as .stagepanel, one
   card per experiment condition, a labeled stat row standing in for a table ---------- */
.vlacards { display: flex; flex-direction: column; gap: clamp(18px, 2.6vw, 24px); }
.vlacard {
  border: 2px solid var(--border-soft); border-radius: var(--radius);
  background: var(--bg-raise); padding: clamp(18px, 2.4vw, 24px);
}
/* headline takeaway, sits ahead of the per-condition cards below it — same
   shell, just a soft teal tint and an accent-colored eyebrow so it reads as
   a summary rather than another data condition */
.vlacard--highlight, .vlacard--selected {
  background: color-mix(in srgb, var(--primary-soft), var(--bg-raise) 25%);
  border-color: var(--primary);
}
/* clicking a card drives the viewer on the left, so it needs to read as a
   control: pointer cursor, hover/focus feedback, and a distinct look once
   selected (shared with .vlacard--highlight's tint, above) */
.vlacard--selectable {
  cursor: pointer;
  transition: border-color .18s var(--ease), background .18s var(--ease), opacity .18s var(--ease);
}
.vlacard--selectable:hover { border-color: var(--fg-dim); }
.vlacard--selectable:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* wraps the qualitative viewer and the result cards in one bordered surface
   (stagesplit's grid still lays out the two columns) so a card click visibly
   drives the image beside it instead of reading as two disconnected widgets */
.vla-explorer {
  border: 1px solid var(--border-soft); border-radius: var(--radius);
  background: var(--bg-raise); padding: clamp(18px, 2.4vw, 28px);
}
/* groups the title and intro blurb as one grid item spanning both columns
   (an item with no explicit placement otherwise lands beside the viewer
   instead of above it) so their spacing is plain flow margin rather than
   the grid's own row-gap, which was stretching the two apart; a bottom rule
   separates the panel's header from its two interactive columns below,
   echoing .stagepanel__row's own divider convention */
.vla-explorer__header {
  grid-column: 1 / -1;
  padding-bottom: 16px; border-bottom: 1px solid var(--border-faint);
}
/* a real heading for the panel (not the borrowed .splitcol__title label
   style, which was sized for pairing two mini column headers and read as
   too slight against the box's own border/padding) — same display font and
   weight as .sub__title, just scaled down since this titles a nested panel
   rather than a page section */
.vla-explorer__title {
  font-family: var(--ff-display); font-size: clamp(17px, 1.6vw, 19px); font-weight: 600;
  letter-spacing: -.006em; color: var(--fg); margin: 0;
}
.vla-explorer__lede {
  font-size: 15px; line-height: 1.55; color: var(--fg-muted); margin: 6px 0 0;
}
/* cards need to stand out from the explorer's own bg-raise surface, and the
   unselected one should read as visibly de-emphasized next to the selected
   card's primary tint (above) — a stronger surface tone plus a touch of
   faded opacity does that without touching the selected card's own rule */
.vla-explorer .vlacard:not(.vlacard--selected) { background: var(--surface-3); opacity: .8; }
.vlacard__eyebrow {
  font-size: 12px; font-weight: 600; letter-spacing: .01em; text-transform: uppercase;
  color: var(--primary-ink); margin: 0 0 6px;
}
.vlacard__title { font-size: 16px; font-weight: 700; color: var(--fg); margin: 0 0 4px; }
.vlacard__subtitle { font-size: 14px; line-height: 1.5; color: var(--fg-muted); margin: 0; }
.vlacard__row {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 12px 24px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-faint);
}
.vlacard__metric {
  font-size: 13px; font-weight: 500; color: var(--fg-dim); white-space: nowrap;
  padding-bottom: 4px;
}
.vlacard__stats { display: flex; gap: clamp(18px, 3vw, 32px); }
.vlacard__stat { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.vlacard__stat-label {
  font-size: 12.5px; color: var(--fg-faint); white-space: nowrap;
}
.vlacard__stat-value {
  font-size: 17px; font-weight: 600; color: var(--fg-muted); font-variant-numeric: tabular-nums;
}
.vlacard__stat-value small { margin-left: 3px; font-size: 12px; font-weight: 500; opacity: .75; }
.vlacard__stat-value--best { color: var(--primary-ink); font-weight: 700; }

/* ---------- results bar chart: grouped bars in a fixed light frame (same
   convention as .stageplayer__frame / .orderings__frame — the SVG is authored
   with dark ink on a light ground, so the frame stays light in both themes)
   ---------- */
/* zero the inline margin: <figure> carries a UA default of `margin: 1em 40px`,
   which was quietly insetting both results charts 80px narrower than the body
   text around them (.orderings__card and .framestrip__card already zero it). */
.barchart { margin: 22px 0 0; }
.barchart__frame {
  background: var(--media-bg); border: 1px solid var(--border-faint); border-radius: var(--radius);
  padding: clamp(16px, 2.6vw, 28px);
}
.barchart__svg { width: 100%; height: auto; display: block; }
/* sits inside the frame's fixed-light background (see .barchart__frame
   comment), so it needs the fixed dark-ink tone rather than a theme var */
.barchart__legend {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 24px;
  margin-top: 14px;
  font-family: var(--ff-body); font-size: var(--fs-fine); color: var(--media-fg);
}
.barchart__legend-item { display: inline-flex; align-items: center; gap: 8px; }
.barchart__swatch { width: 15px; height: 15px; border-radius: 3px; flex: none; }
.barchart__swatch-group { display: inline-flex; height: 15px; border-radius: 3px; overflow: hidden; flex: none; }
.barchart__swatch-group span { width: 10px; height: 100%; }
.barchart__caption { margin-top: 10px; font-size: var(--fs-fine); color: var(--fg-faint); text-align: center; }

/* ---------- card grid ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.1rem; margin-top: 1.5rem; }
.card {
  background: var(--surface); border: 1px solid var(--border-faint);
  border-radius: var(--radius); padding: clamp(18px, 2.4vw, 24px);
  transition: transform .28s var(--ease), box-shadow .28s var(--ease), border-color .28s var(--ease);
}
.card:hover { transform: translateY(-4px); box-shadow: 0 14px 34px rgba(0,0,0,.16); border-color: var(--border); }
.card h3 { font-size: 18px; margin-bottom: .5em; letter-spacing: -.008em; }
.card p { color: var(--fg-muted); margin-bottom: 0; }

/* ---------- bibtex ---------- */
.bib { position: relative; }
.bib pre {
  margin: 0; overflow-x: auto; -webkit-overflow-scrolling: touch;
  background: var(--muted); border: 1px solid var(--border-faint);
  border-radius: var(--radius); padding: 20px;
  font-family: var(--ff-mono); font-size: 12.5px; line-height: 1.7;
  color: var(--fg-muted); tab-size: 2;
}
.bib__copy {
  position: absolute; right: 10px; top: 10px;
  font-size: 14px; padding: 5px 12px; border-radius: var(--radius); cursor: pointer;
  background: var(--surface-2); color: var(--fg-muted); border: 1px solid var(--border-soft);
  font-family: var(--ff-body);
  transition: background .18s var(--ease), color .18s var(--ease);
}
.bib__copy:hover { background: var(--surface-3); color: var(--fg); }

/* ==========================================================================
   footer
   ========================================================================== */
.site-footer {
  border-top: 1px solid var(--border-faint); margin-top: var(--gap-sec);
  padding-block: 34px 46px; font-size: 13.5px; color: var(--fg-dim); line-height: 1.6;
}
.site-footer a { color: var(--fg-muted); }

/* ==========================================================================
   reveal-on-scroll
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity .6s var(--ease), transform .6s var(--ease); }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

@media (max-width: 460px) {
  .nav__brand { font-size: 15px; }
  .nav__in { gap: 8px; }
}

/* ==========================================================================
   drive video grid (uncut-videos.html)
   2x2 of Google Drive player iframes: one row per experimental condition,
   two evaluation episodes per row. Drive serves its player in an iframe, so
   the 16:9 box comes from an aspect-ratio wrapper rather than the intrinsic
   size a <video> would give us.
   ========================================================================== */
.drivegrid { display: grid; gap: clamp(30px, 4.5vw, 52px); margin-top: 28px; }
.drivegrid__rowhead {
  padding-bottom: 12px; margin-bottom: 16px;
  border-bottom: 1px solid var(--border-soft);
}
.drivegrid__rowlabel {
  margin: 0; font-size: 17px; font-weight: 600; color: var(--fg); letter-spacing: -.008em;
}
.drivegrid__rowtext { margin: 5px 0 0; font-size: 15px; line-height: 1.55; color: var(--fg-muted); }
.drivegrid__pair {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2.4vw, 28px);
}
.drivecard__frame {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  background: var(--muted);
  border: 1px solid var(--border-faint); border-radius: var(--radius);
}
.drivecard__video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.drivecard__title { margin: 14px 0 6px; font-size: 17px; font-weight: 600; color: var(--fg); text-align: center; }
.drivecard__text { margin: 0; font-size: 15px; line-height: 1.55; color: var(--fg-muted); text-align: center; }
.drivegrid__note {
  margin: clamp(28px, 4vw, 40px) 0 0;
  font-family: var(--ff-mono); font-size: var(--fs-fine); color: var(--fg-faint);
}
.drivegrid__note a { color: var(--primary-ink); text-decoration: none; border-bottom: 1px solid var(--border); }
.drivegrid__note a:hover { border-bottom-color: var(--primary); }
@media (max-width: 760px) {
  .drivegrid__pair { grid-template-columns: 1fr; max-width: 480px; margin-inline: auto; }
}

/* ==========================================================================
   mobile refinements
   The layout above is fluid and mostly holds up on its own; these are the
   things that only break once the column is actually phone-width.
   ========================================================================== */

/* --- nav ---------------------------------------------------------------
   Brand + three labelled buttons + theme toggle don't fit in ~390px, so
   .nav__actions' own `overflow-x: auto` was quietly scrolling BibTeX out of
   sight behind a hidden scrollbar — unreachable unless you guessed it was
   there. Collapse the buttons to their icons instead; the aria-labels added
   in the markup keep the names available to assistive tech. */
@media (max-width: 620px) {
  .navbtn__label { display: none; }
  .navbtn { padding: 9px; }
  .navbtn svg { width: 17px; height: 17px; }
  .nav__actions { overflow-x: visible; gap: 5px; }
}

/* --- dense figures -----------------------------------------------------
   A three-panel method diagram or a full results sheet is authored to be
   read at ~1000px+. Fitted into a 350px column it becomes an unreadable
   smear that tells the reader nothing. Let those specific figures keep a
   legible intrinsic width and scroll sideways instead. Pinch-zoom still
   works too (the viewport meta allows it) but is far clumsier. */
.zoomfig__hint { display: none; }
@media (max-width: 720px) {
  .zoomfig {
    overflow-x: auto; overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin; scrollbar-color: var(--border) transparent;
  }
  /* svg too: the two results bar charts are inline SVG, and their own
     `width: 100%` is overridden here because min-width wins over width */
  .zoomfig > img, .zoomfig > svg { min-width: 680px; max-width: none; }
  .zoomfig::-webkit-scrollbar { height: 6px; }
  .zoomfig::-webkit-scrollbar-track { background: transparent; }
  .zoomfig::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
  /* the scrollbar is an overlay on iOS/Android — invisible until you're
     already dragging — so the gesture needs to be stated, not implied */
  .zoomfig__hint {
    display: block; margin: 8px 0 0;
    font-family: var(--ff-mono); font-size: var(--fs-fine);
    letter-spacing: var(--ls-meta); text-transform: uppercase;
    color: var(--fg-faint);
  }
}

/* --- carousels ---------------------------------------------------------
   Same invisible-scrollbar problem for the two existing side-scrollers. A
   card is always cut mid-frame at phone width, which hints at more content;
   a soft right edge makes that read as deliberate rather than as clipping. */
@media (max-width: 720px) {
  .orderings__track, .framestrip__track {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
  }
}

/* --- touch targets -----------------------------------------------------
   The pill toggles and disclosure summaries are sized for a mouse cursor
   (~31px and ~20px tall). Both are primary controls on this page, so give
   them enough height to hit reliably with a thumb. */
@media (max-width: 620px) {
  .settings-toggle__btn, .viewer-toggle__btn {
    padding: 10px 16px; font-size: 14px;
  }
  .disclosure__summary { padding-top: 7px; padding-bottom: 7px; }
  .themebtn { width: 36px; height: 36px; }
  /* the scrub handle sits flush against the container edge at its extremes,
     where a thumb runs out of screen — inset the track so it stays grabbable */
  .scrubbar { margin-inline: 10px; }
}

/* --- narrowest phones (320px) ------------------------------------------
   The VLA panel's three-column stat row has `white-space: nowrap` labels
   ("AnchorER 10%") whose combined min-content width exceeds a 320px screen,
   which pushed the whole panel past the viewport. Let them wrap and shrink. */
@media (max-width: 400px) {
  /* equal columns via auto-flow rather than a hardcoded repeat(3), so a card
     with a different number of stats still divides evenly; wrapping the
     labels is what buys the room the nowrap flex row didn't have */
  .vlacard__stats {
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 10px;
  }
  .vlacard__stat { min-width: 0; }
  .vlacard__stat-label {
    white-space: normal; text-align: center; font-size: 11.5px;
    /* reserve two lines: otherwise a one-line label ("RandER") rides up and
       knocks its value out of line with the two-line labels beside it */
    /* pin the line-height too: the inherited 1.62 makes a real two-line label
       taller than the reserved box, so min-height alone wouldn't bind */
    line-height: 1.3; min-height: 2.6em;
    display: flex; align-items: center; justify-content: center;
  }
  .vla-explorer > * { min-width: 0; }
}

/* ==========================================================================
   notice dialog: a short note for a nav item that has nowhere to point yet
   ========================================================================== */
.notice {
  width: min(340px, calc(100vw - 2 * var(--pad)));
  padding: clamp(18px, 2.4vw, 24px);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius);
  background: var(--bg-raise);
  color: var(--fg);
  font-family: var(--ff-body);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .28);
}
.notice::backdrop { background: rgba(6, 12, 18, .5); }
.notice__label { margin-bottom: 10px; }
.notice__text {
  margin: 0 0 18px; font-size: 15px; line-height: 1.6; color: var(--fg-muted);
}
.notice__close {
  display: inline-flex; align-items: center; cursor: pointer;
  padding: 7px 15px; font: inherit; font-size: 13.5px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--fg);
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.notice__close:hover { background: var(--surface-2); border-color: var(--primary); }
