/* ==========================================================================
   LANDING BUILD — shape only. Tokens and components live in base.css, which is
   byte-identical to the instrument build's copy. Everything here is layout.

   WHY THIS IS NOT THE USUAL LONG PAGE
   The house pattern in this repo — sticky nav, centred hero with two buttons,
   then "eyebrow / headline / sub / card" sections, then a four-up grid, then a
   footer — is the reason three sibling benchmark sites look alike. It is also
   the wrong container for this data, which needs a sentence before every number:
   a leaderboard where the leader scores 0.24 and the benchmarks disagree with
   each other is not self-explanatory, and a grid of cards cannot argue.

   So the page is a data essay: one numbered argument, a reading column at a
   fixed measure, and figures that break out of that column to full width. The
   rail on the left is the argument's table of contents and the scroll position
   indicator, not a nav bar. No centred hero, no card grid, no four-up.
   ========================================================================== */

body { min-height: 100vh; }

/* How much sticky chrome sits above the content right now: the masthead alone, or the masthead
   plus the active-slice strip when that is showing. app.js keeps it current by MEASURING the
   strip rather than hardcoding its height. Anything that wants to stick below the chrome reads
   this instead of guessing, which is what stops two sticky things landing on the same line. */
:root { --chrome-h: 54px; }

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 26px; }

/* ---------- masthead ----------
   A rule with a brand on it, not a navigation bar: one line, no call to action,
   no link list. Sticky because the page is long and the theme toggle and the
   jump control are the only two things a reader needs from up here. */
.masthead {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--page) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.masthead__in {
  max-width: var(--maxw); margin: 0 auto; padding: 0 26px;
  height: 54px; display: flex; align-items: center; gap: 18px;
}
.masthead__jump { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.masthead__jump label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); }
.masthead select {
  font-family: inherit; font-size: 12.5px; color: var(--ink-2);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-pill); padding: 5px 10px; cursor: pointer;
}

/* ---------- opening statement ----------
   The finding, at the top, in words. Flush left, no buttons under it. The three figures sit
   below as a rule-separated row because they are the evidence for the sentence above them,
   not decoration. (It was one column with nothing beside it until hero.css added the
   illustration in the space to the right — see that file.)

   `padding-block`, NOT the `padding` shorthand. This element also carries `.wrap`, which
   supplies the page's 26px inline padding at the same 0-1-0 specificity, and `.opening` is
   declared later — so `padding: 74px 0 48px` silently zeroed it and set the whole opening
   section 26px to the left of every other section on the page. Measured, not guessed: the
   headline's left edge was at x=140 while section 01's was at 166. */
.opening { padding-block: 74px 48px; }
.opening__kicker {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--accent-ink); margin-bottom: 22px;
}
.opening h1 {
  font-size: clamp(30px, 5.1vw, 58px); font-weight: 700; letter-spacing: -0.035em;
  line-height: 1.08; max-width: 21ch;
}
.opening h1 em {
  font-style: normal; color: var(--accent-ink);
  /* a rule under the clause that carries the claim, rather than a colour swap
     alone — the sentence still reads if the colour does not arrive */
  border-bottom: 3px solid var(--accent);
  padding-bottom: 1px;
}
.opening__lede {
  margin-top: 24px; max-width: 60ch; font-size: 16.5px; line-height: 1.62; color: var(--ink-2);
}
.opening__lede strong { color: var(--ink); font-weight: 500; }
.opening__meta {
  margin-top: 26px; display: flex; gap: 8px 22px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-3);
}
.opening__meta b { color: var(--ink-2); font-weight: 400; }

.figs--opening { grid-template-columns: repeat(auto-fit, minmax(228px, 1fr)); margin-bottom: 10px; }

/* ---------- the essay grid ----------
   Two columns: a sticky rail of section numbers, and the content. The rail is
   generated from the sections themselves in app.js, so adding a section cannot
   leave the contents list behind. */
.essay {
  max-width: var(--maxw); margin: 0 auto; padding: 0 26px 60px;
  display: grid; grid-template-columns: 152px minmax(0, 1fr); gap: 0 44px;
  align-items: start;
}
.rail { position: sticky; top: 78px; padding-top: 44px; }
.rail ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; }
.rail a {
  display: grid; grid-template-columns: 22px 1fr; gap: 9px;
  padding: 6px 8px 6px 0; text-decoration: none;
  font-size: 12px; line-height: 1.3; color: var(--ink-3);
  border-left: 2px solid transparent; padding-left: 10px;
  transition: color 0.16s, border-color 0.16s;
}
.rail a:hover { color: var(--ink); }
.rail a span { font-family: var(--font-mono); font-size: 11px; color: var(--ink-4); }
.rail a[aria-current="true"] {
  color: var(--ink); font-weight: 500; border-left-color: var(--accent);
}
.rail a[aria-current="true"] span { color: var(--accent-ink); }
.rail__note {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border);
  font-size: 11px; color: var(--ink-4); line-height: 1.5;
}

.essay__body { min-width: 0; }

/* ---------- sections ----------
   A number and a title on one rule. No eyebrow / headline / sub stack. */
.sec { padding: 44px 0 8px; scroll-margin-top: 70px; }
.sec:first-child { padding-top: 34px; }
.sec__head {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  padding-bottom: 12px; border-bottom: 2px solid var(--ink);
  margin-bottom: 24px;
}
.sec__no {
  font-family: var(--font-mono); font-size: 13px; color: var(--accent-ink);
  letter-spacing: 0.06em;
}
.sec__head h2 { font-size: clamp(21px, 2.5vw, 27px); letter-spacing: -0.025em; }
.sec__head p { font-size: 13px; color: var(--ink-3); margin-left: auto; }

/* the reading column: prose is measured, figures are not */
.measure { max-width: var(--measure); }
.measure + .fig-block, .fig-block + .measure { margin-top: 26px; }
.fig-block + .fig-block { margin-top: 18px; }

/* Figures break out of the reading column to the full width of the essay body.
   A matrix with 8 columns and 27 rows is not a thing to read at 68ch.
   They must NOT extend further left than this: the rail is a sticky grid sibling,
   so a negative left margin here slides every figure underneath it and the
   contents list ends up printed on top of a table. (It did. That is why the
   measure is narrow instead — the contrast between 68ch of prose and 1070px of
   figure is already the whole effect.) */
.bleed { margin-inline: 0; }

figure { margin: 0; }
figcaption {
  margin-top: 10px; font-size: 11.5px; color: var(--ink-3); line-height: 1.55;
  /* The same measure as the prose, so a caption's right edge lines up with the paragraph above it.
     It was 78ch, which at 11.5px is 504px against the prose's 573 — near-aligned but not aligned,
     which looks like a mistake rather than a column. See --measure in base.css. */
  max-width: var(--measure);
}
figcaption b { color: var(--ink-2); font-weight: 500; }

/* ---------- active-slice strip ----------
   The collapsed form of the filter bar, for the rest of the page. One line, and only present
   when a filter is off its default or a model is pinned — see the comment on it in index.html
   for why it is a disclosure rather than a second toolbar.

   z-index sits between the masthead (50) and the real filter bar (40). The two never share
   the screen: app.js hides this one while `.filters` is visible, so they cannot both try to
   occupy `top: 54px`. Deliberately no fade — it swaps as you scroll, and a transition on
   something scroll-triggered reads as flicker rather than as polish. */
.slice {
  /* FIXED, not sticky, and that is the whole reason this rule has a comment.

     `position: sticky` participates in normal flow, so the strip RESERVED 42px in the document
     and appearing pushed the entire page — including the hero — down by that much. Everywhere
     below the fold the browser's scroll anchoring hides that; at the very top of the page there
     is nothing above the viewport to anchor to, so clicking a dot in the hero visibly shoved the
     hero down. Fixed positioning never reserves space, so showing or hiding this can no longer
     move anything.

     It costs nothing here: the strip lives at top:54 (under the masthead) and `.opening` has
     74px of top padding, so at scroll 0 the strip sits inside that padding and covers no
     content. Once scrolled it floats over content — which is what it did anyway as a stuck
     sticky element. */
  position: fixed; top: 54px; left: 0; right: 0; z-index: 45;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.slice[hidden] { display: none !important; }
.slice__in {
  max-width: var(--maxw); margin: 0 auto; padding: 8px 26px;
  display: flex; align-items: center; gap: 10px 18px; flex-wrap: wrap;
}
.slice__filters {
  font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-3);
}
.slice__filters b { color: var(--ink-2); font-weight: 400; }
/* The word that does the actual disclosing, so it is the one thing here with weight. */
.slice__filters .on {
  color: var(--accent-ink); text-transform: uppercase; letter-spacing: 0.08em;
  font-size: 10px; margin-right: 8px;
}
.slice .pinbar { width: auto; padding: 0; border: 0; }
.slice__acts { margin-left: auto; display: flex; gap: 8px; }
.slice__btn {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--ink-3);
  background: none; border: 1px solid var(--border); border-radius: var(--r-pill);
  padding: 4px 10px; cursor: pointer; white-space: nowrap;
}
.slice__btn:hover { color: var(--ink); border-color: var(--border-2); }
.slice__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- filter strip ----------
   Scopes every figure below it. Sticky under the masthead so it stays reachable
   while reading the data sections — a filter you have to scroll back up to find
   is a filter nobody uses. */
.filters {
  position: sticky; top: 54px; z-index: 40;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px;
  padding: 11px 16px; margin-bottom: 22px;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border); border-radius: var(--r-lg);
}
.filters__count { margin-left: auto; font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-3); }
.filters .pinbar { width: 100%; padding-top: 9px; border-top: 1px solid var(--border); }

/* ---------- the trace key ----------
   Names the one or two models the trace is drawing, immediately above the rows it draws them
   on. Not a legend off to the side: a reader comparing two models was getting the hovered one
   labelled at the pointer and the pinned one labelled in a different section.

   The swatch is a real line segment with the real dash pattern, so the key cannot describe a
   line style the chart is not using. */
.tracekey {
  /* ITS HEIGHT NEVER CHANGES, AND THAT IS THE WHOLE POINT.

     This bar sits above the chart in normal flow, and it is driven by HOVER. The first version
     appeared and disappeared with the hover, which reflowed the chart underneath it — so the
     pointer stopped being over the dot, the bar vanished, the chart sprang back, the pointer
     was over the dot again, and the page oscillated indefinitely. A hover-driven element must
     never reflow the thing being hovered.

     So the bar is always present and only its CONTENTS change: a hint when nothing is
     selected, one entry when a model is pinned, two when another is hovered. Fixed height plus
     `nowrap` plus `overflow: hidden` means one, two, or no entries all occupy exactly the same
     box — and the two-entry case cannot wrap to a second line either, which would have been
     the same loop at a narrower viewport. The numbers drop out below 900px so two names still
     fit on one line.

     Sticky at --chrome-h so it stays with the chart at any scroll position, and OUTSIDE .card
     because that card sets overflow:hidden, which disables sticky for everything within it.
     z-index under .filters (40), .slice (45) and the masthead (50): if it ever met one, this
     is the thing that should slide beneath. */
  position: sticky; top: var(--chrome-h); z-index: 30;
  display: flex; flex-wrap: nowrap; gap: 0 20px; align-items: center;
  height: 34px; padding: 0 12px; margin: 0 0 6px; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(8px);
  font-size: 11.5px; color: var(--ink-3);
}
.tracekey__item { min-width: 0; }
.tracekey__item .tracekey__name { overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 900px) {
  /* the least essential half, dropped so two model names still fit on one line and the
     height cannot change */
  .tracekey__nums { display: none; }
}
.tracekey__item { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.tracekey__swatch { display: block; width: 22px; height: 2px; flex: none; }
.tracekey__swatch--pin { background: var(--accent-ink); }
/* a dashed swatch as a repeating gradient, so it matches stroke-dasharray: 5 4 */
.tracekey__swatch--hot {
  background: repeating-linear-gradient(to right,
    var(--ink) 0 5px, transparent 5px 9px);
  opacity: 0.75;
}
.tracekey__name { color: var(--ink); font-weight: 500; }
.tracekey__role {
  font-family: var(--font-mono); font-size: 10px; text-transform: uppercase;
  letter-spacing: 0.07em; color: var(--ink-4);
}
.tracekey__nums {
  font-family: var(--font-mono); font-size: 11px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.tracekey__hint { color: var(--ink-4); }

/* ---------- the model trace ----------
   A line joining one model's dot on every benchmark row, so a reader can follow a single model
   down the shared rho axis. It is the visceral form of the page's "median rank span is 18 of
   27" claim: you watch one model swing from the right edge to nothing.

   Two at most, and they are told apart by DASH PATTERN as well as colour — three would need a
   categorical palette, which this build refuses because 27 models cannot pass an all-pairs
   colour-vision check. The pairing matches the dot states: accent for the pinned model,
   neutral for the hovered one.

   pointer-events: none is load-bearing — the dots underneath must stay hoverable and
   clickable, and the overlay covers all of them. */
.trace-host { position: relative; }
.trace {
  position: absolute; left: 0; top: 0;
  pointer-events: none; overflow: visible;
}
.trace path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
/* The line colours are the same two the DOT states use — --accent-ink for the pinned model,
   --ink for the hovered one — so a line and the dots it joins say the same thing in the same
   colour. It is also the only pairing that clears the dataviz floor: --ink-3 was tried first
   and measured only dE 13.5 from --accent-ink, under the 15 that full-colour readers need, and
   the dash pattern does not excuse that. --ink vs --accent-ink is dE 36.1 light / 26.8 dark. */
.trace .trace__pin { stroke: var(--accent-ink); stroke-width: 1.75; }
.trace .trace__hot { stroke: var(--ink); stroke-width: 1.5; stroke-dasharray: 5 4; opacity: 0.75; }

/* ---------- benchmark table with strips ---------- */
.bench { width: 100%; font-size: 13px; min-width: 720px; }
.bench thead th {
  text-align: left; font-weight: 400; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: 0.07em; color: var(--ink-3); padding: 9px 11px;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.bench thead th.num { text-align: right; }
.bench thead th.strip-col { width: 46%; }
.bench tbody th {
  text-align: left; font-weight: 400; padding: 9px 11px;
  border-bottom: 1px solid var(--grid); vertical-align: middle;
}
.bench tbody th .sub { display: block; font-size: 10.5px; color: var(--ink-4); }
.bench tbody td { padding: 9px 11px; border-bottom: 1px solid var(--grid); vertical-align: middle; }
.bench tbody tr:last-child th, .bench tbody tr:last-child td { border-bottom: 0; }
.bench tbody tr:hover th, .bench tbody tr:hover td { background: var(--surface-2); }
.bench td.num {
  text-align: right; font-family: var(--font-mono); font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
.bench td.nowrap { white-space: nowrap; text-align: right; font-family: var(--font-sans); font-size: 12px; color: var(--ink-2); }
.bench .strip-cell { padding: 4px 11px; min-width: 240px; }
/* The axis lives in a tfoot cell in the strip COLUMN, not in a div under the
   whole card: an axis whose ticks do not sit above the data they scale is worse
   than no axis. */
.bench tfoot td { border-bottom: 0; padding: 0 11px 9px; }
.bench tfoot .strip__axis { padding: 0; }

/* ---------- matrices in the essay ---------- */
.mxwrap--essay { max-height: 620px; }
.mxwrap--ag { max-height: none; }

/* ---------- spread figure ---------- */
.spreadcard { padding: 16px 18px 12px; }

/* ---------- effort block ----------
   Three model pairs, eight benchmarks each. A table, not a chart: 24 signed
   numbers where the reader's question is "is the sign consistent", and a sign is
   read faster from a printed value than from a bar's direction. */
.effort { width: 100%; font-size: 12.5px; }
.effort th, .effort td { padding: 7px 9px; border-bottom: 1px solid var(--grid); text-align: right; }
.effort thead th {
  font-weight: 400; font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-3); white-space: nowrap;
}
.effort tbody th { text-align: left; font-weight: 400; color: var(--ink-2); white-space: nowrap; }
.effort td { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.effort .up { color: var(--accent-ink); }
.effort .down { color: var(--amber-ink); }
.effort tfoot td, .effort tfoot th {
  border-bottom: 0; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--ink-3);
}

/* ---------- limits list ---------- */
.limits { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--border); border-radius: var(--r-lg); overflow: hidden; }
.limits li { background: var(--surface); padding: 15px 18px; }
.limits h4 { font-size: 13px; margin-bottom: 5px; }
.limits p { font-size: 13px; color: var(--ink-3); line-height: 1.55; }

/* ---------- method section: two columns on a wide screen ----------
   06 is the only section built from two blocks of comparable weight rather than prose-then-figure:
   three short definitions, and four short caveats. Stacked, that was a half-width prose block
   followed by a full-width list, which is the one place on the page where the reading column's
   empty half is next to something that fills it — so the empty half read as a mistake.

   Side by side they are a spread, which is what reference material at the end of an essay wants to
   be, and section 06 gets about 40% shorter. Explicit two-column template rather than
   `repeat(auto-fit, minmax(...))`: auto-fit will happily make a third column and leave it empty,
   which this project has shipped once.

   1100px, not the 900px breakpoint: below that each column would be under 500px and the caveat
   cards get too narrow to hold a heading and three lines without looking cramped. */
@media (min-width: 1100px) {
  .method {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0 38px; align-items: start;
  }
  /* The COLUMN is the measure here, and it is narrower than --measure, so the cap would do nothing
     but it is removed for clarity: the width is the grid's job in this block. */
  .method > .measure { max-width: none; }
  /* `.measure + .fig-block` adds 26px above the list when they are stacked. Side by side that
     margin would drop the right column below the left one's first line. */
  .method > .fig-block { margin-top: 0; }
}

/* ---------- footer ---------- */
.foot {
  border-top: 1px solid var(--border); margin-top: 20px;
  padding: 26px 0 40px; font-size: 12px; color: var(--ink-3);
}
.foot__in {
  max-width: var(--maxw); margin: 0 auto; padding: 0 26px;
  display: flex; gap: 16px 30px; flex-wrap: wrap; align-items: baseline;
}
.foot__in p { max-width: 62ch; line-height: 1.6; }
.foot code { font-family: var(--font-mono); font-size: 11.5px; }

/* ---------- responsive ---------- */
@media (max-width: 1060px) {
  .essay { grid-template-columns: minmax(0, 1fr); gap: 0; }
  /* The rail becomes a horizontal strip above the essay rather than vanishing:
     it is the only table of contents this page has. */
  .rail {
    position: sticky; top: 54px; z-index: 45; padding: 0;
    background: color-mix(in srgb, var(--page) 92%, transparent);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
    margin-bottom: 6px;
  }
  .rail ol { flex-direction: row; overflow-x: auto; gap: 0; }
  .rail a {
    border-left: 0; border-bottom: 2px solid transparent;
    padding: 9px 12px; white-space: nowrap; grid-template-columns: auto auto;
  }
  .rail a[aria-current="true"] { border-left-color: transparent; border-bottom-color: var(--accent); }
  .rail__note { display: none; }
  .filters { top: 96px; }
  .bleed { margin-left: 0; }
}
@media (max-width: 760px) {
  .wrap, .masthead__in, .essay, .foot__in { padding-inline: 18px; }
  .opening { padding-top: 46px; }
  .sec__head p { margin-left: 0; width: 100%; }
  .masthead__jump label { display: none; }
}
