/* ---------- hero: plain academic title block ----------
   Loaded after chord.css, overrides only the hero. The fullscreen clip and its
   scrim are gone from the markup, so the rules that styled them never match and
   are not repeated here; what is left is a header that is as tall as its text.

   chord.css painted this block white-on-footage. On white the same colours are
   invisible, so every one of them is restated — this file is not a tweak on top
   of the dark hero, it is the light hero. */

.hero {
  min-height: 0;                 /* was 100vh — the header now sizes to its text */
  display: block;
  overflow: visible;
  background: var(--surface-page);
  border-bottom: 1px solid var(--border-subtle);
  /* the gutter moves off .hero-inner and onto the header, so the rules below
     start and end exactly where the robot's travel does */
  padding: 0 clamp(20px, 5vw, 40px);
}
/* V5 "ruled": a heavy rule opens the block, a light one closes it, and the
   credits are separated by a third. position:relative anchors the robot. */
.hero-inner {
  position: relative;
  margin: 104px auto 0;
  padding: 44px 0 40px;
  border-top: 2px solid var(--text-primary);
  border-bottom: 1px solid var(--border-strong);
}

/* the sentence is a mono kicker here, not a headline */
.hero-eyebrow {
  margin: 0 0 20px;
  font-family: var(--font-mono);
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  white-space: nowrap;
  /* Two nudges in one. .16em cancels the phantom gap letter-spacing leaves
     after the last character, which centring otherwise counts as ink. The rest
     is optical: the line's tail is the light green, which weighs less than the
     grey ahead of it, so a geometrically centred line still reads left. */
  text-indent: .8em;
}
/* the line cannot wrap to escape, so it has to be released before it reaches
   the column edge — at this size that is around 950px, not 700 */
@media (max-width: 950px) {
  .hero-eyebrow { white-space: normal; letter-spacing: .12em; text-indent: 0; }
}
/* the task domain keeps the bright green it was given, at kicker size */
.hero-eyebrow i { font-style: normal; font-weight: inherit; color: #41d989; }

.hero-mark {
  color: var(--text-primary);
  text-shadow: none;             /* nothing to lift it off any more */
  font-size: clamp(3rem, 8vw, 5.6rem);
}
/* #7fb0ff was picked to survive dark footage; on white it disappears */
.hero-mark i { color: var(--accent); }

.hero-authors {
  width: 100%;
  margin-top: 22px;
  padding-top: 22px;
  border-top: 1px solid var(--border-subtle);
  color: var(--text-primary);
  text-shadow: none;
}
.hero-authors a { border-bottom-color: var(--border-strong); }
.hero-authors a:hover { color: var(--accent); border-bottom-color: var(--accent); }

.hero-affil {
  color: var(--text-tertiary);
  text-shadow: none;
}

.hero-venue {
  border-color: var(--border-strong);
  color: var(--text-tertiary);
  backdrop-filter: none;
}

/* the reference's rounded dark pills */
.hbtn {
  border-radius: 999px;
  background: var(--text-primary);
  border-color: var(--text-primary);
  color: #fff;
  backdrop-filter: none;
}
.hbtn:hover { background: #263142; border-color: #263142; color: #fff; }
.hbtn.primary { box-shadow: none; }

/* ---------- side rail ----------
   The top bar is gone; the sections index down the left edge instead. Ported
   from the reference page, with its purple swapped for the blue this page
   already uses. Hidden below 1100px, where there is no margin to sit in. */

/* nothing reserves room for a fixed top bar any more, but the anchors still
   want a little air above them when jumped to */
:root { --nav-h: 8px; }

#toc-nav {
  position: fixed;
  left: 1.75rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
  font-family: var(--font-mono);
  opacity: 0;                    /* the spy raises this once a section is current */
  transition: opacity .25s ease;
}
/* the line the dots are threaded on */
#toc-nav::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 9px;
  bottom: 9px;
  width: 2px;
  background: var(--border-subtle);
  z-index: -1;
}
.toc-item { display: flex; align-items: center; gap: .65rem; text-decoration: none; }
.toc-dot-wrap {
  width: 18px; height: 18px; flex: 0 0 18px;
  display: flex; align-items: center; justify-content: center;
}
.toc-dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--surface-page);
  border: 2px solid var(--border-strong);
  box-sizing: border-box;
  transition: width .2s ease, height .2s ease, background .2s ease, border-color .2s ease;
}
.toc-label {
  font-size: .72rem;
  font-weight: 600;
  color: var(--text-tertiary);
  white-space: nowrap;
  transition: color .2s ease, font-weight .2s ease;
}
.toc-item:hover .toc-dot { border-color: var(--accent); }
.toc-item:hover .toc-label { color: var(--text-secondary); }
.toc-item.active .toc-dot {
  width: 17px; height: 17px;
  background: var(--accent);
  border-color: var(--accent);
}
.toc-item.active .toc-label { color: var(--accent); font-weight: 700; }

@media (max-width: 1100px) { #toc-nav { display: none; } }

/* ---------- the video toggle, now a sixth pill ----------
   It is a <button> among anchors, so it needs the bits a button does not
   inherit; everything else it takes from .hbtn like its neighbours. */
button.hbtn {
  font-family: var(--font-sans);
  line-height: 1.2;
  cursor: pointer;
}
button.hbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* The panel opens under the hero, so it no longer needs the toggle's spacing.
   Its own margin does the spacing instead, and it is symmetric: chord.css had
   `margin: 20px auto 0`, which left the clip 20px below the title rule and
   flush against the Overview band's rule underneath. */
#project-video { padding-top: 0; padding-bottom: 0; }

/* ---------- band alternation, restarted at Overview ----------
   chord.css banded the page white-first, which worked under a dark hero: the
   content opened white against the footage. The title block is white now, so
   the run starts one step earlier — Overview takes the grey, and every band
   after it flips to keep the alternation going down to the bibtex.

   Done by id here rather than by moving `subtle` around in the markup, so
   index-chord.html keeps its own banding. Borders ride with the grey bands;
   the white ones need none, since their neighbours already draw the line. */
section.band#overview,
section.band#data,
section.band#realworld,
section.band#bibtex {
  background: var(--surface-subtle);
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}
section.band#method,
section.band#training,
section.band#experiments {
  background: var(--surface-page);
  border-top: 0;
  border-bottom: 0;
}

/* ---------- one content width ----------
   Four blocks used to sit at their own widths — Training at 1340 for the
   objective chips, the bibtex at 860, the video panel at 900 — so the page's
   left and right edges moved as you scrolled. They all take --maxw now and the
   edges hold. Training pays one extra row of chips for it. Scoped by id so
   index-chord.html keeps the widths it was tuned with. */
#training > .shell-wide,
#bibtex > .shell-narrow { width: min(100%, var(--maxw)); }
/* the clip does not need the full content column; 1040 keeps it clearly the
   opening image without dominating the screen on a laptop */
#project-video .video-panel { max-width: 1040px; margin: 26px auto; }

/* ---------- experiments: original width, actually centred ----------
   The question list keeps its 900px measure — the prose reads better there than
   at the full 1180. It was already `margin: 0 auto`, but the 58px gutter the
   numbered spine hangs in is on the left only, so the questions themselves sat
   29px right of centre. Matching the gutter on the right balances the box, and
   the max-width grows by the same 58 so the text keeps its old measure. */
#experiments .qb {
  max-width: 958px;        /* 900 + the spine gutter */
  padding-right: 58px;
}

/* ---------- the SRL mark, standing on the title rule ----------
   Three letters as three characters, each with a pair of eyes, R carrying the
   accent. Every size derives from --u, so the whole mark scales from one
   number. The motion is deliberately the quietest of the ten tried: a slow
   staggered swell, near enough to a static logo that it does not compete with
   the title on a page somebody reads for ten minutes. */
.srl {
  --u: 1.15;
  position: absolute;
  left: 0;
  top: -40px;
  display: inline-flex;
  align-items: flex-end;
  gap: calc(3px * var(--u));
  line-height: 1;
}
.srl .ch {
  position: relative;
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: calc(30px * var(--u));
  letter-spacing: -.03em;
  color: var(--text-primary);
  transform-origin: bottom center;
  animation: srl-breathe 2.6s ease-in-out infinite;
}
.srl .ch:nth-child(2) { color: var(--accent); animation-delay: .14s; }
.srl .ch:nth-child(3) { animation-delay: .28s; }

/* Eyes sit just above each letter rather than punched into it. Punched holes
   worked on the S and R but not the L, whose stem is about 5px wide here —
   too narrow to hold two dots side by side. Above the glyph every letter gets
   the same face, and it survives being scaled down. */
.srl .eyes,
.srl .eyes::after {
  position: absolute;
  width: calc(3.6px * var(--u));
  height: calc(3.6px * var(--u));
  border-radius: 50%;
  background: currentColor;
}
.srl .eyes {
  left: 50%;
  top: calc(-6px * var(--u));
  margin-left: calc(-4.6px * var(--u));
}
.srl .eyes::after { content: ""; left: calc(5.6px * var(--u)); top: 0; }

@keyframes srl-breathe { 0%, 100% { transform: scale(1) } 50% { transform: scale(1.13) } }

@media (prefers-reduced-motion: reduce) {
  .srl .ch { animation: none; transform: none; }
}
@media (max-width: 700px) {
  .srl { --u: .95; top: -34px; }
}

/* ---------- a wider column ----------
   1180 left the pre-training objective chips 29px short of one row, so the VQA
   chip dropped below. The chip label is shorter now and the column is wider;
   between them the three objectives sit on a single line. Everything on the
   page reads off --maxw, so widening it here keeps the edges lined up. */
:root { --maxw: 1260px; }

/* ---------- pre-training objectives on one row ----------
   The chips sat 4px over their box and the last one dropped below. Page width
   could not fix it: .sf-objectives is a flex item that sizes to its own
   content, so it stayed 358px however wide the column got. Telling it not to
   wrap is what actually keeps the three objectives on one line — there is room
   for them, the flow row reserves 150px on the right for the gradient button
   and still leaves ~420px for a row that needs ~365. Below 720px the diagram
   scrolls instead, so wrapping comes back there. */
.sf-objectives { flex-wrap: nowrap; }
@media (max-width: 720px) { .sf-objectives { flex-wrap: wrap; } }

/* ---------- experiments: two figures, each with what it claims ----------
   The five interactive question charts became two paper figures. Each one is
   followed by the claims it supports, so the reader gets the picture first and
   the argument beside it rather than five nested widgets. */
.ev { display: grid; grid-template-columns: 1.35fr 1fr; gap: 30px; align-items: start; margin-bottom: 46px; }
.ev:last-of-type { margin-bottom: 0; }
.ev-fig { margin: 0; }
.ev-fig img {
  width: 100%;
  height: auto;
  display: block;
  border: 1px solid var(--border-subtle);
  border-radius: 10px;
  background: #fff;
}
.ev-fig figcaption {
  margin-top: 10px;
  font-size: .84rem;
  line-height: 1.55;
  color: var(--text-tertiary);
}
.ev-claims { margin: 0; padding: 0; list-style: none; display: grid; gap: 16px; }
.ev-claims li {
  position: relative;
  padding-left: 16px;
  font-size: .97rem;
  line-height: 1.62;
  color: var(--text-secondary);
}
.ev-claims li::before {
  content: "";
  position: absolute;
  left: 0; top: .62em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
.ev-claims b { color: var(--text-primary); }
@media (max-width: 900px) { .ev { grid-template-columns: 1fr; gap: 22px; } }

/* only one question is left on the board, so the numbered spine it used to
   thread through five items would read as a stray mark */
/* the 58px right padding above balanced the spine gutter; with the spine gone
   it only cut the toggle short of the figures' right edge */
#experiments .qb { padding-left: 0; padding-right: 0; max-width: none; }
#experiments .qb::before, #experiments .qb::after { display: none; }
#experiments .qb-node { display: none; }
#experiments .qb-item { border-bottom: 0; padding: 0; }
#experiments .qdrop-body > .q2-deep { margin-left: 0; margin-right: 0; }
#experiments .qb-item + .qb-item .qdrop { margin-top: 0; border-top: 0; }

/* ---------- a question you can open ----------
   The SimVQA deep dive is supporting evidence, not part of the main line, so
   it sits behind its own question. <details> rather than a scripted toggle:
   it keeps keyboard and screen-reader behaviour for free, and find-in-page
   still reaches the closed content in current browsers. */
.qdrop {
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  margin-top: 8px;
}
.qdrop + .qdrop { border-top: 0; }
.qdrop > summary {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 22px 2px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.qdrop > summary::-webkit-details-marker { display: none; }
.qdrop-q {
  flex: 1;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 1.7vw, 1.3rem);
  font-weight: 600;
  letter-spacing: -.015em;
  color: var(--text-primary);
}
/* the chevron is drawn rather than typed, so it rotates cleanly */
.qdrop-hint {
  flex: none;
  width: 11px; height: 11px;
  border-right: 2px solid var(--text-tertiary);
  border-bottom: 2px solid var(--text-tertiary);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .2s ease, border-color .2s ease;
}
.qdrop[open] > summary .qdrop-hint { transform: rotate(-135deg) translate(-3px, -3px); }
.qdrop > summary:hover .qdrop-q { color: var(--accent); }
.qdrop > summary:hover .qdrop-hint { border-color: var(--accent); }
.qdrop > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.qdrop-body { padding-bottom: 30px; }

/* Keep the three expanded experiment answers comfortable to read. */
#experiments .qdrop-body .qb-prose { font-size: 1.05rem; line-height: 1.68; }
#experiments .qdrop-body .q2-glab { font-size: .75rem; }
#experiments .qdrop-body .q2-svl { font-size: .7rem; }
#experiments .qdrop-body .qcap { font-size: .92rem; line-height: 1.58; }
#experiments .qdrop-body .q2-qcap { font-size: .95rem; }
#experiments .qdrop-body table.data { font-size: 1rem; }
#experiments .qdrop-body table.data th { font-size: .93rem; }
#experiments .qdrop-body .search-title { font-size: 1.08rem; }
#experiments .qdrop-body .search-steps b { font-size: 1.05rem; }
#experiments .qdrop-body .search-steps p { font-size: 1rem; line-height: 1.55; }
#experiments .qdrop-body .search-note { font-size: .95rem; line-height: 1.62; }

@media (prefers-reduced-motion: reduce) { .qdrop-hint { transition: none; } }

/* ========== overall scale ==========
   Everything read a step too large — 17px body, 92px band padding. Pulled in
   by roughly 7%, which lands the body on 15.8px and the headings with it,
   since chord.css sizes them in rem and vw. */
/* headings are sized in rem, which keys off html and not body, so the root is
   what actually scales them; body carries its own absolute size so running
   text does not shrink as far as the display type does */
html { font-size: 14.8px; }
body { font-size: 15.8px; line-height: 1.62; }
section.band { padding: 74px clamp(18px, 4vw, 34px); }
.hero { padding: 0 clamp(18px, 4vw, 34px); }
.hero-inner { margin-top: 88px; padding: 38px 0 34px; }
.band-head { margin-bottom: 32px; }

/* ========== mobile ==========
   Two things pushed the page 765px wide inside a 390px phone. */

/* 1. the overview sentence was held on one line by an inline style, so at
      phone width it alone was 745px. It keeps the line where there is room. */
.oc-nowrap { white-space: nowrap; }
@media (max-width: 860px) { .oc-nowrap { white-space: normal; } }

/* 2. the training diagram scrolls inside .sf-scroll, but its grid parent had
      no min-width:0, so instead of letting the child scroll the whole column
      stretched to the diagram's 540px min-width and dragged the page with it */
.stages-row { min-width: 0; }
.stages-row .stage, .stage > .stagefig, .stagefig > .sf-scroll { min-width: 0; }

@media (max-width: 720px) {
  .hero-inner { margin-top: 64px; padding: 30px 0 28px; }
  .hero-mark { font-size: clamp(2.6rem, 13vw, 3.4rem); }
  section.band { padding: 52px 18px; }
  #project-video .video-panel { margin: 18px auto; }
  .ev { gap: 18px; }
  .qdrop > summary { padding: 18px 2px; }
}

/* the distance-probe caption reads as a lead line plus three notes */
.qcap-list { margin: 7px 0 0; padding: 0; list-style: none; display: grid; gap: 5px; }
.qcap-list li { position: relative; padding-left: 13px; }
.qcap-list li::before {
  content: "";
  position: absolute;
  left: 0; top: .66em;
  width: 5px; height: 1px;
  background: var(--border-strong);
}
.qcap-list b { color: var(--text-secondary); font-weight: 650; }

/* ---------- phone: two things that came out wrong ---------- */
@media (max-width: 860px) {
  /* .oc-line is min(2.5rem, 3.4vw). The vw term exists to keep the sentence on
     one line while it is nowrap, but below 860 chord.css already lets it wrap —
     so the term only shrank it, to 13px on a 390px phone, smaller than the body
     text under it. Size it for a wrapped headline instead. */
  .oc-line {
    font-size: clamp(1.45rem, 6.4vw, 2.1rem);
    max-width: 18ch;
    letter-spacing: -.02em;
  }
  .oc-sub { font-size: 1.02rem; margin-top: 14px; }
}

@media (max-width: 720px) {
  /* the two-stage diagram is laid out for a desktop column and scrolls
     sideways on a phone. 540px of min-width meant a phone had to drag it a
     screen and a half; 440 keeps the parts legible with far less dragging,
     and the objective chips already re-wrap at this width. */
  .sf-scroll > * { min-width: 440px; }
  .sf-flowrow { padding-right: 96px; }
  .stagefig { padding-top: 14px; padding-bottom: 12px; }
  #training .stage-head h3 { font-size: 1.15rem; }
}

/* Nothing is burned over the footage: the per-card caption is hidden, so the
   clips play clean. The running title above the carousel stays — it is the one
   place that still says which task and which room you are looking at.
   Hidden rather than deleted: chord.js writes to #cf-now on every step with no
   null guard, so removing it from the DOM stops the carousel dead. */
.cf-cap { display: none !important; }

@media (max-width: 720px) {
  /* The diagram has a real minimum: squeezing the column below ~440px clips
     the action-expert block and collides the token labels. So keep the layout
     at the width it was drawn for and shrink the whole thing instead — `zoom`
     rather than `transform`, because it reflows the parent's height too, where
     a transform would leave the gap behind. overflow-x stays auto, so a
     browser without zoom still just scrolls as before. */
  .sf-scroll > * { min-width: 440px; zoom: .72; }
  .sf-flowrow { padding-right: 0; }
  .sf-grad { position: static; margin-top: 8px; }
  .sf-objectives { flex-wrap: wrap; }
  .stagefig::after { display: none; }
}

/* .cf-card is a <figure>, so it still carried the browser's default
   `margin: 1em 40px`. The 1em top margin pushed every card down by the body
   font size and .cf-vp clipped that much off the bottom — 16px on a phone,
   where the stage has no slack, 3px on a desktop where it does. */
.cf-card { margin-top: 0; margin-bottom: 0; }

/* the mark links to the lab; it is a logo, so no underline, and the letters
   already carry their own colours — only the hover state is added */
a.srl { text-decoration: none; pointer-events: auto; }
/* the hover is per-letter: whichever one the cursor is over turns blue, rather
   than the whole mark swapping its colours at once */
a.srl .ch { transition: color .18s ease; }
a.srl .ch:hover { color: var(--accent); }
a.srl:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 4px; }

/* figure captions are a single line */
.ev-fig figcaption p { margin: 0; }
