/* ibm-1 site ------------------------------------------------------------
   the opener is one committed visual world: ink-blue black, the substrate's own
   atlas colours, and one amber chrome.  a materialization drains the atlas
   colour away and puts the traced route's own ramp in its place -- red at the
   input, purple at the output -- which is also what the input and output
   annotations are coloured, so a label and the end of the path it points at
   agree.  the paper below is themed: bone paper by day, the same ink by night. */

:root {
  /* the opener, single-theme */
  --ink: #07090f;
  --ink-2: #0d1019;
  --on-ink: #e9e7e0;
  --on-ink-muted: #8d93a1;
  --on-ink-faint: rgba(233, 231, 224, 0.28);
  /* the traced route's two ends.  brain.js owns this pair (TRACE) and writes it
     back onto :root at load; these are the same values, for before it runs. */
  --trace-in: #f5424d;    /* observed — where a signal enters the trace */
  --trace-out: #a159fa;   /* target — where it leaves */
  --accent-ink: #f0b34a;  /* the opener's chrome: ring, titles, focus */
  --clamp: #c9a4ff;       /* clamped / intervention */

  /* the paper, light */
  --paper: #f1f1ec;
  --paper-2: #e8e8e1;
  --text: #14161c;
  --muted: #5f6470;
  --rule: #d3d3cb;
  --accent: #a8690f;
  --accent-soft: rgba(240, 179, 74, 0.18);
  --fail: #b23a2f;
  --moved: #2f7a58;
  --half: #8a6d1d;
  --lane-1: #2f8a80; --lane-2: #3d68b0; --lane-3: #b0485e; --lane-4: #5b8a36;  /* lineage corpora */
  --fig-in: #bd2f3b;      /* the trace ramp's two ends, weighted for bone paper */
  --fig-out: #6d34c0;
  --fig-note: #14161c;
  --fig-muted: #5f6470;
  --fig-panel: rgba(241, 241, 236, 0.72);

  --serif: "Source Serif 4", "Iowan Old Style", Georgia, serif;
  --display: "Source Serif 4", "Iowan Old Style", Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0f1117; --paper-2: #161a23; --text: #e6e4dd; --muted: #9198a6; --rule: #2a2e38;
    --accent: #f0b34a; --accent-soft: rgba(240, 179, 74, 0.14); --fail: #e5766a; --moved: #6fc39a; --half: #d9b25a;
    --lane-1: #5fc0b3; --lane-2: #7da6ea; --lane-3: #e58299; --lane-4: #93c870;
    --fig-in: var(--trace-in); --fig-out: var(--trace-out); --fig-note: #e6e4dd; --fig-muted: #9198a6; --fig-panel: rgba(15, 17, 23, 0.6);
  }
}
:root[data-theme="dark"] {
  --paper: #0f1117; --paper-2: #161a23; --text: #e6e4dd; --muted: #9198a6; --rule: #2a2e38;
  --accent: #f0b34a; --accent-soft: rgba(240, 179, 74, 0.14); --fail: #e5766a; --moved: #6fc39a; --half: #d9b25a;
  --lane-1: #5fc0b3; --lane-2: #7da6ea; --lane-3: #e58299; --lane-4: #93c870;
  --fig-in: var(--trace-in); --fig-out: var(--trace-out); --fig-note: #e6e4dd; --fig-muted: #9198a6; --fig-panel: rgba(15, 17, 23, 0.6);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0; background: var(--paper); color: var(--text); position: relative;
  font-family: var(--serif); font-size: 18px; line-height: 1.55;
  font-optical-sizing: auto; -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration-color: var(--accent); text-underline-offset: 0.16em; }
a:hover { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 3px; }
code { font-family: var(--mono); font-size: 0.82em; background: var(--paper-2); padding: 0.05em 0.35em; border-radius: 3px; }
.mono { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; }

.bg { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.hero, .paper { position: relative; z-index: 1; }

/* ===================================================================== hero */
.hero {
  position: relative; height: 100svh; min-height: 640px; overflow: hidden;
  background: radial-gradient(ellipse 70% 60% at 50% 45%, rgba(18, 22, 39, 0.55) 0%, rgba(7, 9, 15, 0.7) 65%);
  color: var(--on-ink); user-select: none;
}
.hero.dragging { cursor: grabbing; }
#hero-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.hero.near #hero-canvas { cursor: grab; }
.hero.dragging #hero-canvas { cursor: grabbing; }
.leaders { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.leader { fill: none; stroke: var(--on-ink-faint); stroke-width: 1; color: var(--on-ink-faint); transition: stroke 0.25s, color 0.25s, opacity 0.4s; }
.ring-leader { marker-end: url(#arrow); }
.hero.narrow .ring-leader { marker-end: none; }
.ring-join { fill: var(--on-ink); opacity: 0.8; }
.hero.is-hovering .ring-leader { stroke: rgba(233, 231, 224, 0.1); color: rgba(233, 231, 224, 0.1); }
.ann-svg .leader { stroke-width: 1.2; }
.ann-svg .loop { stroke-dasharray: 3 3; stroke-width: 1; opacity: 0.9; }
.ann-svg .branches { stroke-width: 0.9; opacity: 0.85; }
.ann-svg .leader-dot { fill: currentColor; }
.ann-svg.ann-in { color: var(--trace-in); } .ann-svg.ann-in .leader { stroke: var(--trace-in); }
.ann-svg.ann-out { color: var(--trace-out); } .ann-svg.ann-out .leader { stroke: var(--trace-out); }
.ann-svg.ann-note { color: var(--on-ink); } .ann-svg.ann-note .leader { stroke: var(--on-ink); opacity: 0.8; }
.ann-svg.hover-ann { color: var(--accent-ink); } .ann-svg.hover-ann .leader { stroke: var(--accent-ink); }
.ann-svg { animation: ann-in 0.6s 0.9s both; }
.ann-svg.hover-ann { animation: none; }

.wordmark {
  position: absolute; left: 50%; top: 42%; transform: translate(-50%, -50%);
  margin: 0; font-family: var(--display); font-weight: 300; font-variation-settings: "opsz" 60;
  font-size: clamp(84px, 17vw, 260px); line-height: 0.9; letter-spacing: -0.03em;
  color: var(--on-ink); mix-blend-mode: screen; opacity: 0.92; pointer-events: none; white-space: nowrap;
  transition: opacity 0.6s, transform 0.8s cubic-bezier(.2,.7,.2,1);
}
.wordmark .wm-dash { font-weight: 300; margin: 0 -0.04em; opacity: 0.55; }
.hero.has-selection .wordmark { opacity: 0.1; transform: translate(-50%, -50%) scale(0.94); transition-duration: 1.2s; }

.hero-down {
  position: absolute; bottom: 18px; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.12em;
  color: var(--on-ink-muted); text-transform: uppercase; transition: opacity 0.8s;
  right: 22px; bottom: 14px; text-decoration: none; font-size: 1rem;
}
.hero-down:hover { color: var(--accent-ink); }

/* the ring of materializations ------------------------------------------- */
.ring { position: absolute; inset: 0; pointer-events: none; transition: opacity 0.35s; }
.hero.has-selection .ring { opacity: 0; pointer-events: none; }
.ring-item {
  position: absolute; pointer-events: auto; appearance: none; background: none; border: 0; padding: 4px 6px; margin: 0;
  color: var(--on-ink); font: 500 0.72rem/1.1 var(--mono); letter-spacing: 0.06em; cursor: pointer;
  white-space: nowrap; transform: translate(-50%, -50%); opacity: 0.86;
  transition: color 0.2s, opacity 0.2s, transform 0.3s;
}
.ring-item[data-side="l"] { transform: translate(-100%, -50%); text-align: right; }
.ring-item[data-side="r"] { transform: translate(0, -50%); text-align: left; }
.ring-item:hover, .ring-item.is-hover, .ring-item:focus-visible { color: var(--accent-ink); opacity: 1; }
.hero.is-hovering .ring-item:not(.is-hover) { opacity: 0.35; }
.ring-item .ring-label { position: relative; }
.ring-item .ring-label::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -3px; height: 1px; background: currentColor; opacity: 0; transition: opacity 0.2s;
}
.ring-item:hover .ring-label::after, .ring-item.is-hover .ring-label::after { opacity: 0.7; }
.ring-group {
  display: block; font-size: 0.58rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent-ink); opacity: 0.85; margin-bottom: 4px;
}
.ring-item[data-side="l"] .ring-group { text-align: right; }

/* selected mode ------------------------------------------------------------ */
.selected { position: absolute; inset: 0; pointer-events: none; opacity: 0; visibility: hidden; transition: opacity 0.4s 0.1s, visibility 0s 0.5s; }
.hero.has-selection .selected { opacity: 1; visibility: visible; transition: opacity 0.7s 0.5s, visibility 0s; }
.sel-close {
  position: absolute; top: 18px; right: 18px; pointer-events: auto; appearance: none; cursor: pointer;
  width: 52px; height: 52px; border-radius: 50%; border: 1px solid var(--on-ink-faint); background: rgba(7, 9, 15, 0.5);
  color: var(--on-ink); font: 300 28px/1 var(--display); display: grid; place-items: center; backdrop-filter: blur(6px);
  transition: border-color 0.2s, color 0.2s, transform 0.3s;
}
.sel-close:hover { border-color: var(--accent-ink); color: var(--accent-ink); transform: rotate(90deg); }
.sel-close-hint { position: absolute; top: 100%; margin-top: 6px; font: 400 0.58rem/1 var(--mono); letter-spacing: 0.18em; text-transform: uppercase; color: var(--on-ink-muted); }
.sel-head { position: absolute; top: 22px; left: 26px; max-width: min(46ch, 44vw); pointer-events: auto; }
.sel-title { margin: 0 0 10px; font-family: var(--display); font-weight: 600; font-style: normal; font-variation-settings: "opsz" 60; font-size: clamp(38px, 4.6vw, 66px); line-height: 1; letter-spacing: -0.02em; text-wrap: balance; color: var(--accent-ink); }
.sel-doc { margin: 0; font-size: 0.98rem; line-height: 1.45; color: var(--on-ink); opacity: 0.85; max-width: 44ch; }

.ann-col { position: absolute; top: 50%; transform: translateY(-50%); display: flex; flex-direction: column; gap: 14px; pointer-events: auto; max-height: 82%; }
.ann-col-in { left: 26px; align-items: flex-start; }
.ann-col-out { right: 26px; align-items: flex-end; }
.ann-col-title { font: 500 0.6rem/1 var(--mono); letter-spacing: 0.24em; text-transform: uppercase; color: var(--on-ink-muted); margin-bottom: 4px; }
.ann-col-in .ann-col-title { color: var(--trace-in); }
.ann-col-out .ann-col-title { color: var(--trace-out); }
/* the label carries the hue too, so the whole annotation — title, label, leader,
   and the node the leader lands on — is one colour */
.ann-in .ann-label { color: var(--trace-in); }
.ann-out .ann-label { color: var(--trace-out); }
.ann-col > div { display: flex; flex-direction: column; gap: 12px; }
.ann-col-out > div { align-items: flex-end; }
.ann { display: grid; gap: 2px; padding: 4px 10px; max-width: 24ch;
  animation: ann-in 0.6s 0.9s cubic-bezier(.2,.7,.2,1) both; }
.ann-out { text-align: right; }
.ann-label { font-family: var(--display); font-weight: 600; font-variation-settings: "opsz" 24; font-size: 1.05rem; line-height: 1.15; letter-spacing: -0.005em; }
.ann-id { font: 400 0.62rem/1.2 var(--mono); color: var(--on-ink-muted); letter-spacing: 0.02em; }
.ann:nth-child(2) { animation-delay: 1s; } .ann:nth-child(3) { animation-delay: 1.1s; } .ann:nth-child(4) { animation-delay: 1.2s; }
.ann:nth-child(5) { animation-delay: 1.3s; } .ann:nth-child(6) { animation-delay: 1.4s; } .ann:nth-child(7) { animation-delay: 1.5s; }
@keyframes ann-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ann, .ann-svg { animation: none; } .sel-close:hover { transform: none; } }

/* narrow layout: the same hero, but forty labels cannot ring a portrait
   figure.  brain.js packs them into a band above and a band below the brain
   instead, two columns about a centre gutter in each band, and a selection
   puts the inputs under the title and the outputs along the bottom the same
   way, leaders and all. */
.hero.narrow .wordmark { font-size: clamp(64px, 20vw, 120px); }
.hero.narrow .ring-item { padding: 1px 4px; font-size: 0.64rem; transition: color 0.2s, opacity 0.2s, transform 0.3s, top 0.5s; }
.hero.narrow .ring-group { font-size: 0.52rem; margin: 3px 0 1px; }
.hero.narrow .hero-down { display: none; }
.hero.narrow .sel-close { top: 10px; right: 10px; width: 40px; height: 40px; font-size: 22px; }
.hero.narrow .sel-close-hint { display: none; }
.hero.narrow .sel-head { top: 12px; left: 14px; right: 60px; max-width: none; }
.hero.narrow .sel-title { font-size: clamp(26px, 7vw, 40px); margin-bottom: 6px; }
.hero.narrow .sel-doc { font-size: 0.8rem; line-height: 1.35; max-width: none; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
.hero.narrow .ann-col { transform: none; top: auto; left: 12px; right: 12px; max-height: none; gap: 4px; align-items: center; }
.hero.narrow .ann-col-in { top: calc(12px + clamp(26px, 7vw, 40px) + 6px + 3.4rem + 14px); }
.hero.narrow .ann-col-out { bottom: 12px; }
.hero.narrow .ann-col > div { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 56px; align-items: start; align-self: stretch; }
.hero.narrow .ann { padding: 2px 4px; max-width: 20ch; }
.hero.narrow .ann:nth-child(odd) { justify-self: end; text-align: right; }
.hero.narrow .ann:nth-child(even) { justify-self: start; text-align: left; }
.hero.narrow .ann-label { font-size: 0.86rem; }

/* ==================================================================== paper */
.paper { max-width: none; margin: 0; padding: 0 clamp(18px, 4vw, 48px) 80px; background: color-mix(in srgb, var(--paper) 84%, transparent); }
.paper > * { max-width: 1180px; margin-left: auto; margin-right: auto; }
.masthead { padding: 64px 0 40px; border-bottom: 1px solid var(--rule); }
.eyebrow { margin: 0 0 28px; font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.standfirst { margin: 0; max-width: 68ch; font-family: var(--display); font-weight: 400; font-variation-settings: "opsz" 32; font-size: clamp(20px, 2.3vw, 27px); line-height: 1.45; letter-spacing: -0.008em; text-wrap: pretty; }
.standfirst em { font-style: normal; font-weight: 600; color: var(--accent); }

.sec { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 32px; padding: 56px 0; border-bottom: 1px solid var(--rule); }
.margin { display: grid; align-content: start; gap: 8px; position: sticky; top: 28px; align-self: start; z-index: 2; }
.margin .mono { color: var(--accent); }
.margin span:last-child { font-family: var(--display); font-style: normal; font-weight: 600; font-variation-settings: "opsz" 20; font-size: 1.25rem; line-height: 1.2; color: var(--text); }
.body { max-width: 68ch; }
.body p { margin: 0 0 1.2em; }
.body h3 { margin: 2em 0 0.5em; font-family: var(--display); font-weight: 500; font-variation-settings: "opsz" 24; font-size: 1.35rem; line-height: 1.2; letter-spacing: -0.01em; text-wrap: balance; }
.note { font-size: 0.94rem; color: var(--muted); border-top: 1px solid var(--rule); padding-top: 14px; }
.caption { font-size: 0.86rem; color: var(--muted); font-style: italic; }
.display-math { font-family: var(--display); font-weight: 400; font-variation-settings: "opsz" 24; font-size: 1.6rem; letter-spacing: 0.01em; margin: 0.6em 0 1.2em !important; padding-left: 1.2em; border-left: 2px solid var(--accent); }
.display-math sub { font-size: 0.6em; }
.math { font-family: var(--display); font-weight: 400; font-style: italic; font-size: 1.15rem; letter-spacing: 0.01em; }

/* the four primitives: a name and its formula on one line, one sentence or
   two beneath, and a single quiet line that opens the registry for it */
.prims { display: grid; grid-template-columns: 1fr 1fr; gap: 32px 40px; margin: 8px 0 12px; }
.prim { display: grid; gap: 10px; align-content: start; padding-top: 14px; border-top: 1px solid var(--rule); min-width: 0; }
.prim-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 16px; }
.prim .mono { color: var(--accent); }
.prim .math { font-size: 1.08rem; }
.prim p { margin: 0; font-size: 0.94rem; line-height: 1.5; }
.prim-more { margin-top: 2px; }
.prim-more summary { cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 8px; padding: 4px 0; font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.06em; color: var(--muted); }
.prim-more summary::-webkit-details-marker { display: none; }
.prim-more summary::before { content: "+"; color: var(--accent); font-size: 0.85rem; }
.prim-more[open] summary::before { content: "−"; }
.prim-more summary:hover { color: var(--text); }
.prim-more summary em { font-style: normal; }
.prim-more .reg-list { padding: 6px 0 4px; display: grid; gap: 6px; }
/* the registry itself is fine print: one small paragraph per entry, nothing tabular */
.reg-list p { margin: 0; font-size: 0.7rem; line-height: 1.45; color: var(--muted); overflow-wrap: anywhere; }
.reg-list code { font-size: 0.66rem; background: none; padding: 0; color: var(--text); }
.reg-list p > code:first-child { color: var(--accent); }

.pull { margin: 0 auto; padding: 64px 0; border-bottom: 1px solid var(--rule); display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 32px; }
.pull p { grid-column: 2; margin: 0; max-width: 34ch; font-family: var(--display); font-weight: 400; font-style: italic; font-variation-settings: "opsz" 60; font-size: clamp(22px, 2.4vw, 30px); line-height: 1.3; letter-spacing: -0.005em; text-wrap: balance; }
.pull cite { grid-column: 2; margin-top: 14px; font-family: var(--mono); font-style: normal; font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }

/* §2 leads with four propositions rather than the whole assay: a numbered head, one
   paragraph of claim, then the two or three figures that would have to move for the
   claim to be untrue -- each with what it was measured AGAINST, never bare.
   the assay itself is kept entire, one <details> below, because the withdrawals in it
   are the most reused thing here and must not become a thing you have to ask for. */
.lede-top { font-size: 1.02rem; line-height: 1.5; color: var(--muted); max-width: 62ch; }
.lede-top em { font-style: normal; font-weight: 600; color: var(--text); }

.props { display: grid; gap: 34px; margin: 26px 0 8px; }
.prop { display: grid; gap: 12px; align-content: start; padding-top: 16px; border-top: 1px solid var(--text); }
.prop-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px; }
.prop-head .mono { color: var(--accent); font-size: 0.68rem; letter-spacing: 0.12em; }
.prop-head h3 { margin: 0; flex: 1 1 18ch; font-family: var(--display); font-weight: 600;
  font-variation-settings: "opsz" 32; font-size: 1.42rem; line-height: 1.15; letter-spacing: -0.012em; text-wrap: balance; }
.prop-head .tag { flex: none; }
.prop > p { margin: 0; max-width: 62ch; }
.prop em { font-style: normal; font-weight: 600; color: var(--text); }

/* a figure and its baseline, read as one line: the number carries the eye, the clause
   beside it says what the number is against */
.prop-figs { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 12px; }
.prop-figs li { display: grid; grid-template-columns: 15ch minmax(0, 1fr); gap: 4px 20px;
  align-items: baseline; padding-top: 11px; border-top: 1px solid var(--rule); }
.prop-figs b { font-family: var(--display); font-weight: 600; font-variation-settings: "opsz" 40;
  font-size: 1.24rem; line-height: 1.15; letter-spacing: -0.015em; color: var(--accent);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.prop-figs span { font-size: 0.9rem; line-height: 1.45; color: var(--muted); }
.prop-figs em { font-style: italic; font-weight: 400; color: var(--text); }
.prop-figs code { font-size: 0.8rem; padding: 0.05em 0.28em; margin-right: -0.2em; }

.prop-note { margin-top: 30px; max-width: 62ch; }
.prop-note em { font-style: italic; color: var(--text); }

.assay { margin: 26px 0 0; border-top: 1px solid var(--rule); }
.assay summary { cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 8px;
  padding: 12px 0 2px; font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.06em; color: var(--muted); }
.assay summary::-webkit-details-marker { display: none; }
.assay summary::before { content: "+"; color: var(--accent); font-size: 0.85rem; }
.assay[open] summary::before { content: "−"; }
.assay summary:hover { color: var(--text); }
.assay summary em { font-style: normal; }

.table-wrap { overflow-x: auto; margin: 8px 0 20px; }
.claims { width: 100%; border-collapse: collapse; font-size: 0.94rem; line-height: 1.4; min-width: 560px; }
.claims th { text-align: left; font-family: var(--mono); font-weight: 500; font-size: 0.64rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); padding: 0 12px 10px 0; border-bottom: 1px solid var(--text); }
.claims td { vertical-align: top; padding: 11px 12px 11px 0; border-bottom: 1px solid var(--rule); }
.claims td:first-child { font-family: var(--display); font-weight: 500; font-variation-settings: "opsz" 24; font-size: 1rem; width: 36%; }
.claims .num { text-align: right; padding-right: 0; white-space: nowrap; }
.tag { display: inline-block; font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; padding: 3px 7px; border: 1px solid currentColor; border-radius: 2px; }
.tag-fail { color: var(--fail); }
.tag-moved { color: var(--moved); }
.tag-half { color: var(--half); }

.arc { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; margin: 10px 0 18px; border-top: 1px solid var(--text); }
.arc-step { display: grid; align-content: start; gap: 4px; padding: 14px 14px 14px 0; border-right: 1px solid var(--rule); margin-right: 14px; }
.arc-step:last-child { border-right: 0; margin-right: 0; }
.arc-n { font-family: var(--display); font-weight: 400; font-variation-settings: "opsz" 60; font-size: clamp(28px, 3.2vw, 44px); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.arc-step-hi .arc-n { color: var(--accent); }
.arc-l { font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.08em; text-transform: uppercase; }
.arc-d { font-size: 0.84rem; line-height: 1.35; color: var(--muted); }

.bars { display: grid; gap: 8px; margin: 12px 0 10px; }
.bar { display: grid; grid-template-columns: 120px 1fr 56px; align-items: center; gap: 12px; font-size: 0.9rem; }
.bar-l { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.08em; text-transform: uppercase; }
.bar-t { height: 12px; background: var(--paper-2); position: relative; }
.bar-t i { position: absolute; inset: 0; width: calc(var(--v) * 100%); background: var(--muted); }
.bar-hi .bar-t i { background: var(--accent); }
.bar-n { font-family: var(--mono); font-size: 0.8rem; text-align: right; font-variant-numeric: tabular-nums; }

.corpus { list-style: none; margin: 8px 0 20px; padding: 0; columns: 2; column-gap: 32px; font-size: 0.94rem; }
.corpus li { break-inside: avoid; padding: 6px 0; border-bottom: 1px solid var(--rule); display: flex; gap: 12px; align-items: baseline; }
.corpus b { font-family: var(--display); font-weight: 500; font-size: 1.1rem; min-width: 2ch; text-align: right; font-variant-numeric: tabular-nums; }


.next { margin: 8px 0 22px; padding: 0; list-style: none; display: grid; gap: 10px; }
.next li { padding-left: 18px; position: relative; }
.next li::before { content: ""; position: absolute; left: 0; top: 0.62em; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
.next b { font-weight: 600; }

.colophon { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; padding: 40px 0 0; font-size: 0.9rem; color: var(--muted); }
.colophon p { margin: 0 0 6px; }
.colophon .mono { color: var(--accent); margin-bottom: 10px; }

@media (max-width: 960px) {
  /* minmax(0, …) rather than 1fr: a wide table inside must scroll, never push
     the section — and the page with it — past the viewport */
  .sec, .pull { grid-template-columns: minmax(0, 1fr); gap: 18px; padding: 44px 0; }
  .margin { position: static; grid-template-columns: auto 1fr; align-items: baseline; }
  .body { min-width: 0; }
  .pull p, .pull cite { grid-column: 1; }
  .arc { grid-template-columns: 1fr 1fr; }
  /* the figure stacks over its baseline rather than squeezing the clause to a few words */
  .prop-figs li { grid-template-columns: minmax(0, 1fr); gap: 3px; }
  .arc-step:nth-child(2) { border-right: 0; }
  .colophon { grid-template-columns: 1fr; }
  .masthead { padding: 44px 0 32px; }
}
@media (max-width: 600px) {
  body { font-size: 17px; }
  .paper { padding-bottom: 56px; }
  .masthead { padding: 36px 0 28px; }
  .standfirst { font-size: 19px; line-height: 1.5; }
  .sec { padding: 36px 0; }
  .prims { grid-template-columns: 1fr; gap: 24px; }
  .display-math { font-size: 1.25rem; padding-left: 0.9em; }
  .corpus { columns: 1; }
  .arc { grid-template-columns: 1fr; }
  .arc-step { border-right: 0; margin-right: 0; border-bottom: 1px solid var(--rule); }
  .bar { grid-template-columns: 96px 1fr 50px; }
  /* the claims table stacks: claim and outcome on one line, the measurement under */
  .table-wrap { overflow: visible; margin: 4px 0 8px; }
  .claims { min-width: 0; border-top: 1px solid var(--text); }
  .claims thead { display: none; }
  .claims tbody { display: block; }
  .claims tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 14px; align-items: baseline; padding: 12px 0; border-bottom: 1px solid var(--rule); }
  .claims td { display: block; padding: 0; border: 0; width: auto; }
  .claims td:first-child { width: auto; grid-column: 1; grid-row: 1; font-size: 0.98rem; }
  .claims td.num { grid-column: 2; grid-row: 1; }
  .claims td:nth-child(2) { grid-column: 1 / -1; font-size: 0.86rem; color: var(--muted); }
  .tip { max-width: calc(100vw - 24px); }
  .tip.tip-wide { max-width: calc(100vw - 24px); }
}

/* ================================================================ figures */
.snap { position: relative; margin: 28px 0 32px; background: none; color: var(--fig-note); overflow: hidden; }
.snap canvas { display: block; width: 100%; height: var(--snap-h, auto); cursor: grab; touch-action: pan-y; user-select: none; }
.snap.dragging canvas { cursor: grabbing; }
.snap .leaders { position: absolute; left: 0; top: 0; width: 100%; height: var(--snap-h, 100%); pointer-events: none; }
.snap-labels { position: absolute; inset: 0; height: var(--snap-h, 100%); pointer-events: none; }
.snap .ann-snap { position: absolute; transform: translateY(-50%); animation: none; max-width: 21ch; color: var(--fig-note); }
.snap .ann-snap[data-side="l"] { left: 10px; }
.snap .ann-snap[data-side="r"] { right: 10px; text-align: right; }
.snap .ann-snap .ann-label { font-size: 0.92rem; }
/* the figures take the same two hues, at the weight their paper asks for */
.snap .ann-snap.ann-in .ann-label { color: var(--fig-in); }
.snap .ann-snap.ann-out .ann-label { color: var(--fig-out); }
.snap .ann-snap .ann-id { color: var(--fig-muted); }
.snap .ann-svg { animation: none; }
.snap .ann-svg.ann-in { color: var(--fig-in); } .snap .ann-svg.ann-in .leader { stroke: var(--fig-in); }
.snap .ann-svg.ann-out { color: var(--fig-out); } .snap .ann-svg.ann-out .leader { stroke: var(--fig-out); }
.snap .ann-svg.ann-note { color: var(--fig-note); } .snap .ann-svg.ann-note .leader { stroke: var(--fig-note); opacity: 0.75; }
/* a narrow figure has no room beside the brain: the labels sit in two columns
   under it and their leaders climb into the drawing (brain.js sets .narrow and
   stretches the leader layer over both) */
.snap.narrow .snap-labels { position: relative; inset: auto; height: auto; display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row dense; gap: 12px 16px; padding: 18px 18px 4px; }
.snap.narrow .ann-snap { position: static; transform: none; max-width: none; padding: 0; }
.snap.narrow .ann-snap[data-side="l"] { grid-column: 1; }
.snap.narrow .ann-snap[data-side="r"] { grid-column: 2; text-align: right; }
.snap.narrow .ann-snap .ann-label { font-size: 0.88rem; }
.snap figcaption { position: relative; padding: 10px 0 0; font-size: 0.86rem; line-height: 1.45; color: var(--muted); border-top: 1px solid var(--rule); }
.snap figcaption b { color: var(--text); font-weight: 600; font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase; margin-right: 6px; }
.body figure.snap { max-width: none; }
.snap:not(.rendered) canvas { min-height: 200px; }

/* ================================================================= lineup */
.body-wide { max-width: none; }
.body-wide > .note { max-width: 68ch; }
.lineup { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px 28px; margin: 24px 0 40px; }
.line { display: grid; gap: 0; align-content: start; }
.line .snap { margin: 0 0 6px; }
.line .snap-small canvas { height: var(--snap-h, auto); }
.line-text { display: grid; gap: 2px; }
.line-text .mono { color: var(--accent); }
.status { font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase; padding: 6px 0 0; border-top: 1px solid var(--rule); margin-top: 4px; }
.status-built { color: var(--moved); }
.status-open { color: var(--half); }
.status-declared { color: var(--muted); }
.h-plain { margin: 8px 0 12px; font-size: 1.15rem; font-weight: 600; }
.wrong { margin: 6px 0 24px; padding: 0; list-style: none; counter-reset: wrong; display: grid; gap: 12px; }
.wrong li { counter-increment: wrong; padding-left: 34px; position: relative; font-size: 0.96rem; line-height: 1.5; }
.wrong li::before { content: counter(wrong); position: absolute; left: 0; top: 0.15em; font-family: var(--mono); font-size: 0.7rem; color: var(--fail); }
.wrong li span { font-weight: 600; }
@media (max-width: 960px) {
  .lineup { grid-template-columns: 1fr 1fr; }
  .compute { grid-template-columns: 1fr 1fr; }
  .compute > div:nth-child(2) { border-right: 0; }
  .traj { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
  /* each release line is a thumbnail beside its list, not a full-width figure */
  .lineup { grid-template-columns: 1fr; gap: 22px; }
  .line { grid-template-columns: minmax(0, 32%) minmax(0, 1fr); gap: 14px; align-items: center; }
  .line .snap { margin: 0; }
  .models .model-toggle em { display: none; }   /* the count is one tap away, and the name needs the room */
  .models .model-toggle em + b { margin-left: auto; }
  .compute { grid-template-columns: 1fr; }
  .compute > div { border-right: 0; margin-right: 0; border-bottom: 1px solid var(--rule); }
  .snap .ann-snap { max-width: 14ch; }
}

/* ================================================================= models */
.models { list-style: none; margin: 2px 0 0; padding: 0; display: grid; gap: 5px; }
.models li { min-width: 0; }
.models .model { display: flex; align-items: baseline; gap: 8px; min-width: 0; width: 100%; font-size: 0.8rem; color: inherit; text-decoration: none; }
.models code { font-size: 0.7rem; background: none; padding: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.models b { font-family: var(--mono); font-size: 0.7rem; font-weight: 500; color: var(--accent); margin-left: auto; white-space: nowrap; font-variant-numeric: tabular-nums; }
.models .wip b { color: var(--muted); }
.models a.model:hover code { color: var(--accent); }
.models .hf { font-size: 0.8rem; line-height: 1; }
/* a model that has weights: the name is a link that opens its checkpoints */
.models .model-toggle { appearance: none; background: none; border: 0; padding: 0; margin: 0; text-align: left; cursor: pointer; font-family: inherit; }
.models .model-toggle code { text-decoration: underline; text-decoration-style: dotted; text-decoration-color: var(--accent); text-underline-offset: 0.2em; }
.models .model-toggle:hover code, .models .model-toggle[aria-expanded="true"] code { color: var(--accent); text-decoration-style: solid; }
.models .model-toggle::after { content: "▸"; order: -1; font-size: 0.6rem; color: var(--accent); transition: transform 0.15s; }
.models .model-toggle[aria-expanded="true"]::after { content: "▾"; }
.models .model-toggle em { font-family: var(--mono); font-style: normal; font-size: 0.6rem; letter-spacing: 0.06em; color: var(--muted); margin-left: auto; }
.models .model-toggle em + b { margin-left: 10px; }
.ckpts[hidden] { display: none; }   /* the display rule below would beat the UA one */
.ckpts { list-style: none; margin: 4px 0 6px; padding: 6px 0 6px 18px; display: grid; gap: 4px; max-height: 13.5em; overflow: auto; border-left: 1px solid var(--rule); }
.ckpts .model { font-size: 0.74rem; }
.ckpts code { font-size: 0.66rem; color: var(--muted); display: flex; min-width: 0; }
/* the step is what distinguishes one checkpoint from the next, so the run name
   gives way to it rather than the other way round */
.ckpts code i { font-style: normal; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 2ch; }
.ckpts code span { white-space: nowrap; }
.ckpts b { color: var(--muted); font-size: 0.66rem; }
.ckpts a.model:hover code, .ckpts a.model:hover b { color: var(--accent); }

/* ============================================================= references */
.ref { color: inherit; text-decoration: underline; text-decoration-style: dotted; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.2em; cursor: help; }
.ref:hover, .ref.is-open { color: var(--accent); text-decoration-style: solid; }
.tip { position: absolute; z-index: 20; max-width: 30ch; padding: 10px 12px; font-size: 0.84rem; line-height: 1.4; color: var(--text); background: var(--paper); border: 1px solid var(--rule); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18); display: grid; gap: 6px; }
.tip[hidden] { display: none; }
.tip.tip-wide { max-width: 44ch; }
.tip-extra { margin: 2px 0 0; }
.tip-extra[hidden] { display: none; }
.tip-extra .models { margin: 0; }
.tip-link { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.06em; color: var(--accent); text-decoration: none; }
.tip-link:hover { text-decoration: underline; }
.tip-link::after { content: " →"; }
.hero .ref { color: inherit; }

/* =================================================================== deck */
.deck { margin: 4px 0 34px; }
.deck-scroll { position: relative; height: 396px; overflow: hidden; margin: 0; cursor: grab; touch-action: pan-y; perspective: 1100px;
  /* whatever the fan is doing at the page edge, it dissolves there rather than being sliced */
  --edge: clamp(48px, 9vw, 120px);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--edge), #000 calc(100% - var(--edge)), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--edge), #000 calc(100% - var(--edge)), transparent 100%); }
.deck-scroll.dragging { cursor: grabbing; user-select: none; }
.deck-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.card[hidden] { display: none; }   /* the .card display rule would otherwise beat the UA one */
.card { position: absolute; left: 50%; top: 34px; width: 214px; height: 318px; padding: 14px 15px; display: grid; grid-template-rows: auto auto 1fr; gap: 6px; background: color-mix(in srgb, var(--paper) 80%, var(--paper-2)); border: 1px solid var(--rule); border-radius: 8px; box-shadow: 0 12px 34px rgba(0, 0, 0, 0.26); will-change: transform, opacity; }
.card-n { display: block; font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.08em; color: var(--accent); text-decoration: none; font-weight: 500; }
.card-n:hover { text-decoration: underline; }
.card-title { margin: 2px 0 0; font-size: 0.92rem; font-weight: 600; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.card-desc { margin: 0; font-size: 0.78rem; line-height: 1.4; color: var(--muted); display: -webkit-box; -webkit-line-clamp: 10; -webkit-box-orient: vertical; overflow: hidden; }
@media (max-width: 600px) { .deck-scroll { height: 370px; } .card { width: 190px; height: 300px; } }

/* ---- the reel: squircle tiles strewn across the hero/paper divide ---- */
/* the reel gets a band of its own.  it used to hang on the hero/paper divide by
   a -5rem top margin, which put the tiles over the bottom of the brain; both
   margins are now non-negative and the band's own padding holds it clear. */
.reel-band {
  position: relative; z-index: 3;
  padding: 5.5rem 0 3rem;
}
.reel-head {
  margin: 0 auto 2rem; padding: 0 1.5rem; max-width: 1240px;
  font-family: var(--mono, monospace); font-weight: 500;
  font-size: .72rem; letter-spacing: .16em; text-transform: lowercase;
  color: #7d8b95; text-align: center;
}
.reels {
  position: relative; z-index: 3;
  margin: 0 auto; padding: 0 1.5rem;
  max-width: 1240px;
  display: flex; justify-content: center; align-items: flex-start;
  flex-wrap: wrap; gap: 2.4rem 4.5rem;
}
/* one pile per kind of picture: the tiles stack most of the way over one
   another, each a little off the line, the first on top; a hover lifts one out */
.reel {
  display: flex; flex-direction: column; align-items: center;
  pointer-events: none;
}
.pile { display: flex; align-items: flex-start; padding: 22px 0 36px; }   /* the strew drops a tile 22px */
.reel-label {
  margin: 0; font-family: var(--mono, monospace); font-size: .64rem;
  letter-spacing: .12em; text-transform: lowercase; color: #7d8b95; text-align: center;
}
.reel .tile {
  pointer-events: auto;
  position: relative; margin: 0;
  width: 150px; height: 150px; flex: 0 0 auto;
  border-radius: 30% / 30%;               /* squircle-ish */
  overflow: hidden;
  background: #0d1013;
  z-index: var(--z, 0);                    /* set per pile by site.js */
  box-shadow: 0 10px 34px rgba(0,0,0,.45), 0 0 0 1px rgba(255,255,255,.07);
  transition: transform .28s cubic-bezier(.2,.7,.3,1), box-shadow .28s;
}
.reel .tile + .tile { margin-left: -94px; }   /* stacked: ~56px of each shows */
/* every picture fills its squircle, centred: an <img> left at its natural
   aspect sat as a strip across the top and the tile read as blank */
.reel .tile video, .reel .tile img {
  width: 100%; height: 100%; object-fit: cover; object-position: center; display: block;
  transform: scale(1.06);
}
/* a diagram is mostly white page around its plots: zoom onto the middle */
.reel .tile-diagram { background: #fff; }
.reel .tile-diagram img { transform: scale(1.22); }
/* a network capture is the whole hero, labels and all: zoom onto the brain */
.reel .tile-net img { transform: scale(1.7); object-position: 50% 54%; }
/* strewn: each tile sits a little off the line */
.reel .t0 { transform: translateY(14px)  rotate(-3deg); }
.reel .t1 { transform: translateY(-16px) rotate(2.5deg); }
.reel .t2 { transform: translateY(22px)  rotate(-1.5deg); }
.reel .t3 { transform: translateY(-10px) rotate(3deg); }
.reel .t4 { transform: translateY(18px)  rotate(-2deg); }
.reel .t5 { transform: translateY(-6px)  rotate(1.5deg); }
.reel .t6 { transform: translateY(10px)  rotate(-2.5deg); }
.reel .tile:hover {
  transform: translateY(-4px) rotate(0deg) scale(1.09); z-index: 20;
  box-shadow: 0 18px 50px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.18);
}
.reel figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.4rem .8rem .7rem;
  background: linear-gradient(to top, rgba(6,8,10,.94) 30%, transparent);
  font-size: .62rem; line-height: 1.25; letter-spacing: .01em;
  opacity: 0; transition: opacity .25s;
}
.reel .tile:hover figcaption { opacity: 1; }
.reel figcaption b { display: block; color: #eaf2f6; font-weight: 600; }
.reel figcaption span { display: block; color: #9fb0ba; font-family: var(--mono, monospace); font-size: .58rem; margin-top: .18rem; }
@media (max-width: 900px) {
  .reel-band { padding: 3.5rem 0 2rem; }
  .reel-head { margin-bottom: 1.4rem; }
  .reels { gap: 1.4rem 2.5rem; margin-bottom: 1.75rem; }
  .reel .tile { width: 112px; height: 112px; }
  .reel .tile + .tile { margin-left: -72px; }
}
@media (max-width: 480px) {
  .reel .tile { width: 96px; height: 96px; }
  .reel .tile + .tile { margin-left: -64px; }   /* nine tiles fit in 336px */
}
@media (prefers-reduced-motion: reduce) {
  .reel .tile { transition: none; }
}

/* ---- lightbox: a tile fills the screen with its caption and description ---- */
.lb { position: fixed; inset: 0; z-index: 999; display: flex;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 1.2rem; padding: 3rem 2rem;
  background: rgba(4,6,8,.955); backdrop-filter: blur(14px);
  animation: lbin .18s ease-out; }
.lb[hidden] { display: none; }
@keyframes lbin { from { opacity: 0 } to { opacity: 1 } }
.lb-stage { max-width: min(1100px, 92vw); max-height: 62vh; display: flex; }
.lb-stage video, .lb-stage img {
  max-width: 100%; max-height: 62vh; width: auto; height: auto;
  border-radius: 14px; box-shadow: 0 24px 70px rgba(0,0,0,.7); background: #0d1013; }
.lb-meta { max-width: 62ch; text-align: left; }
.lb-meta h3 { margin: 0 0 .3rem; font-size: 1.02rem; color: #eaf2f6; font-weight: 600; }
.lb-cap { margin: 0 0 .55rem; font-family: var(--mono, monospace);
  font-size: .74rem; color: #7fd7c4; letter-spacing: .01em; }
.lb-desc { margin: 0; font-size: .84rem; line-height: 1.55; color: #a9bac4; }
.lb-close { position: absolute; top: 1.1rem; right: 1.4rem;
  width: 40px; height: 40px; border-radius: 50%; cursor: pointer;
  background: rgba(255,255,255,.07); color: #dfe9ee;
  border: 1px solid rgba(255,255,255,.14); font-size: 1.4rem; line-height: 1; }
.lb-close:hover { background: rgba(255,255,255,.14); }
.lb-count { margin: 0 0 .35rem; font-family: var(--mono, monospace); font-size: .66rem; color: #6d7c86; letter-spacing: .08em; }
.lb-nav { position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 64px; border-radius: 14px; cursor: pointer;
  background: rgba(255,255,255,.06); color: #dfe9ee;
  border: 1px solid rgba(255,255,255,.12); font-size: 1.7rem; line-height: 1; }
.lb-nav:hover { background: rgba(255,255,255,.14); }
.lb-prev { left: 1.1rem; }
.lb-next { right: 1.1rem; }
@media (max-width: 700px) { .lb-nav { top: auto; bottom: 1rem; transform: none; width: 52px; height: 44px; } }
.reel .tile { cursor: zoom-in; }
.reel .tile:focus-visible { outline: 2px solid #7fd7c4; outline-offset: 3px; }
@media (max-width: 700px) { .lb { padding: 2rem 1.1rem; } .lb-stage { max-height: 46vh; } }

/* the standfirst now sits between the hero and the reel rather than in the
   paper's masthead, so it needs its own band and its own rhythm. */
.standfirst-band {
  position: relative; z-index: 3;
  max-width: 72ch; margin: 0 auto; padding: 5rem 1.5rem 0;
}
.standfirst-band .standfirst { margin: 0; }
@media (max-width: 900px) {
  .standfirst-band { padding: 3rem 1.25rem 0; }
}

/* ---- the lineage bundle: vertical roads that veer in and out; each corpus in its own
        colour until it merges into the trunk's.  labels beside their road, no container ---- */
.lin-track { position: relative; width: 100%; max-width: 1000px; margin: 0 auto; }
.lin-svg { display: block; width: 100%; height: auto; overflow: visible; }
.lin-svg foreignObject { overflow: visible; }

.lin-roads { opacity: .4; }
.lin-road { stroke: none; }
.lin-planned { opacity: .6; }
.lin-road.is-future { fill: none; stroke-width: 1.3; stroke-dasharray: 6 7; }

.lin-rule { stroke: var(--rule); stroke-width: .6; opacity: .5; }
.lin-rule.is-future { stroke-dasharray: 4 6; }
.lin-stage { font-family: var(--mono); font-size: 12px; letter-spacing: .16em; text-anchor: start;
             text-transform: uppercase; fill: var(--muted); opacity: .9; }
.lin-stage.is-future { opacity: .45; }

.lin-leader { stroke: var(--muted); stroke-width: 1.2; fill: none; opacity: .55; }
.lin-dot { fill: var(--accent); }

.lin-ann-body { display: grid; gap: 2px; padding: 0; height: 100%; align-content: center;
                color: inherit; text-decoration: none; position: relative; }
.lin-ann-body.to-left { text-align: right; justify-items: end; }
.lin-ann-body.to-right { justify-items: start; }
.lin-kind { font: 400 10px/1.2 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.lin-label { font-family: var(--display); font-weight: 600; font-size: 17px; line-height: 1.15;
             letter-spacing: -.005em; }
a.lin-ann-body:hover .lin-label { color: var(--accent); }
.lin-note { font: 400 11.5px/1.35 var(--mono); color: var(--muted); }
.lin-hf { font: 400 12px/1.5 var(--mono); color: var(--text); text-decoration: none; white-space: nowrap; }
.lin-hf code { font: inherit; }
.lin-hf .hf { font-size: 13px; }
.lin-hf:hover { color: var(--accent); }
.lin-ann.is-future .lin-label, .lin-ann.is-future .lin-note { opacity: .6; }

.lin-tip { display: none; }
.lin-ann-body:hover .lin-tip, .lin-ann-body:focus-visible .lin-tip {
  display: block; position: absolute; top: 100%; width: 300px; z-index: 30;
  background: var(--paper-2); border: 1px solid var(--rule); border-radius: 6px;
  padding: .6rem .75rem; font: 400 12px/1.45 var(--serif); text-align: left; color: var(--text);
  box-shadow: 0 10px 28px rgba(0,0,0,.2);
}
.lin-ann-body.to-left:hover .lin-tip { right: 0; }
.lin-ann-body.to-right:hover .lin-tip { left: 0; }

@media (max-width: 760px) {
  .lin-label { font-size: 14px; } .lin-note, .lin-hf { font-size: 10px; }
  .lin-tip { width: 210px; }
}

/* =====================================================================
   the spine layout.  no section numbers, no rules, no dividers: a heading
   is the only separator, and the growing trunk on the left carries the
   sense of progression.  see spine.js for why it is not a timeline.
   ===================================================================== */

/* the paper wash is FULL-BLEED and fades in from the standfirst.  constraining it
   to the content width -- which is what max-width here used to do -- turned it into
   an opaque rectangle sitting on top of the animated background, with four hard
   edges.  the width belongs on the content, never on the wash. */
.paper { max-width: none; margin: 0; padding: 0 0 40px;
  background: linear-gradient(to bottom, transparent 0,
    color-mix(in srgb, var(--paper) 86%, transparent) 260px); }
.spine-band { max-width: 1280px; margin-left: auto; margin-right: auto;
  padding-left: clamp(18px, 4vw, 48px); padding-right: clamp(18px, 4vw, 48px); }

/* longhands: a `padding` SHORTHAND here silently reset the padding-left set above,
   which left the band flush and the try-it column 48px inboard of it. */
.spine-band { display: grid; grid-template-columns: 304px minmax(0, 1fr); gap: 34px;
  padding-top: 70px; padding-bottom: 40px; }
.spine-rail { position: relative; grid-column: 1; width: 304px; }
.spine-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible;
  opacity: 0; transition: opacity .6s; }
.spine-rail.is-ready .spine-svg { opacity: 1; }
/* ONE opacity, on the group.  every road inside is fully opaque, so a ribbon crossing
   the trunk composites to exactly the trunk's colour and no seam appears. */
.spine-roads { opacity: .62; }
.spine-trunk, .spine-feed, .spine-tap { stroke: none; }
.spine-trunk { fill: var(--accent); }
.spine-tap { fill: var(--accent); }
.spine-label { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; text-anchor: end; fill: var(--muted); }
/* the corpus that fuses in here, named and linked.  right-aligned against its ribbon
   and free to take a second line, which is what lets it carry a dataset accession
   rather than a modality. */
.spine-svg foreignObject { overflow: visible; }
.spine-inlbl { font-family: var(--mono); font-size: 9.5px; letter-spacing: .08em;
  line-height: 1.3; text-transform: uppercase; text-align: right; color: var(--muted); }
.spine-inlbl a { color: var(--muted); text-decoration: none;
  border-bottom: 1px solid var(--rule); }
.spine-inlbl a:hover { color: var(--accent); border-bottom-color: var(--accent); }

.spine-flow { grid-column: 2; display: grid; gap: 132px; min-width: 0; }

/* a station.  the heading IS the divider -- no rule, no number, no eyebrow */
.station { display: grid; grid-template-columns: minmax(0, 1.04fr) minmax(0, 0.96fr);
  gap: 40px; align-items: start; }
.station > .st-text { min-width: 0; display: grid; gap: 14px; align-content: start; }
.station h2 { margin: 0; font-family: var(--display); font-weight: 600;
  font-variation-settings: "opsz" 48; font-size: clamp(25px, 2.7vw, 37px); line-height: 1.08;
  letter-spacing: -0.022em; text-wrap: balance; }
.station h2 em { font-style: italic; font-weight: 400; }
.station.is-declared h2 { color: var(--muted); }
.st-lede { margin: 0; font-size: 1.02rem; line-height: 1.55; max-width: 54ch; color: var(--muted); }
.st-design .display-math { margin: 6px 0 0 !important; font-size: 1.35rem; }

.st-figs { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 14px; }
/* 15ch, not 13: "48.4x -> 1.00x" wrapped mid-arrow at 13 */
.st-figs li { display: grid; grid-template-columns: 15ch minmax(0, 1fr); gap: 4px 20px; align-items: baseline; }
.st-figs > li > b { font-family: var(--display); font-weight: 600; font-variation-settings: "opsz" 40;
  font-size: 1.3rem; line-height: 1.1; letter-spacing: -0.015em; color: var(--accent);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.st-figs span { font-size: 0.9rem; line-height: 1.45; color: var(--muted); }
.st-figs span b { font-family: inherit; font-size: inherit; color: var(--text); font-weight: 600; }

.st-control { margin: 2px 0 0; font-size: 0.88rem; line-height: 1.5; color: var(--muted); max-width: 56ch; }
.st-control b { color: var(--text); font-weight: 600; }
.st-declared { margin: 0; font-size: 0.92rem; line-height: 1.55; color: var(--muted); max-width: 58ch; }
.st-declared b { color: var(--fail); font-weight: 600; }

.st-media { min-width: 0; position: sticky; top: 30px; }
.st-media figure { margin: 0; }
.st-media img, .st-media video { width: 100%; height: auto; display: block; border-radius: 3px; }
.st-pile { display: grid; gap: 14px; }
.st-media figcaption { margin-top: 10px; font-size: 0.8rem; line-height: 1.45; color: var(--muted); }
.st-media .tile { cursor: pointer; }

/* ---- filler: unmeasured placeholders, unmistakably red --------------- */
.filler { color: var(--fail) !important; }
.st-figs.is-filler > li > b.filler { text-decoration: line-through; text-decoration-thickness: 1px; opacity: .8; }
.st-figs span b.filler-chip, .filler-chip { display: inline-block; font-family: var(--mono); font-size: 0.56rem; font-weight: 400;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--fail); border: 1px solid currentColor;
  border-radius: 2px; padding: 2px 6px; margin-left: 4px; white-space: nowrap; vertical-align: 1px; }

/* ---- try it ---------------------------------------------------------- */
.try { padding-top: 40px; padding-bottom: 110px; }
.try h2 { margin: 0 0 20px; font-family: var(--display); font-weight: 600;
  font-variation-settings: "opsz" 60; font-size: clamp(30px, 3.4vw, 46px); line-height: 1;
  letter-spacing: -0.025em; }
.code { margin: 0 0 20px; padding: 20px 22px; background: var(--paper-2); border-radius: 4px;
  overflow-x: auto; max-width: 74ch; }
.code code { display: block; background: none; padding: 0; font-size: 0.79rem; line-height: 1.75;
  white-space: pre; color: var(--text); }
.code .c { color: var(--muted); }
.try-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin: 0; }
.btn { display: inline-block; font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.08em;
  text-decoration: none; color: var(--paper); background: var(--accent); padding: 10px 17px;
  border-radius: 3px; border: 1px solid var(--accent); transition: opacity .15s; }
.btn:hover { opacity: .85; color: var(--paper); }
.btn-quiet { background: none; color: var(--muted); border-color: var(--rule); }
.btn-quiet:hover { color: var(--accent); border-color: var(--accent); }

@media (max-width: 1080px) {
  /* the rail cannot survive one column: it degrades to nothing rather than to a
     stripe implying an order it is no longer showing */
  .spine-band, .try { padding-left: 22px; padding-right: 22px; }
  .try { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .try > *, .try-inner > * { grid-column: 1; }
  .spine-band { grid-template-columns: minmax(0, 1fr); gap: 0;
    padding-top: 40px; padding-bottom: 20px; }
  .spine-rail { display: none; }
  .spine-flow { grid-column: 1; gap: 78px; }
  .station { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .st-media { position: static; }
  .st-figs li { grid-template-columns: minmax(0, 1fr); gap: 3px; }
}

/* the visual-pathway view needs more vertical room than a landscape snap: the
   retina sits well forward of the occipital port and both must be in frame */
.snap-tall canvas { min-height: 380px; }

/* the before/after spectrum figure */
.spectra-fig { margin: 0; }
.spectra-svg { display: block; width: 100%; height: auto; }
.sp-band { fill: var(--accent); opacity: .08; }
.sp-bandlabel { font-family: var(--mono); font-size: 9px; letter-spacing: .14em;
  text-transform: uppercase; text-anchor: middle; fill: var(--muted); opacity: .9; }
.sp-grid { stroke: var(--rule); stroke-width: .7; opacity: .5; }
.sp-tick { font-family: var(--mono); font-size: 10px; text-anchor: middle; fill: var(--muted); }
.sp-axis { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; text-anchor: middle; fill: var(--muted); opacity: .8; }
.sp-before { fill: none; stroke: var(--muted); stroke-width: 1.6; opacity: .75; }
.sp-after { fill: none; stroke: var(--accent); stroke-width: 2.1; }
.sp-dot-before { fill: var(--muted); }
.sp-dot-after { fill: var(--accent); }
.sp-keytext { font-family: var(--mono); font-size: 10px; fill: var(--muted); }

/* the whole-body figure.

   NOTE, because the rule directly below does the opposite: this canvas is deliberately NOT
   masked at its rim.  the figure stands in a patch of grass whose own alpha falls to zero
   before its geometry ends, so the feather is in the material and the page shows through it
   in either theme.  a CSS mask here would feather the FEET along with the grass, which is
   the one part of this figure that has to stay crisp -- it is where the body meets the
   ground.  the treatment room below is a box and has no such surface, so it is masked. */
.body-fig { margin: 0; }
#body3d { width: 100%; min-height: 360px; cursor: grab; opacity: 0; transition: opacity .7s; }
#body3d.is-ready { opacity: 1; }
#body3d:active { cursor: grabbing; }
#body3d canvas { display: block; width: 100%; height: auto; }
/* the figure is the widest thing in the column and the caption under it is the narrowest;
   holding it to the prose measure stops a one-line label spanning the whole media column */
.body-fig figcaption { max-width: 46ch; }

/* the cobot + head stimulation figure, now set in a treatment room.

   the room is a box with four hard edges, and a box with hard edges sitting on a page is a
   screenshot rather than a figure.  the canvas is therefore masked away at its rim: a
   radial gradient rounds the corners off, and a feather on each of the four sides keeps
   the middle of every edge square, which together is the squircle -- a plain ellipse
   pinched the floor in at the sides and the room stopped looking rectangular.
   `mask-composite: intersect` is what makes it an AND of the three; without it the default
   `add` unions them, and the figure simply keeps its old hard edge rather than breaking. */
.tms-fig { margin: 0; }
#tms3d { width: 100%; min-height: 300px; cursor: grab; opacity: 0; transition: opacity .7s; }
#tms3d.is-ready { opacity: 1; }
#tms3d:active { cursor: grabbing; }
#tms3d canvas {
  display: block; width: 100%; height: auto;
  --feather:
    radial-gradient(138% 132% at 50% 46%, #000 0 64%, rgba(0,0,0,.88) 85%, transparent 100%),
    linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 4%, #000 93%, transparent 100%);
  -webkit-mask-image: var(--feather);
  mask-image: var(--feather);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* the THINGS retrieval panel: the round trip the station's two figures score --
   stimulus, a named arrow, the measured response, a second named arrow, and the model's
   top five out of 200.  the ranking is the evidence, so it gets the width.

   the row is sized on content and on @container queries, never on @media, because this
   panel's width has not tracked the viewport's.  when it sat in the station's right
   column it was 387px at a 1400px viewport and 856px at 900px -- WIDER as the window
   narrowed -- and the grid it replaced gave `auto` to the candidates and left .rt-mid
   ONE PIXEL wide at 1400, so the waveform was simply not drawn at the width most readers
   use.  the station is now st-full (the row was asked not to wrap, and 387px could only
   wrap), so the panel is 846px at 1500, 674px at 1100, 856px at 900 and 556px at 600;
   the queries below are keyed to those, measured, not to the old column.

   the fold order is deliberate: .rt-step keeps each arrow WITH the artefact it points
   at, so a row that cannot hold five things in a line breaks into
   [seen -> response] / [-> ranking] and never into an arrow orphaned from its target. */
#retrieval { opacity: 0; transition: opacity .6s; margin-bottom: 26px;
  container-type: inline-size; }
#retrieval.is-ready { opacity: 1; }

/* the sliding window.  its height is set by retrieval.js from the MEASURED rows (3.5 of
   them on one line, 2.5 when they fold), so nothing here assumes a row height.
   overflow is CLIP, not hidden: a hidden box can still be scrolled -- the browser does it
   itself to reveal a focused link -- and a scrollTop underneath the transform would
   silently offset every position the loop computes.  clip cannot be scrolled at all.
   the fade is a mask, so rows enter and leave softly instead of being cut at a hard edge;
   nothing is positioned over this box, so the stacking context a mask creates (see
   CLAUDE.md, "The site") has nothing to paint over. */
.rt-window { position: relative; overflow: clip; --rt-fade: 34px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--rt-fade),
    #000 calc(100% - var(--rt-fade)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--rt-fade),
    #000 calc(100% - var(--rt-fade)), transparent 100%); }
/* column-reverse on BOTH levels: the aria-hidden copy sits on top and each copy runs
   newest-first visually, while the DOM stays in dataset order for readers and tab order.
   position:relative makes the track every row's offsetParent, which is what the loop
   measures against. */
.rt-track { position: relative; display: flex; flex-direction: column-reverse;
  will-change: transform; padding-bottom: var(--rt-fade); }
.rt-copy { display: flex; flex-direction: column-reverse; }
.rt-window.is-static { -webkit-mask-image: none; mask-image: none; }
.rt-window.is-static .rt-track { flex-direction: column; will-change: auto; padding-bottom: 0; }
.rt-head { margin: 0 0 14px; font-size: .78rem; line-height: 1.55; color: var(--muted); max-width: 58ch; }
.rt-head b { color: var(--accent); font-weight: 600; }

.rt-row { display: flex; flex-wrap: wrap; align-items: center; gap: 11px 12px;
  padding: 13px 0; border-top: 1px solid var(--rule); }
/* the basis is stated, not left at `auto`.  `auto` resolves to the step's MAX-content --
   both children at their caps, 402px for the first step -- so the row folded while 90px
   of it was still empty, and then the candidates ran off the right edge because
   `min-width: 0` let the step shrink under its own contents.  the numbers below are the
   children's bases plus the gap; keep them in step with .rt-leg / .rt-mid / .rt-out.
   min-width stays at its `auto` default so a step can never be narrower than it fits in.
   these are the NARROW-panel numbers; the container query below raises them in lockstep
   with .rt-leg's min-width, and a step basis left behind is how the 700px viewport ended
   up with both arrows stacked over their targets instead of beside them. */
.rt-step { display: flex; flex-wrap: wrap; align-items: center; gap: 11px 12px;
  flex: 1 1 208px; }
.rt-step-out { flex: 3 1 332px; }

.rt-seen { margin: 0; flex: 0 0 auto; }
.rt-seen img { width: 74px; height: 74px; object-fit: cover; border-radius: 3px; display: block; }
.rt-seen figcaption { margin-top: 5px; font-family: var(--mono); font-size: .58rem;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted); line-height: 1.25;
  width: 74px; }

/* an arrow with the model's name over it -- the materialization figure's .mz-mark.is-name
   register, in document flow rather than over a canvas.  the shaft is drawn in CSS and not
   as an SVG because it has to stretch from ~84px to the full row width without the head
   stretching with it. */
/* the basis is small and the cap is generous on purpose: flex line-breaking happens on
   the BASIS, before any shrinking, so a fat basis folds the row earlier than it needs to,
   and an uncapped grow turns the arrow into the widest thing in the row on a line it has
   to itself.  the cap is loose (340) because the alternative at a mid width is 90px of
   dead space at the end of the line: a long arrow reads as a long arrow, a gap reads as a
   bug. */
.rt-leg { position: relative; flex: 1 1 84px; min-width: 80px; max-width: 340px;
  display: grid; gap: 4px; text-align: center; }
.rt-leg b { font-family: var(--display); font-weight: 600; font-size: 11px;
  line-height: 1.15; color: var(--text); }
/* a model name broken at one of its own hyphens -- "IBM-1-EEG-to- / Image" -- reads as two
   names, so it is kept on one line wherever the panel can spare the width.  the query is
   on the PANEL, not the viewport, for the reason given at the top of this block.
   the min-width rises with it: a nowrap name in an 86px box does not clip, it PAINTS OVER
   the trace beside it, which is the failure this rule would otherwise introduce. */
@container (min-width: 360px) {
  .rt-leg { min-width: 112px; }
  .rt-leg b { white-space: nowrap; }
  .rt-step { flex-basis: 236px; }      /* 112 + 12 + .rt-mid's 112 */
  .rt-step-out { flex-basis: 360px; }  /* 112 + 12 + .rt-out's 236 */
}
/* ONE LINE, NO WRAP, wherever it can be done without starving the candidates -- the
   request was that this row not fold.  the station went full-width for it (st-full), so
   the panel is now ~846px at 1500 and ~674px at 1100.  the tightest single line is
   60 (stimulus) + 2 x 112 (names, 110.6px measured at 11px) + 80 (trace) + 234 (five
   42px thumbnails) + gaps = ~640, so the switch sits at 660 and 1100 is on the right
   side of it; below, the wrap rules above take over.

   .rt-step becomes display:contents so all five pieces are siblings in ONE flex line and
   each gets its own shrink: nested, the shrink was shared out by the steps' bases and the
   thumbnails lost to the trace.  the trace gives way first (shrink 3, floor 80px), the
   candidates last (shrink .5, floor 42px each), the names never.  the stimulus and the
   gaps scale with the panel in container units, which buys the thumbnails ~20px at 1100. */
/* every selector carries #retrieval: a @container block adds NO specificity, and the
   .rt-mid / .rt-out base rules sit further down this file, so unprefixed these lost on
   source order and the trace kept its wrap-mode basis -- 42px thumbnails at 1100. */
@container (min-width: 660px) {
  #retrieval .rt-row { flex-wrap: nowrap; gap: 0 clamp(10px, 1.6cqi, 16px);
    --rt-seen: clamp(60px, 9cqi, 74px); }
  #retrieval .rt-step { display: contents; }
  #retrieval .rt-seen img { width: var(--rt-seen); height: var(--rt-seen); }
  #retrieval .rt-seen figcaption { width: var(--rt-seen); }
  #retrieval .rt-mid { flex: 1 3 150px; min-width: 80px; }
  #retrieval .rt-out { flex: 0 .5 284px; min-width: 234px; }
}
.rt-leg a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule); }
.rt-leg a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.rt-shaft { position: relative; display: block; height: 1.5px; background: currentColor;
  margin-right: 5px; }
.rt-shaft::after { content: ""; position: absolute; right: -5px; top: 50%;
  transform: translateY(-50%); border-left: 6px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
/* the two directions take the opener's two route colours: into the brain, and out of it */
.rt-leg-in { color: var(--fig-in); }
.rt-leg-out { color: var(--fig-out); }

/* the arrows carry meaning, so they carry text; only the glyph itself is hidden */
.rt-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* the trace keeps its 150x66 aspect, so growing it wide also grows it TALL: past ~190px
   it towers over the 74px stimulus beside it and stops reading as a row. */
.rt-mid { margin: 0; flex: 1 1 112px; min-width: 96px; max-width: 190px;
  display: grid; justify-items: center; gap: 3px; }
.rt-eeg { width: 100%; height: auto; }
.rt-eeg path { fill: none; stroke: var(--muted); stroke-width: .7; opacity: .75; }
/* the trace is a RECORDING, and it sits under an arrow named for a model.  the caption is
   what stops the row being read as "the model drew this waveform". */
.rt-mid figcaption { font-family: var(--mono); font-size: .5rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted); text-align: center; }
/* on the single line at ~1100 the trace is ~83px and the caption must fold; the spans make
   it fold at the separator ("measured · / 8 ch shown") instead of stranding "shown" */
.rt-mid figcaption span { white-space: nowrap; }

/* grow 3 against the arrow's 1: the ranking is the evidence, so when a line has slack the
   candidates take most of it and stay at their full 52px rather than the arrow doing so */
.rt-out { display: grid; gap: 7px; justify-items: start; flex: 3 1 236px; min-width: 236px; }
.rt-top5 { list-style: none; margin: 0; padding: 0; display: flex; gap: 6px; width: 100%; }
/* the thumbnails shrink to a floor of 42px and then the whole .rt-step wraps instead:
   degrading to a readable smaller picture beats squeezing five of them into nothing */
.rt-top5 li { flex: 0 1 52px; min-width: 42px; display: grid; gap: 3px; justify-items: center; }
.rt-top5 img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 3px;
  display: block; border: 2px solid transparent; opacity: .55; }
.rt-top5 span { font-family: var(--mono); font-size: .5rem; letter-spacing: .04em; color: var(--muted);
  text-align: center; line-height: 1.2; overflow-wrap: anywhere; }
/* the true image is marked by a border AND full opacity AND the rank line below -- never
   by hue alone, and its name is spelled out for a screen reader in .rt-sr */
.rt-top5 li.is-true img { border-color: var(--accent); opacity: 1; }
.rt-top5 li.is-true span { color: var(--text); }
.rt-rank { margin: 0; font-family: var(--mono); font-size: .58rem; letter-spacing: .1em;
  text-transform: uppercase; }
.rt-rank.is-hit { color: var(--moved); }
.rt-rank.is-miss { color: var(--half); }

/* two figures that carry the whole claim, so they get the size */
.st-big { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 14px 44px; }
.st-big li { display: grid; gap: 2px; }
.st-big b { font-family: var(--display); font-weight: 600; font-variation-settings: "opsz" 60;
  font-size: clamp(42px, 5vw, 66px); line-height: 0.95; letter-spacing: -0.035em;
  color: var(--accent); font-variant-numeric: tabular-nums; }
.st-big b i { font-style: normal; font-size: 0.5em; letter-spacing: -0.01em; margin-left: 0.04em; }
.st-big span { font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); }

.st-media-wide { position: static; }
.st-cap { display: block; margin-top: 10px; font-size: 0.8rem; line-height: 1.45; color: var(--muted); }

/* ---- Try It: a notebook, because that is where this actually gets run ---- */
/* the try-it column uses the SAME grid as the spine band, so its content lines up with
   the station text rather than with the page edge.  offsetting each child by hand did not
   work: `.try h2` sets its own margin and is more specific, so the heading stayed left
   while the notebook moved. */
/* structurally IDENTICAL to .spine-band -- same max-width, same padding, same two
   columns, same gap -- because anything else lands a few tens of pixels off and the
   misalignment is exactly the kind the eye catches without being able to name. */
.try { max-width: 1280px; margin: 0 auto;
  padding: 30px clamp(18px, 4vw, 48px) 110px;
  display: grid; grid-template-columns: 304px minmax(0, 1fr); gap: 34px; }
.try-inner { display: contents; }
.try > *, .try-inner > * { grid-column: 2; }
/* THE PHONE RULE HAS TO COME AFTER THE DESKTOP ONE.  the 1080px media query near the top
   of this file sets one column and `grid-column: 1`, but these two desktop rules come later
   with the same specificity, so they won at every width: on a phone the notebook sat in
   column 2 of a one-column grid -- an implicit second column 300px off the right edge -- and
   the whole page scrolled sideways (documentElement 477px wide in a 390px viewport).  a media
   query does not raise specificity; only source order was deciding it. */
@media (max-width: 1080px) {
  .try { grid-template-columns: minmax(0, 1fr); gap: 0;
    padding-left: 18px; padding-right: 18px; }
  .try > *, .try-inner > * { grid-column: 1; }
  .nb { max-width: 100%; }
  .nb-code, .nb-out { max-width: 100%; }
}
/* a phone: code a size smaller so most lines fit, and what does not SCROLLS inside its own
   cell (overflow-x on .nb-code / .nb-out) instead of widening the page */
@media (max-width: 600px) {
  .nb-code code { font-size: .68rem; line-height: 1.6; }
  .nb-out { font-size: .64rem; }
  .nb-cell { grid-template-columns: 34px minmax(0, 1fr); }
}
.nb { max-width: 760px; border: 1px solid var(--rule); border-radius: 6px; overflow: hidden;
  background: var(--paper-2); }
.nb-bar { display: flex; align-items: center; gap: 6px; padding: 9px 13px;
  border-bottom: 1px solid var(--rule); background: color-mix(in srgb, var(--paper) 55%, var(--paper-2)); }
.nb-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--rule); }
.nb-name { margin-left: 8px; font-family: var(--mono); font-size: .66rem; color: var(--muted); }
.nb-cell { display: grid; grid-template-columns: 46px minmax(0, 1fr); align-items: start;
  border-bottom: 1px solid var(--rule); }
.nb-cell:last-child { border-bottom: 0; }
.nb-gutter { padding: 14px 0 0; font-family: var(--mono); font-size: .62rem; color: var(--accent);
  opacity: .7; text-align: center; user-select: none; }
.nb-code { margin: 0; padding: 13px 16px 13px 0; overflow-x: auto; }
.nb-code code { display: block; background: none; padding: 0; white-space: pre;
  font-family: var(--mono); font-size: .78rem; line-height: 1.7; color: var(--text); }
.nb-out { margin: 0; padding: 0 16px 14px 0; grid-column: 2; font-family: var(--mono);
  font-size: .72rem; line-height: 1.6; color: var(--muted); white-space: pre; overflow-x: auto;
  border-left: 2px solid var(--accent-soft); padding-left: 12px; }
.nb-code .kw { color: var(--lane-3); }
.nb-code .fn { color: var(--lane-2); }
.nb-code .str { color: var(--lane-4); }
.nb-code .bool { color: var(--lane-1); }
.nb-code .cm { color: var(--muted); font-style: italic; }
.try .try-cta { margin-top: 22px; }



/* the stimulation figure's one line of text, UNDER the render: "target: <site> · <band>".
   it replaced a frosted card inside the frame at the user's request -- one line, nothing else.
   (the label layer and its z-index are gone with it; the trap that z-index answered is in
   CLAUDE.md under "The site".) */
#tms3d { position: relative; }
.tms-target { margin: 8px 0 0; font-family: var(--mono); font-size: 0.7rem; letter-spacing: .06em;
  color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* the stimulation station carries the only visualisation for its whole subject, so it
   gets the width the two it replaced used to have between them */
.station.st-wide { grid-template-columns: minmax(0, 0.76fr) minmax(0, 1.24fr); }
@media (max-width: 1080px) { .station.st-wide { grid-template-columns: minmax(0, 1fr); } }

/* ---- the materialization diagram: one scene, four brains ---- */
.station.st-full { grid-template-columns: minmax(0, 1fr); gap: 26px; }
.station.st-full .st-text { max-width: 62ch; }

/* ---- resonance tiles: naked vstacks, no card chrome ------------------ */
/* each tile is {pulsing brain, name, paragraph} and nothing else -- no
   border, no panel, no shadow, no hover lift, and (at the user's request) no
   visible status line: measured/declared lives in data-status on each article
   and in the comment above the section.  the grid is auto-fit rather
   than a literal five-across row: the flow column is 846px here, so five in a
   row would give each brain ~150px, smaller than the thalamus it has to show. */
.rz-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 34px 26px; margin: 10px 0 0; align-items: start; }
.rz-tile { display: grid; gap: 7px; align-content: start; min-width: 0;
  background: none; border: 0; box-shadow: none; padding: 0; }
.rz-tile > .rz-snap { margin: 0 0 3px; }
.rz-snap .snap-labels { display: none; }   /* no leaders or labels at this size */
.rz-tile h3 { margin: 0; font-family: var(--display); font-weight: 600;
  font-variation-settings: "opsz" 24; font-size: 1.04rem; line-height: 1.2;
  letter-spacing: -0.012em; text-wrap: balance; }
.rz-say { margin: 0; font-size: 0.86rem; line-height: 1.5; color: var(--muted); }
/* the one measured tile carries its numbers under its paragraph, stacked:
   .st-figs' 15ch label column does not fit in a tile this narrow */
.rz-figs { margin: 7px 0 0; gap: 10px; }
.rz-figs li { grid-template-columns: minmax(0, 1fr); gap: 2px; }
.rz-figs > li > b { font-size: 1.12rem; }
.rz-figs span { font-size: 0.8rem; line-height: 1.45; }
.rz-foot { margin: 28px 0 0; font-size: 0.82rem; line-height: 1.5; color: var(--muted); max-width: 74ch; }
/* the measured tile is the only one carrying numbers, so it is half again as tall as the
   rest.  spanning it down two rows was the first fix and it is worse: a grid row is as
   tall as its tallest item, so the tile ended a long way above the bottom of the two rows
   it had claimed and left a column of white in the MIDDLE of the figure.  a ragged last
   row is the normal shape of five things in a three-column grid, and the empty cell is at
   the end where nobody reads it as a mistake.
   that empty sixth cell is now the "more" button, so five tiles plus it fill
   3 x 2 exactly, and eleven plus it fill 4 x 3 when it is open. */
@media (min-width: 760px) {
  .rz-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 600px) { .rz-grid { grid-template-columns: minmax(0, 1fr); gap: 30px; } }

/* the six extra tiles are wrapped so one `hidden` toggles them, and the
   wrapper is display: contents so its tiles are still items of .rz-grid.
   [hidden] must win over that, hence the explicit pair. */
.rz-extra:not([hidden]) { display: contents; }
.rz-extra[hidden] { display: none; }

/* The "more" button was removed when all eleven tiles were made to show at once,
   and its four rule bodies were left behind WITHOUT their selectors.  CSS error
   recovery then swallowed everything up to the next `{`, which ate the base
   `.rz-grid.is-all` rule: the grid was computing gap 34px 26px, inherited from
   `.rz-grid`, instead of its declared 28px 20px.  Nothing looked broken, because a
   grid with the wrong gap is still a grid. */

/* open: eleven tiles and the button, packed denser and set smaller */
.rz-grid.is-all { gap: 28px 20px; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
@media (min-width: 760px) { .rz-grid.is-all { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 600px) { .rz-grid.is-all { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 14px; } }
.rz-grid.is-all .rz-tile { gap: 5px; }
.rz-grid.is-all .rz-tile h3 { font-size: 0.9rem; }
.rz-grid.is-all .rz-say { font-size: 0.78rem; line-height: 1.45; }
.rz-grid.is-all .rz-figs > li > b { font-size: 0.98rem; }
.rz-grid.is-all .rz-figs span { font-size: 0.74rem; }
/* one column: a full-width figure-sized blank for the button would be a
   screen of nothing on a phone */

.mz { position: relative; width: 100%; max-width: 1000px; opacity: 0; transition: opacity .7s; }
.mz.is-ready { opacity: 1; }
.mz-canvas { width: 100%; cursor: grab; }
/* each brain turns on its own axis, so the affordance is per-brain, not per-scene */
.mz-canvas:active { cursor: grabbing; }
.mz-canvas canvas { display: block; width: 100%; height: auto; }

.mz-labels { position: absolute; inset: 0; pointer-events: none; }
.mz-mark { position: absolute; top: 0; left: 0; transform-origin: 0 0; white-space: nowrap;
  transition: opacity .3s; display: grid; gap: 1px; }
.mz-mark b { font-family: var(--display); font-weight: 600; font-size: 11.5px; color: var(--text); }
.mz-mark span { font-family: var(--mono); font-size: 7.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); }

/* every mark is anchored by materialize.js's own translate(), never by a margin: the
   anchor side is what lets it clamp a label back inside the canvas instead of letting
   a long model name run off the edge. */
/* the wordmark and each model's name both sit ON the thing they name -- the hub's crown,
   the lane's arrow -- so both need a halo to stay legible over a point cloud.  a
   text-shadow in the PAGE's own colour, not a panel: a panel behind either of them would
   punch a hole in the brain it is sitting on. */
.mz-mark.is-hub, .mz-mark.is-name { text-align: center; }
.mz-mark.is-hub b { font-size: 21px; color: var(--accent);
  text-shadow: 0 0 9px var(--paper), 0 0 4px var(--paper), 0 0 2px var(--paper); }
.mz-mark.is-name b { font-size: 12.5px;
  text-shadow: 0 0 7px var(--paper), 0 0 3px var(--paper), 0 0 2px var(--paper); }

/* inputs and outputs take the same two colours as the traced route in the opener.
   the side a port sits on IS its direction -- it carries no "in"/"out" tag -- and now the
   strand leaving it is its rule too, so the bar each label used to carry was a second line
   saying the same thing a few pixels from the first.  the halo is what lets the
   materialization thread run behind a label without cutting its text. */
.mz-mark.is-in { padding-right: 5px; text-align: right; }
.mz-mark.is-out { padding-left: 5px; }
.mz-mark.is-in b, .mz-mark.is-out b { font-size: 10.5px;
  text-shadow: 0 0 5px var(--paper), 0 0 2px var(--paper); }
.mz-mark.is-in b { color: var(--fig-in); }
.mz-mark.is-out b { color: var(--fig-out); }
/* variable names ride the implicit brain and fade by which way their site faces, so their
   opacity is set per frame by materialize.js -- a CSS opacity here would multiply it */
.mz-mark.is-var { font-family: var(--mono); font-size: 6.5px; letter-spacing: .03em;
  color: var(--accent); transition: none;
  text-shadow: 0 0 5px var(--paper), 0 0 2px var(--paper), 0 0 1px var(--paper); }

/* set by materialize.js from the CANVAS's own width, not the viewport's */
.mz.is-tight .mz-mark b { font-size: 9.5px; }
.mz.is-tight .mz-mark.is-name b { font-size: 10.5px; }
.mz.is-tight .mz-mark.is-hub b { font-size: 16px; }
.mz.is-tight .mz-mark.is-var { font-size: 6.5px; }

@media (max-width: 1000px) {
  .mz-mark.is-var { display: none; }
}

/* rail labels sit outside the roads group, so they keep full contrast and their links
   stay clickable through the mask */
.spine-labels { pointer-events: auto; }
.spine-tap.is-wip { opacity: .35; }
/* one block per splinter point, one line per model that leaves there.  8.5px and
   free to wrap: "IBM-1-AV-MEG-Predictor (93.7M)" does not fit the rail on one line and
   the alternative -- widening the rail again -- comes out of the prose. */
.spine-outlbl { font-family: var(--mono); font-size: 8.5px; letter-spacing: .04em;
  line-height: 1.3; display: grid; gap: 5px; }
.spine-outlbl a, .spine-outlbl > span { display: block; color: var(--accent); text-decoration: none; }
.spine-outlbl a:hover { text-decoration: underline; }
.spine-outlbl > span { color: var(--muted); }
.spine-outlbl b { font-weight: 400; color: var(--muted); }
.spine-outlbl .hf { margin-right: 2px; font-size: 9px; }
.spine-outlbl i { font-style: normal; opacity: .75; }

/* ---- the rhythm catalogue, under the resonance tiles ------------------
   rhythmtable.js builds every row from data/rhythms.js; nothing here assumes a
   row count, a loop count or a column's contents.

   THE ROW FOLDS ON THE TABLE'S OWN WIDTH, NOT THE VIEWPORT'S.  this element
   lives inside a station, and a station's columns have gone the other way from
   the window before now -- the retrieval panel was 387px at a 1400px viewport
   and 856px at 900px, so an @media breakpoint unfolded it exactly where it had
   least room (CLAUDE.md, "The site").  the BASE rules below are the narrow,
   stacked ones -- name, then band and peak, then states -- and the single
   @container query opens them into columns when the table itself is wide
   enough.  a browser with no container-query support keeps the stacked block,
   which is the case that has to be readable anyway.  there is no @media rule in
   this block at all, so there is no desktop rule that can outrank a mobile one
   on source order. */
.rzt { margin: 34px 0 0; container-type: inline-size; }
.rzt-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* the two filters.  both are pure DOM -- they set [hidden] on rows and on loop
   sections that lose all of theirs -- so nothing is rebuilt and no state is lost. */
.rzt-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 10px 16px; margin: 0 0 16px; }
.rzt-chips { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.rzt-chip { display: inline-flex; align-items: baseline; gap: 6px; cursor: pointer;
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); background: none; border: 1px solid var(--rule); border-radius: 2px;
  padding: 5px 9px; transition: color .15s, border-color .15s, background-color .15s; }
.rzt-chip i { font-style: normal; font-size: 0.9em; opacity: .6; font-variant-numeric: tabular-nums; }
.rzt-chip:hover { color: var(--text); border-color: var(--muted); }
.rzt-chip.is-on { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.rzt-find { display: flex; align-items: center; min-width: 0; }
.rzt-q { font-family: var(--mono); font-size: 0.7rem; color: var(--text); background: var(--paper-2);
  border: 1px solid var(--rule); border-radius: 2px; padding: 6px 9px; width: 15rem; max-width: 100%; }
.rzt-q::placeholder { color: var(--muted); }

/* the column head repeats the summary's columns minus the marker cell, and pays
   for the marker with padding instead -- 1.15rem + the 12px gap -- so the two
   grids resolve to the same track widths without the head carrying a blank span. */
.rzt-colhead { display: none; grid-template-columns: minmax(0, 1.7fr) 7.4rem 5.2rem minmax(0, 1.6fr);
  gap: 0 12px; padding: 0 0 7px calc(1.15rem + 12px);
  font-family: var(--mono); font-size: 0.56rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted); }

.rzt-loop { padding: 13px 0 4px; border-top: 1px solid var(--rule); }
.rzt-lh { margin: 0 0 3px; font-weight: 400; font-size: inherit;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 10px; }
.rzt-lname { font-family: var(--display); font-weight: 600; font-variation-settings: "opsz" 24;
  font-size: 0.92rem; line-height: 1.25; letter-spacing: -0.012em; color: var(--text); }
/* the ring is the loop's claim -- which structures, in which order -- so it is
   set small but never truncated: it wraps, and a station whose name is longer
   than the column breaks inside itself rather than pushing the page sideways. */
.rzt-ring { font-family: var(--mono); font-size: 0.57rem; letter-spacing: 0.05em;
  line-height: 1.5; text-transform: uppercase; color: var(--muted); overflow-wrap: anywhere; min-width: 0; }
.rzt-arw { font-style: normal; margin: 0 0.4em; opacity: .5; }
.rzt-back { opacity: .45; }   /* the ring closes: the first station, again */
.rzt-trip { margin-left: auto; font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.06em;
  color: var(--accent); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* a row is a <details>: focusable, and toggled by Enter or Space, for free */
.rzt-row { border-top: 1px solid var(--rule); }
.rzt-loop > .rzt-rows > .rzt-row:first-child { border-top: 0; }
.rzt-sum { list-style: none; cursor: pointer; display: grid; align-items: baseline;
  grid-template-columns: 1.15rem max-content minmax(0, 1fr); gap: 2px 10px; padding: 9px 0 10px; }
.rzt-sum::-webkit-details-marker { display: none; }
.rzt-sum::before { content: "+"; grid-column: 1; grid-row: 1;
  font-family: var(--mono); font-size: 0.78rem; line-height: 1.35; color: var(--accent); }
.rzt-row[open] > .rzt-sum::before { content: "\2212"; }
.rzt-sum:hover .rzt-name { color: var(--accent); }
.rzt-name { grid-column: 2 / -1; grid-row: 1; font-size: 0.88rem; line-height: 1.35;
  color: var(--text); overflow-wrap: anywhere; transition: color .15s; }
.rzt-band { grid-column: 2; grid-row: 2; }
.rzt-peak { grid-column: 3; grid-row: 2; }
.rzt-st { grid-column: 2 / -1; grid-row: 3; }
.rzt-band, .rzt-peak { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.rzt-band { color: var(--accent); }
.rzt-peak { color: var(--muted); }
/* a band or a peak the catalogue does not carry is an em dash.  never a zero,
   never a blank cell, and never a number this table chose for it. */
.rzt-nil { color: var(--muted); opacity: .45; }
/* stacked, the two numbers sit side by side with no column head over them, and a
   bare second figure beside a range does not say what it is.  the word is the
   head, and the @container block below takes it away again once the real head is
   on screen. */
.rzt-peak::before { content: "peak "; opacity: .6; }
.rzt-st { font-size: 0.72rem; line-height: 1.45; color: var(--muted); overflow-wrap: anywhere; }
.rzt-mech { margin: 0 0 13px; padding-left: calc(1.15rem + 10px);
  font-size: 0.8rem; line-height: 1.5; color: var(--muted); max-width: 68ch; }

/* [hidden] is how the filters hide things, and a UA [hidden] rule loses to any
   author `display` on the same element -- so the pair is written out here. */
.rzt-row[hidden], .rzt-loop[hidden] { display: none; }
.rzt-none { margin: 20px 0 0; font-size: 0.82rem; line-height: 1.5; color: var(--muted); }
.rzt-count { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--rule);
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--muted); font-variant-numeric: tabular-nums; }
.rzt.is-empty .rzt-colhead { display: none; }

/* wide enough for four columns.  the query is on .rzt's own inline size. */
@container (min-width: 560px) {
  .rzt-colhead { display: grid; }
  .rzt-sum { grid-template-columns: 1.15rem minmax(0, 1.7fr) 7.4rem 5.2rem minmax(0, 1.6fr);
    gap: 0 12px; padding: 8px 0 9px; }
  .rzt-name { grid-column: 2; grid-row: 1; }
  .rzt-band { grid-column: 3; grid-row: 1; }
  .rzt-peak { grid-column: 4; grid-row: 1; }
  .rzt-peak::before { content: none; }
  .rzt-st { grid-column: 5; grid-row: 1; }
  .rzt-mech { padding-left: calc(1.15rem + 12px); }
}

@media (prefers-reduced-motion: reduce) {
  .rzt-chip, .rzt-name { transition: none; }
}
