/*
 * alkor — product site, restyle proposal.
 *
 * A public ledger of one run, not a brochure. The page is ruled like a broadsheet index:
 * full-bleed 1px rules, mono running-heads carrying a real datum, cream display type on a
 * warm near-black ground. Structure is drawn by rules and space only — there are no shadows
 * and no tinted bands anywhere in this sheet. The single filled object on the page is the
 * action block, and it carries the one accent: a reddish orange.
 *
 * FOUR RESERVED ROLES, and they must not be confused for each other:
 *   - --action (#e2542a) is identity and interaction. It is Mizar in the lockup, fills the
 *     primary button, and draws the focus ring, the current nav mark and the entry point of
 *     the fleet diagram. Nothing else.
 *   - --ok / --warn / --danger mean run state, and nothing decorative.
 * The accent lands at hue 14°, which is where the old salmon "failed" state lived (hue 7°,
 * only 7° away). --danger moved to rose at 346° — 28° of hue and CIELab dE 45.6 from the
 * accent, which is the distance --warn already holds from it, and the bar a state colour
 * has to clear on a page about refusals.
 *
 * THE ACCENT FILLS AND MARKS; IT IS NEVER TEXT. On the light ground it measures 3.33:1,
 * which clears the 3:1 a fill or a 1px mark owes and misses the 4.5:1 a word owes.
 *
 * Two floors carried over from the product and held here in BOTH themes:
 *   - a measured value never renders below 12px;
 *   - body text holds 4.5:1 and state-bearing marks 3:1.
 *
 * The display tops out at 5.5rem, which is where the hero headline sets. Measured in the
 * browser rather than estimated: its widest line ("Small local models") sets 727px at 88px
 * against a 738px column at 1920 and a 742px column at 1440, so 88px is the largest size
 * that still holds the headline to the two lines the composition is built on.
 */

/* ==========================================================================
   1. Tokens
   ========================================================================== */

:root {
  /* Spacing — one 4px unit, nine rungs. */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 40px; --s-7: 64px; --s-8: 96px; --s-9: 144px;

  --radius: 2px;

  --font-sans: "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Type. The display cap is 6rem; nothing on this page goes above it. */
  --t-display: clamp(2.375rem, 6.11vw, 5.5rem);
  --t-h2:      clamp(1.875rem, 3.2vw, 2.75rem);
  --t-h3:      1.1875rem;
  --t-stat:    clamp(2rem, 3.4vw, 3rem);
  --t-lead:    clamp(1.0625rem, 1.25vw, 1.1875rem);
  --t-body:    0.9375rem;
  --t-meta:    0.8125rem;
  --t-mono:    0.8125rem;
  --t-mono-sm: 0.75rem;

  --wrap: 1320px;
  --gutter: clamp(20px, 4vw, 40px);
  --h-topbar: 44px;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Dark leads: this page is read at a desk beside a terminal, usually at night, next to a
   run that takes minutes. The ground is warm rather than blue-black so the cream sits on
   it as ink on stock rather than as light on glass.

   THE RAMP IS A TEMPERATURE GRADIENT, NOT A GREY SCALE. Every rung is derived from the
   accent in OKLCH, and the hue walks with the role: text stays yellow-warm at 66–72°, the
   ground sits at 44–46°, the structural rungs run 38–42°, and the accent itself lands at
   36.5°. The greys used to sit at 80–107° — warm, but warm in a different direction from
   the orange, which is exactly what made the page read as monochrome-and-unrelated.
   Chroma climbs with the rung: 0.012 at the ground, 0.078 at a major rule, 0.185 at the
   accent. Nothing here is a neutral; everything is the accent at some distance. */
:root, :root[data-theme="dark"] {
  color-scheme: dark;

  /* Two surfaces, and the second one sinks. The veil was briefly lifted above the ground
     and carried enough chroma to read as a maroon card rather than a recessed screen; a
     pane that holds a terminal has to sit under the page, not on it. It is now 1.05:1
     from the ground — the border draws the edge, the sink only has to be felt. */
  --ground: #272321;
  --veil:   #130804;   /* code, log panes, mocks, the notice strip */

  /* Structure — chroma rising with weight */
  --rule:        #362721;   /* minor divisions: ledger columns, list rows */
  --rule-strong: #4f362d;   /* emphasis inside a block */
  --rule-accent: #6b3727;   /* MAJOR divisions only: a section's own rule */

  /* Text — L 0.622 → 0.926, H 66–72, the yellow-warm end of the gradient */
  --ink:         #efe5d8;   /* 15.1:1 */
  --ink-2:       #b1a395;   /* 7.7:1  */
  --ink-3:       #948474;   /* 5.2:1 on the ground, 5.5:1 on the veil */

  --action-bg:   #e2542a;   /* 4.97:1 under --action-ink; 4.97:1 as a mark on the ground */
  --action-ink:  #16100d;
  --action-bg-h: #f0603b;
  --action-mute: #af5136;   /* 3.6:1 — the accent at mark strength: borders, never text */

  /* Syntax. Two more rungs of the accent family, at text strength on the veil. These exist
     because --ok and --warn used to do this job, which made a clinical verdict print in the
     pass colour and "0 unverified" print as a warning. A run's output is not a run's state. */
  --syn-str: #c8aa96;   /* 9.1:1 on the veil */
  --syn-num: #e08b74;   /* 7.6:1 on the veil */

  /* Alcor's colour in the lockup. Only the crescent outside Mizar is visible, so this reads
     against the page ground (18.9:1) with the orange disc along one edge (3.79:1). A pure
     value rather than the cream ink because the crescent is ~3px deep at topbar size and
     every bit of edge separation counts. */
  --mark-counter: #ffffff;

  /* One family: a shared L/C band (L 0.72, C 0.115) with only the hue telling them apart,
     so three states read as siblings rather than three borrowed colours. Every one clears
     dE 45.6 from the accent — the distance that keeps "do this" and "this failed" apart. */
  --ok:     #80b66e;   /* 7.9:1, H 138, dE 88.3 */
  --warn:   #c1a147;   /* 7.6:1, H  90, dE 53.4 */
  --danger: #e1859b;   /* 7.2:1, H   5, dE 51.7 */

  --select-bg: rgba(239, 229, 216, 0.20);
}

:root[data-theme="light"] {
  color-scheme: light;

  --ground: #f7f1e8;
  --veil:   #efe4dd;

  --rule:        #e8d2c5;
  --rule-strong: #d7b6a6;
  --rule-accent: #d19983;

  --ink:         #201810;   /* 15.6:1 */
  --ink-2:       #625448;   /* 6.5:1  */
  --ink-3:       #706052;   /* 5.4:1 on the ground, 4.8:1 on the veil */

  --action-bg:   #e2542a;   /* the accent is one value in both themes */
  --action-ink:  #201810;   /* 4.61:1 */
  --action-bg-h: #f0603b;
  --action-mute: #c95a37;   /* 3.7:1 as a mark */

  --syn-str: #6f5443;   /* 5.6:1 on the veil */
  --syn-num: #8e412c;   /* 5.7:1 on the veil */

  --mark-counter: #000000;  /* 18.5:1 on paper, 5.54:1 against the disc edge */

  --ok:     #397421;   /* 5.1:1, H 138, dE 90.3 */
  --warn:   #805e00;   /* 5.3:1, H  90, dE 48.7 */
  --danger: #9d3d59;   /* 5.8:1, H   5, dE 50.9 */

  --select-bg: rgba(32, 24, 16, 0.15);
}

/* ==========================================================================
   2. Base, and the browser surfaces this design also owns
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--h-topbar) + 24px);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.62;
  font-feature-settings: "kern" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--select-bg); color: var(--ink); }

:root { scrollbar-color: var(--rule-strong) var(--ground); scrollbar-width: thin; caret-color: var(--ink); }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--ground); }
::-webkit-scrollbar-thumb { background: var(--rule-strong); border: 3px solid var(--ground); border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

:focus-visible {
  outline: 2px solid var(--action-bg);
  outline-offset: 3px;
  border-radius: 1px;
}

h1, h2, h3, h4, p, ul, ol, figure, pre { margin: 0; }
ul, ol { padding: 0; list-style: none; }

a { color: inherit; text-decoration-color: var(--rule-strong); text-underline-offset: 0.22em; text-decoration-thickness: 1px; }
a:hover { text-decoration-color: currentColor; }

strong, b { font-weight: 600; color: var(--ink); }
em { font-style: normal; box-shadow: inset 0 -1px 0 var(--rule-strong); }

code, .mono, pre { font-family: var(--font-mono); font-variant-ligatures: none; }
code { font-size: 0.92em; color: var(--ink); }
.mono { font-size: var(--t-mono); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--gutter); top: -100px; z-index: 60;
  background: var(--action-bg); color: var(--action-ink);
  padding: 10px 16px; font-weight: 600; text-decoration: none; border-radius: var(--radius);
}
.skip-link:focus { top: 12px; }

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ==========================================================================
   3. Type roles
   ========================================================================== */

.display {
  font-size: var(--t-display);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.h2 {
  font-size: var(--t-h2);
  font-weight: 650;
  line-height: 1.04;
  letter-spacing: -0.028em;
  text-wrap: balance;
  max-width: 18ch;
}

.h3 {
  font-size: var(--t-h3);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.015em;
}

.lede {
  font-size: var(--t-lead);
  line-height: 1.58;
  color: var(--ink-2);
  max-width: 62ch;
}
.lede strong, .lede em { color: var(--ink); }

.prose { color: var(--ink-2); max-width: 68ch; }

.tag {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.06em;
  text-transform: lowercase;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* The running head: a mono label on the section's own rule, paired with a fact about that
   section on the right. It sits on the rule rather than above the heading — this is the
   sheet's masthead device, not a kicker. */
.runhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  border-top: 1px solid var(--rule-accent);
  padding-top: var(--s-3);
  margin-bottom: var(--s-7);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}
.runhead > :first-child { color: var(--ink-3); }
.runhead > :last-child { color: var(--ink-2); }
.runhead b { font-weight: 500; color: var(--ink); }

/* ==========================================================================
   4. Notice strip + topbar
   ========================================================================== */

/* The one line on this page that must not be missed. It stays quiet in voice — no fill, no
   state hue, no alarm — and stops being quiet in value: the page's own ground, a major rule
   under it, and body-sized type instead of meta. */
.notice {
  border-bottom: 1px solid var(--rule-accent);
}
.notice__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 9px var(--gutter);
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  font-size: var(--t-body);
  color: var(--ink-2);
  line-height: 1.5;
}
.notice__icon { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--ink-3); }
.notice strong { color: var(--ink); }

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--rule);
}
/* The bar's own bottom rule doubles as the reader's position in the sheet. It is a broadsheet
   device rather than a web one: the rule is already there, and this only says how much of it
   has been read. Scroll-driven, so it is the reader's hand moving it and there is no clock to
   fall out of step with; browsers without scroll timelines simply keep the plain rule. */
@supports (animation-timeline: scroll()) {
  .topbar::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -1px;
    height: 1px;
    background: var(--action-bg);
    transform: scaleX(0);
    transform-origin: left;
    animation: rule-draw linear both;
    animation-timeline: scroll(root block);
  }
}
.topbar__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
  min-height: var(--h-topbar);
  display: flex;
  align-items: center;
  gap: var(--s-5);
}
.topbar__lockup { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }

/* The disclaimer sits in the bar itself, so it stays on screen the whole way down. The full
   wording is in the footer; here it is the short form, quiet in voice and set after a rule. */
.topbar__notice {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding-left: var(--s-3);
  border-left: 1px solid var(--rule);
  font-size: var(--t-meta);
  line-height: 1.2;
  color: var(--ink-2);
  white-space: nowrap;
  min-width: 0;
}
.topbar__notice span { overflow: hidden; text-overflow: ellipsis; }
.topbar__notice strong { color: var(--ink); font-weight: 600; }
.topbar__notice-icon { width: 14px; height: 14px; flex: none; color: var(--ink-3); }
@media (max-width: 1080px) { .topbar__notice strong { display: none; } }
@media (max-width: 480px) {
  .topbar__notice-icon { display: none; }
  .topbar__inner { gap: var(--s-3); }
  .topbar__lockup .pill { display: none; }
  .topbar__notice { font-size: 12px; padding-left: var(--s-2); white-space: normal; }
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--ink);
  min-width: 0;
}
.brand__star { width: 15px; height: 13px; flex: none; }

/* The mark is Mizar and Alcor. Mizar, the bright one, is the accent disc, and it obscures its
   companion: Alcor's centre is 28 units from Mizar's against a radius of 30, so drawn first
   and covered, only the crescent between 30 and 42.7 survives — about 3px of it at topbar
   size. Paint order is load-bearing and this is the direction that carries the metaphor:
   Alcor first, Mizar over it. Flip it and Alcor becomes a dot sitting on the disc instead of
   the faint one you have to resolve at its edge. */
.brand__mizar { fill: var(--action-bg); }
.brand__alcor { fill: var(--mark-counter); }
.brand__mark { width: 62px; height: 21px; flex: none; }
.brand { flex: none; }
.brand__descriptor {
  font-size: var(--t-meta);
  color: var(--ink-3);
  border-left: 1px solid var(--rule);
  padding-left: var(--s-3);
  margin-left: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (max-width: 1080px) { .brand__descriptor { display: none; } }

.pill {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.05em;
  color: var(--ink-2);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  padding: 1px 7px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.nav { display: flex; gap: var(--s-5); margin-left: auto; }
.nav a {
  font-size: var(--t-meta);
  color: var(--ink-2);
  text-decoration: none;
  padding: 4px 0;
  position: relative;
  transition: color 0.18s var(--ease);
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--action-bg);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.28s var(--ease);
}
.nav a:hover { color: var(--ink); }
.nav a:hover::after, .nav a.is-current::after { transform: scaleX(1); }
.nav a.is-current { color: var(--ink); }
@media (max-width: 760px) { .nav { display: none; } }

.topbar__actions { display: flex; align-items: center; gap: var(--s-1); }
@media (max-width: 760px) { .topbar__actions { margin-left: auto; } }

.icon-btn {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  padding: 0;
  transition: color 0.16s, border-color 0.16s;
}
.icon-btn:hover { color: var(--ink); border-color: var(--rule-strong); }
.icon-btn svg { width: 15px; height: 15px; }

/* The language switch is an icon-btn carrying two letters instead of a glyph, so it
   keeps the row's height and hover while sizing itself to the label. */
.lang-btn {
  width: auto;
  min-width: 30px;
  padding: 0 7px;
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.icon-moon { display: none; }
:root[data-theme="dark"] .icon-sun { display: none; }
:root[data-theme="dark"] .icon-moon { display: block; }

/* ==========================================================================
   5. Buttons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: var(--t-body);
  font-weight: 550;
  letter-spacing: -0.01em;
  text-decoration: none;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 0.18s var(--ease), color 0.18s var(--ease), border-color 0.18s;
}
.btn__arrow { width: 13px; height: 13px; flex: none; transition: transform 0.3s var(--ease); }
.btn:hover .btn__arrow { transform: translate(2px, -2px); }
.btn--down:hover .btn__arrow { transform: translate(0, 2px); }

.btn--action {
  background: var(--action-bg);
  color: var(--action-ink);
  padding: 14px 22px;
}
.btn--action:hover { background: var(--action-bg-h); }

.btn--plain {
  color: var(--ink-2);
  padding: 14px 2px;
  box-shadow: inset 0 -1px 0 var(--rule-strong);
  border-radius: 0;
}
.btn--plain:hover { color: var(--ink); box-shadow: inset 0 -1px 0 currentColor; }

/* ==========================================================================
   6. Sections
   ========================================================================== */

main { display: block; }

.band { padding-top: var(--s-8); padding-bottom: 0; }
main > .band:last-child { padding-bottom: var(--s-8); }
.band__head { margin-bottom: var(--s-7); display: grid; gap: var(--s-4); }

/* ---- Hero ---- */

.hero { padding-top: var(--s-8); padding-bottom: 0; }

.hero__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, min(480px, 36vw));
  gap: clamp(32px, 3.8vw, 56px);
  align-items: start;
}
.hero__head { margin-bottom: clamp(18px, 2.4vw, 28px); }
.hero__head span { display: block; }
/* The middle line drops to the secondary ink so the one word that matters in it stays lit. */
.hero__head-dim { color: var(--ink-3); }
.hero__head-dim b { color: var(--ink); font-weight: inherit; }

/* The bar is the hero's single loud mark — the accent spent in one place, at the width of
   the column it closes, in place of the stamp block the headline used to carry. */
.hero__bar {
  height: 6px;
  background: var(--action-bg);
  margin-bottom: var(--s-5);
}

.hero__stamp {
  display: inline-block;
  background: var(--action-bg);
  color: var(--action-ink);
  border-radius: var(--radius);
  padding: 0.04em 0.13em 0.09em;
  margin-left: -0.13em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.hero__copy .lede { max-width: 54ch; }
.hero__lede-lead {
  display: block;
  color: var(--ink);
  font-weight: 600;
  margin-bottom: 0.3em;
}
.hero__lede-rest { display: block; }
.hero__cta { display: flex; align-items: center; gap: var(--s-5); flex-wrap: wrap; margin-top: var(--s-6); }

@media (max-width: 980px) {
  .hero__top { grid-template-columns: minmax(0, 1fr); gap: var(--s-7); }
}

/* ---- The hero film ----

   The hero loop from video/hero.html: the note over its syndromic board, 18:25 so it stands as
   tall as the hero's text column. It comes in two editions, each rendered on its theme's own
   ground (#272321, #f7f1e8), so in either theme it has no edge at all. */

.herofilm { margin: 0; }
.herofilm__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 18 / 25;
  background: var(--ground);
}
/* One edition per theme; only the one matching the page is ever in the flow. */
.herofilm__video--light { display: none; }
:root[data-theme="light"] .herofilm__video--dark { display: none; }
:root[data-theme="light"] .herofilm__video--light { display: block; }
@media (max-width: 980px) {
  .herofilm { max-width: 480px; }
}

/* ---- The syndromic board: the hero's object ----

   One patient's evidence drawn as nested claims, from the syndromic-board proposal. A circle
   inside another is a narrower claim over the same evidence, never one caused by it. The rim
   carries one arc per input the rule needs: solid where the note documented it, broken where
   nobody looked, hatched through when nothing was documented at all. The rim says how well
   evidenced, never the verdict; verdicts are words, in the cells under the board. Area and
   hue encode nothing clinical, so the accent is spent only on the hover that pairs a circle
   with its cell. The markup is generated once, statically, so the board needs no script. */

.synboard { margin: 0; }
.synboard__svg { display: block; width: 100%; height: auto; margin: 0 0 var(--s-4); }

.sb-field { fill: none; stroke: var(--rule-strong); stroke-width: 1; }
.sb-case {
  fill: var(--ink-3); font-family: var(--font-mono); font-size: 13px;
  letter-spacing: 0.08em; text-anchor: middle;
}
.sb-on  { fill: none; stroke: var(--ink); stroke-width: 2.5; transition: stroke 0.16s; }
.sb-off { fill: none; stroke: var(--ink-3); stroke-width: 1.25; stroke-dasharray: 2 3; }
.sb-hatch { fill: url(#sb-hatch); }
#sb-hatch line { stroke: var(--ink-3); stroke-width: 1; opacity: 0.4; }
/* Depth recedes: the screens read first, the detail under them second. */
.sb-node--deep { opacity: 0.58; }
.sb-name {
  fill: var(--ink); font-family: var(--font-sans); font-weight: 600;
  font-size: 18px; letter-spacing: -0.01em; text-anchor: middle;
}
.sb-sub {
  fill: var(--ink-2); font-family: var(--font-mono); font-size: 15px;
  letter-spacing: 0.04em; text-anchor: middle;
}
.sb-marker { fill: var(--ink-3); font-family: var(--font-mono); font-size: 16px; text-anchor: middle; }

/* The verdicts, as four cells under the board. Each cell's tick bar is its circle's rim
   unrolled: one tick per input the rule needs, solid where documented, dashed where nobody
   looked. The verdict is the word; the ticks say how much of it was evidenced. */
.synboard__cells {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 1px; background: var(--rule); border: 1px solid var(--rule);
}
.synboard__cells li {
  background: var(--ground);
  padding: var(--s-3) var(--s-4);
  display: grid; gap: 6px; align-content: start;
  transition: box-shadow 0.16s;
}
.synboard__name { font-size: var(--t-meta); color: var(--ink-2); }
.synboard__verdict { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.018em; line-height: 1.2; }
.synboard__ev { display: flex; align-items: center; gap: var(--s-3); font-size: var(--t-mono-sm); color: var(--ink-3); }
.synboard__ev .mono { white-space: nowrap; }
@media (max-width: 480px) {
  .synboard__cells li { padding: var(--s-3); }
  .synboard__ev { flex-wrap: wrap; row-gap: 4px; }
}
.synboard__ticks { display: flex; gap: 3px; }
.synboard__ticks i { width: 10px; border-top: 2.5px solid var(--ink); }
.synboard__ticks i.off { border-top: 1px dashed var(--ink-3); margin-top: 1px; }

/* A circle and its row answer each other: hover either and both take the accent mark. */
.synboard g:hover .sb-on,
.synboard:has(li[data-id="shock"]:hover) g[data-id="shock"] .sb-on,
.synboard:has(li[data-id="sepsis"]:hover) g[data-id="sepsis"] .sb-on,
.synboard:has(li[data-id="volume"]:hover) g[data-id="volume"] .sb-on,
.synboard:has(li[data-id="focal"]:hover) g[data-id="focal"] .sb-on { stroke: var(--action-bg); }
.synboard li:hover,
.synboard:has(g[data-id="shock"]:hover) li[data-id="shock"],
.synboard:has(g[data-id="sepsis"]:hover) li[data-id="sepsis"],
.synboard:has(g[data-id="volume"]:hover) li[data-id="volume"],
.synboard:has(g[data-id="focal"]:hover) li[data-id="focal"] { box-shadow: inset 0 -2px 0 var(--action-bg); }

.synboard__legend {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4);
  margin: var(--s-3) 0 0;
  font-size: var(--t-mono-sm); color: var(--ink-3);
}
.synboard__legend span { display: inline-flex; align-items: center; gap: var(--s-2); }
.sb-key { display: inline-block; width: 16px; border-top: 2px solid var(--ink); }
.sb-key--off { border-top: 1px dashed var(--ink-3); }
.sb-key--none {
  width: 10px; height: 10px; border: 1px dashed var(--ink-3);
  background: repeating-linear-gradient(45deg, transparent 0 3px, color-mix(in oklab, var(--ink-3) 45%, transparent) 3px 4px);
}

/* The group a run's rows sit in. The hero's own list is an <ol> and needs no box of its own;
   this exists so a block of .rstep rows still has one element to name. */
.rsteps { display: grid; }

.rstep {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: var(--s-3);
  row-gap: 2px;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
}
.rstep__dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--ok);
  align-self: center;
  justify-self: center;
}
.rstep__name { font-weight: 550; letter-spacing: -0.01em; }
.rstep__state {
  font-family: var(--font-mono); font-size: var(--t-mono-sm);
  color: var(--ok); letter-spacing: 0.04em;
  grid-column: 3;
}
.rstep__profile { grid-column: 2; color: var(--ink-3); font-size: var(--t-mono-sm); font-variant-numeric: tabular-nums; }
.rstep__t { grid-column: 3; color: var(--ink-2); justify-self: end; font-size: var(--t-mono-sm); }

/* The two states a checked row can also report. `--no` is a refusal the run acted on: the one
   quote the verifier could not find. `--idle` is a row that has not happened yet, and is not a
   failure — it takes the dot's own neutral rather than a state hue, which is why it exists. */
.rstep__state--no { color: var(--danger); }
.rstep__state--idle { color: var(--ink-3); }
.rstep--idle .rstep__dot { background: var(--ink-3); }

/* ---- The ledger: the page's repeating structure, in place of cards ---- */

.ledger {
  display: grid;
  border-top: 1px solid var(--rule);
}
.ledger--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ledger--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ledger--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ledger > * {
  padding: var(--s-5) var(--s-5) var(--s-2) var(--s-5);
  border-left: 1px solid var(--rule);
}
.ledger > *:first-child { border-left: 0; padding-left: 0; }
.ledger h3 { margin-bottom: var(--s-3); }
.ledger p { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; }

@media (max-width: 900px) {
  .ledger--4, .ledger--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--s-5); }
  .ledger--4 > *:nth-child(3), .ledger--3 > *:nth-child(3) { border-left: 0; padding-left: 0; }
}
@media (max-width: 600px) {
  .ledger { grid-template-columns: minmax(0, 1fr) !important; row-gap: 0; }
  .ledger > * {
    border-left: 0; padding-left: 0;
    border-top: 1px solid var(--rule);
    padding-top: var(--s-4); padding-bottom: var(--s-4); padding-right: 0;
  }
  .ledger > *:first-child { border-top: 0; padding-top: var(--s-4); }
}

/* ---- The note: a two-column aside, ruled top and bottom ---- */

.note {
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 1fr);
  gap: var(--s-6);
  border-top: 1px solid var(--rule-accent);
  border-bottom: 1px solid var(--rule);
  padding-block: var(--s-5);
  margin-top: var(--s-7);
}
.note__k { font-family: var(--font-mono); font-size: var(--t-mono); color: var(--ink); letter-spacing: -0.01em; }
.note__body { color: var(--ink-2); max-width: 70ch; display: grid; gap: var(--s-3); }
.note__body strong { color: var(--ink); }
@media (max-width: 720px) { .note { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); } }

/* ---- Mechanism marks (#premise ledger) ----

   The premise band states that a call is narrowed until a rule can check it, and then shows
   nothing. Each article now carries the claim drawn in the sheet's own material: four
   identical, unconnected rules for four calls that leave no transcript between them, and two
   kept readings marked in the accent above two struck through. Geometry, not illustration;
   the marks are aria-hidden because the paragraph beside them already says it in words. */

.pfig { display: block; width: 132px; height: auto; margin-bottom: var(--s-4); overflow: visible; }
.pfig line { stroke: var(--ink-3); stroke-width: 1; transform-box: fill-box; transform-origin: left center; }
.pfig .k { stroke: var(--action-mute); stroke-width: 2; }   /* kept: the accent as a mark, never as text */
.pfig .drop, .pfig .strike { opacity: 0.45; }

/* ---- Snippets ---- */

.snippet {
  position: relative;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--veil);
}
.code {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  line-height: 1.75;
  color: var(--ink);
  padding: var(--s-4) 92px var(--s-4) var(--s-4);
  overflow-x: auto;
  white-space: pre;
  tab-size: 2;
}
.c-prompt { color: var(--ink-3); user-select: none; }
.c-str { color: var(--syn-str); }
.c-key { color: var(--ink); }
.c-val { color: var(--syn-num); }
.c-punc { color: var(--ink-3); }
.cmd { color: var(--ink); }

.copy-btn {
  position: absolute;
  top: 9px; right: 9px;
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-mono); font-size: var(--t-mono-sm);
  color: var(--ink-3);
  background: var(--veil);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  padding: 3px 8px;
  cursor: pointer;
  transition: color 0.16s, border-color 0.16s;
}
.copy-btn:hover { color: var(--ink); border-color: var(--action-mute); }

.snippet::after {
  content: "";
  position: absolute;
  top: 1px; right: 1px; bottom: 1px;
  width: 40px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to right, transparent, var(--veil));
  transition: opacity 0.2s var(--ease);
}
.snippet.has-more::after { opacity: 1; }
@media (max-width: 700px) {
  .snippet { display: grid; }
  .code { padding-right: var(--s-4); }
  .copy-btn { position: static; justify-self: end; margin: 0 9px 9px; }
}
.copy-btn.is-done { color: var(--ink); border-color: var(--ink-3); }
.copy-btn svg { width: 11px; height: 11px; }

/* ---- Quickstart ---- */

.start-lead { display: grid; gap: var(--s-4); }
.start-lead .snippet { margin-block: var(--s-1); }

.steps { display: grid; border-top: 1px solid var(--rule); margin-top: var(--s-7); }
.step {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) minmax(0, 1.3fr);
  gap: var(--s-5);
  align-items: start;
  padding-block: var(--s-5);
  border-bottom: 1px solid var(--rule);
}
.step__n { color: var(--ink-3); font-size: var(--t-mono); padding-top: 3px; font-variant-numeric: tabular-nums; }
.step__copy { display: grid; gap: var(--s-2); }
.step__copy p { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; }
@media (max-width: 900px) {
  .step { grid-template-columns: 28px minmax(0, 1fr); gap: var(--s-3) var(--s-4); }
  .step .snippet { grid-column: 2; }
}

.steps-lead {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--ink);
  margin-top: var(--s-7);
  margin-bottom: calc(var(--s-5) * -1);
  letter-spacing: -0.01em;
}

/* ---- Architecture ladder ---- */

.arch {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
@media (max-width: 980px) { .arch { grid-template-columns: minmax(0, 1fr); } }

.ladder { border-top: 1px solid var(--rule); }
/* The indent is carried by the CONTENT, not by the row's own box: the rule under each level has
   to run the full width whatever the nesting does, and the content is the only part that moves
   when the stack lies flat below. The right padding grows with the depth so a row's text keeps
   the same measure indented as it has flat. */
.ladder__row {
  --indent: calc(var(--depth) * 22px);
  border-bottom: 1px solid var(--rule);
  padding: var(--s-4) calc(4ch + var(--indent)) var(--s-4) 0;
  position: relative;
}
.ladder__row > *:not(.ladder__n) { transform: translateX(var(--indent)); }
.ladder__row::before {
  content: "";
  position: absolute;
  left: calc(var(--depth) * 22px - 11px);
  top: 0; bottom: 0;
  width: 1px;
  background: var(--action-mute);
}
.ladder__row[data-depth="0"]::before { display: none; }
/* "Point at the stack and it lies flat." The hint above the ladder promises this, so the ladder
   does it: under the pointer or keyboard focus every level slides back to the margin and the
   guides that carried the nesting fade out. It is the claim of the section made touchable —
   six levels, one tree, and the indent is the only thing that was ever holding them apart.
   Reduced motion keeps the flattening and drops the slide. */
.ladder__row > *:not(.ladder__n) { transition: transform 0.4s var(--ease); }
.ladder__row::before { transition: opacity 0.3s var(--ease); }
.ladder:hover .ladder__row > *, .ladder:focus-within .ladder__row > * { transform: none; }
.ladder:hover .ladder__row::before, .ladder:focus-within .ladder__row::before { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .ladder__row > *:not(.ladder__n) { transition: none; }
}
.ladder__path {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  margin-bottom: 5px;
  letter-spacing: 0.02em;
}
.ladder__sep { color: var(--ink-3); }   /* was opacity: 0.5 — 2.19:1, ten of them per theme */
.ladder__head { display: flex; align-items: baseline; gap: var(--s-3); flex-wrap: wrap; margin-bottom: 5px; }
.ladder__k { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.018em; }
.ladder__n {
  position: absolute;
  top: var(--s-4);
  right: 0;
  color: var(--ink-3);
  font-size: var(--t-mono-sm);
}
.ladder__d { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; max-width: 68ch; }
.ladder__hint { font-family: var(--font-mono); font-size: var(--t-mono-sm); color: var(--ink-3); margin-bottom: var(--s-3); }
@media (max-width: 560px) {
  .ladder__row { --indent: calc(var(--depth) * 10px); }
  .ladder__row::before { left: calc(var(--depth) * 10px - 5px); }
  .ladder__head .pill { white-space: normal; }
}

/* ---- The meter: a rate, and the length that lets you compare it ----
   Distilled as .alk-meter in system/alkor-ledger.css.

   A comparison sits on the ledger grid like everything else on this sheet; the only addition
   is a 4px track under each rate, because three percentages are read against one another and
   a length is read faster than a digit. The track is a rule that happens to be short — it
   carries no state hue, and a low rate is never tinted with --danger, because a smaller number
   is not a failed run. The verdict pill beside it is the thing that carries state, and it
   carries a word too.

   The shipped run's rate takes the accent on the same grounds the workflow tally does: one
   headline figure at display size, where the bar is 3:1 and it measures 4.97:1 dark, 3.38:1
   light. That is a display-size exception and it does not survive a smaller ramp — the
   distilled Operate version keeps every figure in --ink and moves the accent into the track.

   Selectors are compounded under .meters because .ledger p (0,1,1) would otherwise outrank a
   bare element class and reset these back to meta text. The prose line under each meter is
   deliberately NOT one of them: it is the ledger's own paragraph, and it should stay that. */

.meters .meter { display: grid; gap: var(--s-2); align-content: start; }
.meters h3 { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.018em; margin: 0; }
.meters .meter__k {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  letter-spacing: 0.04em;
  line-height: 1.4;
}
.meters .meter__v {
  font-size: var(--t-stat);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  margin-top: var(--s-2);
}
.meters .meter--shipped .meter__v { color: var(--action-bg); }
.meter__bar { height: 4px; background: var(--rule); }
.meter__bar > i { display: block; height: 100%; width: var(--w); background: var(--ink-3); }
.meter--shipped .meter__bar > i { background: var(--action-mute); }
.meters .meter__n {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.pill--pass { color: var(--ok); border-color: var(--ok); }
.pill--fail { color: var(--danger); border-color: var(--danger); }

/* The sub-head inside a band, distilled as .alk-subhead: a second heading rank would out-shout
   the section's own h2, so the label is set in mono at measured size, on the rule the ledger
   under it already draws. */
.subhead {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--ink);
  letter-spacing: 0.02em;
  margin-top: var(--s-8);
  margin-bottom: var(--s-4);
}

/* ---- The workflow row ---- */

.wf-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-6);
  flex-wrap: wrap;
  margin-bottom: var(--s-7);
}
.wf-tally { text-align: right; }
.wf-tally__v {
  font-size: var(--t-stat);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--action-bg);   /* large text: 4.97:1 dark, 3.38:1 light, both over the 3:1 bar */
}
.wf-tally__k { color: var(--ink-3); font-size: var(--t-meta); max-width: 28ch; margin-top: 6px; }
@media (max-width: 720px) { .wf-tally { text-align: left; } .wf-tally__k { max-width: none; } }

.wf-keys { display: flex; gap: var(--s-5); margin-bottom: var(--s-4); flex-wrap: wrap; }
.wf-key { display: inline-flex; align-items: center; gap: 7px; font-family: var(--font-mono); font-size: var(--t-mono-sm); color: var(--ink-2); }
.dot { width: 5px; height: 5px; border-radius: 50%; flex: none; background: var(--ink-3); }
/* Filled disc vs hollow ring — the distinction a colourblind reader can still make, and it
   frees two state hues that were being spent on a taxonomy rather than on run state. */
.dot--model, .dot--code { width: 7px; height: 7px; }
.dot--model { background: var(--ink-2); }
.dot--code  { background: transparent; border: 1.5px solid var(--ink-2); }

.wf-card { display: grid; gap: 6px; align-content: start; }
.wf-card__n { color: var(--ink-3); font-size: var(--t-mono-sm); display: flex; align-items: center; gap: 7px; }
.wf-card h3 { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.018em; margin: 2px 0 0; }
.wf-card__p { font-family: var(--font-mono); font-size: var(--t-mono-sm); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.wf-card__d { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; margin-top: var(--s-2); }
.wf-card__t {
  font-family: var(--font-mono); font-size: var(--t-mono); color: var(--ink);
  font-variant-numeric: tabular-nums; margin-top: var(--s-3);
}

/* Run order drawn over the ledger: one accent segment and marker per step. The accent carries
   sequence here, never the model/rule taxonomy — the filled and hollow dots still do that. */
.wf-rail { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: var(--s-4); }
.wf-rail i { position: relative; height: 2px; background: var(--action-bg); }
.wf-rail i::after {
  content: "";
  position: absolute;
  left: 0; top: -4px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--action-bg);
}
@media (max-width: 900px) { .wf-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .wf-rail { grid-template-columns: minmax(0, 1fr); } }

.ledger--railed { border-top: 0; }
.ledger--railed > .wf-card { padding-top: var(--s-4); }
.ledger--railed .wf-card__n { color: var(--action-bg); font-size: var(--t-mono); }
.ledger--railed .wf-card__n .dot--model { background: var(--action-bg); }
.ledger--railed .wf-card__n .dot--code { border-color: var(--action-bg); }
.ledger--railed .wf-card h3 { font-size: 1.5rem; letter-spacing: -0.024em; }
.ledger--railed .wf-card__d { font-size: 0.9375rem; line-height: 1.58; }

/* What a step runs on is the card's data point, not how long it took: timings and ports move
   with the machine and the config, and the page does not print figures it cannot stand behind. */
.ledger--runner > .wf-card { gap: var(--s-2); padding-bottom: var(--s-5); }
.ledger--runner .wf-card__r { margin-top: 2px; }
.ledger--runner .wf-card__d { margin-top: var(--s-3); }

.wf-foot { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-6); margin-top: var(--s-7); }
.wf-foot p { color: var(--ink-2); max-width: 52ch; font-size: var(--t-meta); line-height: 1.6; }
@media (max-width: 720px) { .wf-foot { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); } }

/* The section's three closing notes read across one band: how the runs were marked, where the
   gap is, and what the corpus cannot show. Column rules carry the division; no card, no fill. */
.wf-close {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-6);
  margin-top: var(--s-7);
  border-top: 1px solid var(--rule-accent);
  padding-top: var(--s-5);
}
.wf-close__col { display: grid; gap: var(--s-3); align-content: start; }
.wf-close__col + .wf-close__col { border-left: 1px solid var(--rule); padding-left: var(--s-6); }
.wf-close__k {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: -0.01em;
  color: var(--ink-3);
}
.wf-close__col p:last-child { margin: 0; color: var(--ink-2); font-size: 0.96875rem; line-height: 1.62; }
.wf-close__col--caveat p:last-child { color: var(--ink-3); }
@media (max-width: 980px) {
  .wf-close { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .wf-close__col + .wf-close__col {
    border-left: 0;
    padding-left: 0;
    border-top: 1px solid var(--rule);
    padding-top: var(--s-4);
  }
}

/* ---- The nine steps, walked one at a time (#how) ----

   The section that answers "how does this actually work" for a reader who has not opened the
   repository. It is a stepper rather than nine stacked blocks because the thing being shown is
   SEQUENCE: what each step is handed, and who decided it. Nine blocks down the page read as
   nine facts; one block that advances reads as one run.

   It never takes the page over. The panel is a block in the band's own rhythm, the arrow keys
   page it only while focus is inside it, and every step is one click away on the strip — so
   nothing here sits behind an interaction a reader has to discover.

   WHAT IT DOES NOT PRINT, and why. No durations, no tok/s, no scores. The rule is the one
   already written over .ledger--runner: a timing belongs to a machine and a config, and this
   page does not print figures it cannot stand behind. What a step RUNS ON is stable and is
   printed. The counts that do appear — nine steps, three of them model, four phrases in the
   worked example — are properties of the run's shape rather than measurements of its speed.

   The worked example is one synthetic dictation, and it says so where it enters. */

.hiw { margin-top: var(--s-6); }

.hiw__keys { display: flex; gap: var(--s-5); margin-bottom: var(--s-4); flex-wrap: wrap; }

/* The strip is this section's diagram and its control at once: filled where a model writes the
   answer, hollow where a rule decides, which is the distinction .dot--model already carries a
   few hundred lines up. Nine buttons, so no step is a mystery and none of them is unreachable. */
.hiw__strip {
  display: grid;
  grid-template-columns: repeat(9, minmax(0, 1fr));
  gap: 3px;
  list-style: none;
  margin: 0 0 var(--s-6);
  padding: 0;
}
.hiw__strip li { display: grid; }
.hiw__pip {
  width: 100%;
  display: grid;
  gap: 7px;
  justify-items: center;
  background: none;
  border: 0;
  padding: 0 0 2px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  transition: color 0.16s;
}
.hiw__pip i {
  display: block;
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 26px;
  box-shadow: inset 0 0 0 1px var(--rule-strong);
  transition: box-shadow 0.16s, background 0.16s;
}
.hiw__pip[data-kind="model"] i { background: var(--rule); box-shadow: none; }

/* The playhead, laid ALONG THE FOOT of each pip rather than across it. The block itself is
   still the diagram — filled where a model writes the answer, hollow where a rule decides —
   and a fill that covered the whole pip would erase that distinction on every step already
   walked, which is most of them. So the progress is a 3px track under the diagram: empty ahead
   of the run, sweeping while its step is on screen, and left behind at the muted weight.

   The bar's width IS the clock. It sweeps over --dwell, the same duration the script's timer
   is holding, and both are frozen by the same pause — so the bar can never disagree with the
   step it sits under. */
.hiw__pip i::before, .hiw__pip i::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
}
/* The unrun remainder of the current step, so the bar has a visible length to fill against
   rather than a bright stub floating on the pip's own edge. */
.hiw__pip i::before { background: var(--rule-strong); opacity: 0; }
.hiw__pip[aria-current="step"] i::before { opacity: 1; }
.hiw__pip i::after {
  background: var(--action-bg);
  transform: scaleX(0);
  transform-origin: left center;
}
.hiw__pip.is-played i::after { transform: none; background: var(--action-mute); }

.hiw__pip:hover { color: var(--ink-2); }
.hiw__pip:hover i { box-shadow: inset 0 0 0 1px var(--action-mute); }
.hiw__pip[data-kind="model"]:hover i { background: var(--action-mute); box-shadow: none; }
.hiw__pip[aria-current="step"] { color: var(--ink); }
.hiw__pip[aria-current="step"] i { box-shadow: inset 0 0 0 1px var(--action-bg); }
.hiw__pip[data-kind="model"][aria-current="step"] i { background: var(--action-bg); box-shadow: none; }
/* Stopped on a step, the current pip's track is simply full: the strip reads the same whether
   the run is playing, paused at a beat, or being walked by hand. */
.hiw__pip[aria-current="step"] i::after { transform: none; }
/* On the accent-filled current model pip the track needs the counter-colour to be seen at all. */
.hiw__pip[data-kind="model"][aria-current="step"] i::after { background: var(--ground); }

/* One stack, so the panel is as tall as its tallest step and nothing below it moves when the
   step changes. Steps that are not current keep their space and leave the tab order. */
.hiw__stage { display: grid; }
.hiw__step {
  grid-area: 1 / 1;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(28px, 4.4vw, 64px);
  align-items: start;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.22s ease;
}
.hiw__step.is-current { opacity: 1; visibility: visible; }
@media (prefers-reduced-motion: reduce) { .hiw__step { transition: none; } }

.hiw__said { display: grid; gap: var(--s-4); align-content: start; }
.hiw__n {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
/* The step's own title leads its column, so it sits above the panel's lead paragraph rather
   than level with it — the same lift .ledger--railed gives a workflow card's heading. */
.hiw__said h3 { margin: 0; max-width: 24ch; font-size: 1.375rem; letter-spacing: -0.022em; }
.hiw__said p { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.6; max-width: 52ch; }
.hiw__said p.hiw__lead { font-size: 1.0625rem; line-height: 1.58; }
.hiw__said p.hiw__lead strong { color: var(--ink); font-weight: 600; }

.hiw__shown { display: grid; gap: var(--s-4); }
.hiw .runhead { margin-bottom: var(--s-4); }
.hiw .rstep:last-child { border-bottom: 0; }

/* The form as it came back: a tick where a reading carries the words it was read from, a dash
   where nobody dictated anything. The dash is the quietest mark here and the load-bearing one. */
.hiw__form { display: grid; }
.hiw__frow {
  display: grid;
  grid-template-columns: 14px minmax(0, 8.5rem) minmax(0, 1fr);
  column-gap: var(--s-4);
  align-items: baseline;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
}
.hiw__frow:last-child { border-bottom: 0; }
.hiw__frow svg { width: 13px; height: 13px; align-self: center; justify-self: center; color: var(--ok); }
.hiw__frow--none svg { color: var(--ink-3); }
.hiw__frow dt {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.hiw__frow dd { margin: 0; display: grid; gap: 2px; }
.hiw__v { font-family: var(--font-mono); font-size: var(--t-mono); color: var(--ink); font-variant-numeric: tabular-nums; }
.hiw__v--none { font-family: var(--font-sans); font-size: var(--t-meta); color: var(--ink-3); }
.hiw__heard { font-size: var(--t-meta); color: var(--syn-str); }

/* One slot, two models, drawn rather than described. The claim this figure carries is the
   product's central one — alkor owns the server lifecycle, so a workflow needing more models than
   fit at once still runs on one machine — and it is a claim about time and space, which four rows
   of words were the wrong instrument for. Two outlined boxes on one lane, never overlapping, with
   the swept interval between them. Outlined and not filled: this world draws structure with 1px
   rules and spends fill only on the action block. */
.slot { display: grid; gap: var(--s-2); }
.slot__track { position: relative; height: 56px; }
.slot__blk {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--a);
  right: calc(100% - var(--b));
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 2px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
}
.slot__blk b { font-size: var(--t-meta); font-weight: 600; color: var(--ink); }
.slot__blk i { font-size: var(--t-mono-sm); font-style: normal; color: var(--ink-3); }
/* The interval where the machine is holding neither of them. Dashed, because nothing is there. */
.slot__gap {
  position: absolute;
  top: 50%;
  left: var(--a);
  right: calc(100% - var(--b));
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  height: 22px;
  border-top: 1px dashed var(--rule-strong);
  border-bottom: 1px dashed var(--rule-strong);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.slot__axis {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
}

/* A recomputed value against the line that judges it. The dot is the reading, the tick is the
   threshold, and the tinted run is the side of the line that is bad news — which IS run state,
   so it is the one place in this section a state hue appears, and it ships beside a word. */
.hiw__gauge { display: grid; gap: var(--s-2); padding: var(--s-4) 0; border-bottom: 1px solid var(--rule); }
.hiw__gauge:last-of-type { border-bottom: 0; }
.hiw__gtop { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-5); }
.hiw__gname { font-size: var(--t-meta); color: var(--ink-2); max-width: 38ch; }
.hiw__gnum {
  font-family: var(--font-mono);
  font-size: var(--t-stat);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.hiw__scale { position: relative; height: 40px; margin-top: var(--s-1); }
.hiw__axis { position: absolute; left: 0; right: 0; top: 9px; height: 3px; background: var(--rule); }
.hiw__zone { position: absolute; top: 5px; height: 11px; background: color-mix(in srgb, var(--danger) 16%, transparent); }
.hiw__thr { position: absolute; top: 2px; width: 1px; height: 17px; background: var(--ink-2); }
.hiw__thrlab {
  position: absolute;
  top: 23px;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-2);
  white-space: nowrap;
}
.hiw__dot {
  position: absolute;
  top: 4px;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--danger);
  box-shadow: 0 0 0 3px var(--ground);
  transform: translateX(-50%);
}
.hiw__verdict {
  display: flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: var(--t-mono-sm);
  color: var(--ink-2); letter-spacing: 0.04em;
}
.hiw__verdict .dot { background: var(--danger); }

/* Four quoted phrases, and where each was found. The bar is the note end to end and the mark is
   the position; the phrase with no position is the one being thrown away. It is struck through
   rather than only tinted, so the deletion survives greyscale and a colourblind reader. */
.hiw__q { display: grid; }
.hiw__qrow {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr) 7rem;
  column-gap: var(--s-4);
  align-items: center;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
}
.hiw__qrow:last-child { border-bottom: 0; }
.hiw__qrow svg { width: 13px; height: 13px; color: var(--ok); justify-self: center; }
.hiw__qrow--gone svg { color: var(--danger); }
.hiw__phrase {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--syn-str);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hiw__qrow--gone .hiw__phrase {
  color: var(--ink-3);
  text-decoration: line-through;
  text-decoration-color: var(--danger);
  text-decoration-thickness: 1px;
}
.hiw__where { position: relative; height: 8px; background: var(--rule); }
.hiw__where i { position: absolute; top: -3px; width: 3px; height: 14px; background: var(--ok); }
.hiw__miss {
  font-family: var(--font-mono); font-size: var(--t-mono-sm);
  color: var(--danger); text-align: right; letter-spacing: 0.04em;
}

.hiw__foot {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-top: var(--s-6);
  border-top: 1px solid var(--rule);
  padding-top: var(--s-4);
}
.hiw__count {
  font-family: var(--font-mono); font-size: var(--t-mono-sm);
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.hiw__hint { font-family: var(--font-mono); font-size: var(--t-mono-sm); color: var(--ink-3); margin-left: auto; }
.hiw__move { display: flex; gap: var(--s-2); }

/* The transport. One button owns the run's three states and says which one it is in words as
   well as in a glyph: play it, pause it, or play it again from step one. It sits first in the
   footer because it is the control that makes this section a recording rather than a form. */
.hiw__play {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: 30px;
  padding: 0 11px 0 9px;
  background: none;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  color: var(--ink);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  transition: border-color 0.16s, color 0.16s;
}
/* Held wide enough for the longest of its three words in either edition, so the footer does
   not shuffle every time the run starts or stops. */
.hiw__play span { min-width: 10ch; text-align: left; }
.hiw__play:hover { border-color: var(--action-mute); }
.hiw__play svg { width: 13px; height: 13px; flex: none; }
/* Only the glyph for the state the run is actually in. */
.hiw__play .i-pause, .hiw__play .i-replay { display: none; }
.hiw.is-playing:not(.is-paused) .hiw__play .i-play { display: none; }
.hiw.is-playing:not(.is-paused) .hiw__play .i-pause { display: block; }
.hiw.is-ended .hiw__play .i-play, .hiw.is-ended .hiw__play .i-pause { display: none; }
.hiw.is-ended .hiw__play .i-replay { display: block; }
@media (max-width: 620px) { .hiw__play span { display: none; } .hiw__play { padding: 0 8px; } }

.hiw__move button {
  width: 34px; height: 30px;
  display: grid; place-items: center;
  background: none;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.16s, color 0.16s;
}
.hiw__move button svg { width: 14px; height: 14px; }
.hiw__move button:hover { border-color: var(--action-mute); }
.hiw__move button[disabled] { color: var(--ink-3); border-color: var(--rule); cursor: default; }

/* The dictation and the ending page are read, not copied, so they take the snippet's surface
   without its copy button — and the dictation wraps, because it is prose somebody spoke. */
.snippet--plain .code { padding-right: var(--s-4); }
.code--wrap { white-space: pre-wrap; color: var(--ink-2); line-height: 2; }
.code--wrap mark { background: none; color: var(--ink); box-shadow: inset 0 -1px 0 var(--action-bg); }

@media (max-width: 900px) {
  /* Stacked, the step's two rows would share out the slack the stage keeps for its tallest step
     and open a hole between the sentence and the panel. They sit at the top instead. */
  .hiw__step { grid-template-columns: minmax(0, 1fr); gap: var(--s-5); align-content: start; }
  .hiw__strip { gap: 2px; }
  .hiw__pip i { height: 18px; }
  .hiw__hint { display: none; }
}

/* ---- The three clinical contracts (#clinical) ----

   Three ledger columns, each carrying the rule it applies as four mono rows before any prose
   about it. The rule is printed rather than described because it is short enough to print:
   a reader who can see all four outcomes of a 2x2 can check the sentence underneath against
   it, which is the whole posture of the page. Four rows in every card is deliberate — it is
   what keeps three different instruments (a table, a score, a count) reading as one system.

   Selectors are compounded under .syndromes for the reason .meters compounds: .ledger p
   (0,1,1) outranks a bare element class and would reset the mono lines to meta prose. */

.syndromes .syn__k {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  color: var(--ink-3);
  margin: 0;
}
.syndromes .syn h3 { margin: var(--s-2) 0 var(--s-4); }

/* THE ACCENT ENTERS THIS BAND, AND ONLY AS FILL AND MARK. The section carries the page's
   thesis and was the one band that spent no accent at all, which is what made it read flat
   beside #why's cream tally and the hero's stamp. Three marks, no text: the band's own top
   rule at 2px, the same mix at 60% strength on each card's rule, and a hairline box around
   the measured figure. The accent never becomes a word here — it measures 3.33:1 on the
   light ground, which clears what a fill owes and misses what a word owes. */
.ledger.syndromes { border-top: 2px solid color-mix(in oklab, var(--action-mute) 65%, var(--rule)); }

/* Two sentences, two lines, because the stamp's own padding is enough to move where the
   headline breaks — and a break inside "Each one" is a worse line than any width argument
   for letting it flow. The stamp sits two levels down, so the direct-child combinator is
   load-bearing: `.h2--lines span` would turn the accent block into a full-width band. */
.h2--lines > span { display: block; }

/* The band's lede was cut to one line of argument, so its measure comes in with it: 62ch is
   the page's paragraph width and it leaves a short sentence stranded across a long line. The
   figure is the accepted one, not a round number. */
.lede--tight { max-width: 46ch; }

/* The clinical lede runs three short sentences instead of one, so it takes its own measure:
   56ch is where the third sentence stops stranding a word on its own line. It is separate
   from --tight because the Spanish twin still carries the one-sentence version at 46ch. */
.lede--clinical { max-width: 56ch; }


/* The stamp, on the hero's terms: one word set in the accent block, in --action-ink at
   4.97:1. It is the page's signature move and it belongs to the word the section turns on —
   "decline" — not to a decorative one. One stamp per page section, or it stops being one. */
.syn-stamp {
  display: inline-block;
  background: var(--action-bg);
  color: var(--action-ink);
  border-radius: var(--radius);
  padding: 0.04em 0.13em 0.09em;
  margin-left: -0.13em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* The rule itself: a key and its outcome on one row, ruled like everything else on the sheet.
   An outcome the rule does NOT assign is dropped to --ink-3 rather than tinted with --danger:
   "no category" is the instrument declining, not a run failing, and the two must not share a
   hue on a page where run state is the thing colour is reserved for. */
.crule { margin: 0 0 var(--s-4); border-top: 1px solid color-mix(in oklab, var(--action-mute) 39%, var(--rule)); }
.crule__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  padding: 5px 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  font-variant-numeric: tabular-nums;
}
.crule dt { color: var(--ink-3); }
.crule dd { margin: 0; color: var(--ink); text-align: right; }
.crule .crule__off { color: var(--ink-3); }

/* The rule is a transformation, and the card now prints it as one: the finding in mono on its
   own line, the reading it produces under it in Archivo, with a caption over the pair naming
   both sides ("findings becomes category"). The stacked pair replaced the two-column row
   because the columns read as a table of unrelated values — the reader could not tell which
   side the model extracts and which side the code decides. "becomes" is the only accent-tinted
   word in the band, and it is a caption, never a claim. Compounded under .syndromes for the
   same reason the rest of this block is: `.ledger p` would otherwise reset the caption. */
.syndromes .crule__cap {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  margin: 0 0 8px;
}
.syndromes .crule__cap-to { color: color-mix(in oklab, var(--action-mute) 70%, var(--ink-3)); }
.syndromes .crule__row { display: block; padding: 7px 0; }
.syndromes .crule dt { color: var(--ink-3); }
.syndromes .crule dd {
  text-align: left;
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: 1.35;
  margin-top: 2px;
}

/* The cards end at the rule. The prose that explained each contract, and the measured figure
   with its caveat, were cut on 2026-09-17: the column now prints the question and the rule and
   nothing else. The last row loses its bottom border because there is no longer anything under
   it for that line to divide — a rule with nothing beneath it reads as a dropped row. The
   .syn__m / .syn__src rules below stay: the Spanish twin still carries both. */
.syndromes .syn .crule { margin-bottom: 0; }
.syndromes .syn .crule .crule__row:last-child { border-bottom: 0; }

/* The measured line, and the line that says what it is not. They sit together because the
   figure is not publishable without the caveat under it — same rule as every other number on
   this page, given a class here so the pairing cannot drift apart in an edit. */
.syndromes .syn__m {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  border: 1px solid color-mix(in oklab, var(--action-mute) 65%, var(--rule));
  border-radius: var(--radius);
  padding: 3px 9px;
  margin-top: var(--s-4);
}
.syndromes .syn__src { color: var(--ink-3); font-size: var(--t-meta); margin-top: 4px; }

/* ---- The three-run comparison (#why) ----

   The three runs used to sit as equal ledger columns, which made the one claim the page is
   built on — 20 of 20 against 5 of 20 — read as a tidy table. They are unstacked here into
   full-content-width rows so the proportion is drawn at page scale: the shipped run's track
   spans the whole 1320px measure, the model alone reaches a third of the way across. The
   track is the only new object, and it is the meter bar at section weight; no new hue, no
   fill but the accent, no shadow. */

.runs { border-top: 1px solid var(--rule-accent); }
.run { --bar: 14px; padding-block: var(--s-5); border-top: 1px solid var(--rule); }
.run:first-child { border-top: 0; }

.run__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-5);
  flex-wrap: wrap;
  margin-bottom: var(--s-4);
}
.run__id { display: flex; align-items: baseline; gap: var(--s-4); flex-wrap: wrap; }
.run__k {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.run__name { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.018em; margin: 0; }

/* Display-size figure, so the accent clears the 3:1 a large value owes — the same exception
   .wf-tally__v already takes. It is never used at body size. */
.run__v {
  font-size: var(--t-stat);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.run--win .run__v { color: var(--action-bg); }

.run__track { height: var(--bar); background: var(--rule); }
.run__track > i {
  display: block;
  height: 100%;
  width: var(--w);
  background: var(--ink-3);
  transform-origin: left;
}
.run--win .run__track > i { background: var(--action-mute); }

.run__foot {
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 1fr);
  gap: var(--s-6);
  margin-top: var(--s-4);
  align-items: start;
}
.run__n {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.run__d { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; max-width: 74ch; }

/* The counter the hero's .tick means to be: counter-reset has to read the property the
   keyframe animates, not the target it animates towards. */
.cnt { --tick: var(--tick-to); counter-reset: cnt var(--tick); font-variant-numeric: tabular-nums; }
.cnt::after { content: counter(cnt); }

@media (max-width: 720px) { .run__foot { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); } }

/* ---- Surfaces (dashboard + report) ---- */

.surface {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  border-top: 1px solid var(--rule);
  padding-block: var(--s-7);
}
/* last-of-type, not last-child: a screenshot figure now follows the surfaces in this band. */
.surface:last-of-type { border-bottom: 1px solid var(--rule); }
.surface--reverse .surface__art { order: -1; }
.surface__body { display: grid; gap: var(--s-3); align-content: start; }
.surface__body h3 { font-size: clamp(1.375rem, 2vw, 1.75rem); font-weight: 600; letter-spacing: -0.025em; line-height: 1.15; margin-bottom: var(--s-1); }
.surface__body p { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.6; max-width: 56ch; }
.surface__foot { color: var(--ink-3) !important; font-family: var(--font-mono); font-size: var(--t-mono-sm) !important; margin-top: var(--s-2); font-variant-numeric: tabular-nums; }
@media (max-width: 900px) {
  .surface { grid-template-columns: minmax(0, 1fr); }
  .surface--reverse .surface__art { order: 0; }
}

.mock {
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--s-4);
  display: grid;
  gap: var(--s-4);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  background: var(--veil);
}
.mock__bar { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.mock__chip { border: 1px solid var(--rule); border-radius: var(--radius); padding: 2px 7px; color: var(--ink-3); }
.mock__chip.is-live { color: var(--ok); border-color: var(--ok); }
.mock__canvas { display: flex; align-items: center; gap: 0; flex-wrap: wrap; }
.mock__node {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 5px 9px; color: var(--ink-3);
}
.mock__node.is-done { color: var(--ink-2); }
.mock__node.is-done .mock__dot { background: var(--ok); }
.mock__node.is-live { color: var(--ink); border-color: var(--ink-3); }
.mock__node.is-live .mock__dot { background: var(--warn); }
.mock__dot { width: 4px; height: 4px; border-radius: 50%; background: var(--rule-strong); }
.mock__meta { color: var(--ink-3); }
.mock__wire { width: 16px; height: 1px; background: var(--rule-strong); flex: none; }
.mock__log { display: grid; gap: 4px; border-top: 1px solid var(--rule); padding-top: var(--s-3); color: var(--ink-3); }
.mock__log b { color: var(--ink-2); font-weight: 400; }
.mock__log i { font-style: normal; color: var(--ink-2); }

.mock--doc { gap: var(--s-3); }
.mock__line { height: 1px; background: var(--rule); }
.mock__line--h { height: 3px; background: var(--ink-3); width: 46%; }
.mock__line--s { width: 68%; }
.mock__chart { display: flex; align-items: flex-end; gap: 14px; height: 76px; margin-block: var(--s-3); }
.mock__chart span { flex: 0 1 26px; background: var(--rule-strong); border-radius: 1px; }
.mock__chart span.is-accent { background: var(--action-mute); }

/* ---- Product screenshots ----

   Real captures of the dashboard, taken against a live run rather than drawn in CSS. The
   frame is a rule and nothing else: a shadow would lift the image off a page that has no
   raised objects anywhere else in it.

   Two files per shot, one per theme, swapped here rather than by a <picture> media query —
   the theme is a data attribute this site sets itself, and prefers-color-scheme cannot see
   an explicit choice. The dark file is the default because the page is. */

.shot { margin: 0; display: grid; gap: var(--s-3); }

.shot__frame {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--veil);
  overflow: hidden;
  line-height: 0;
}
.shot__frame img { display: block; width: 100%; height: auto; }

/* Only one of the pair is ever in the flow. The class sits on the <picture>, not the
   <img> inside it, so the whole source set goes with it — and every rule below carries
   .shot__frame so that showing and hiding are decided at one specificity, not two. */
.shot__frame picture { display: none; }
.shot__frame .shot__img--dark { display: block; }
:root[data-theme="light"] .shot__frame .shot__img--dark { display: none; }
:root[data-theme="light"] .shot__frame .shot__img--light { display: block; }

.shot__cap {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.shot__cap b { color: var(--ink-2); font-weight: 400; }

/* The shot that sits under the hero: full wrap width, and the only thing in its band. */
.shotband { padding-block: var(--s-7); }
.shotband .shot__frame { border-color: var(--rule-strong); }

/* A surface whose art is a real screenshot stacks instead of splitting: a 1600px window
   scaled into a half column is a grey rectangle, and the whole point of the capture is that
   its detail can be read. The prose keeps its measure; the image takes the band. */
.surface--shot { grid-template-columns: minmax(0, 1fr); gap: var(--s-5); align-items: start; }
.surface--shot .surface__body { max-width: 68ch; }
.surface__art .shot { gap: var(--s-2); }

/* A shot that stands on its own inside a band of surfaces, below the last of them. */
.shot--log { margin-top: var(--s-7); }

/* On a phone the whole window scaled to 380px is a grey rectangle. Below this width the
   frame becomes the viewport instead: the capture holds a legible size and the reader
   swipes across it, which is the same bargain the wide code blocks in this page make. */
@media (max-width: 720px) {
  .shot__frame { overflow-x: auto; overscroll-behavior-x: contain; }
  .shot__frame img { width: 880px; max-width: none; }
}

/* ---- Fleet ---- */

.fleet { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(32px, 5vw, 72px); align-items: start; }
@media (max-width: 900px) { .fleet { grid-template-columns: minmax(0, 1fr); } }

.fleet__diagram { display: grid; grid-template-columns: minmax(0, 1fr) 72px minmax(0, 0.9fr); align-items: center; gap: 0; }
.fleet__host { display: grid; gap: var(--s-2); }
.fleet__k { font-family: var(--font-mono); font-size: var(--t-mono-sm); color: var(--ink-3); margin-bottom: var(--s-1); }
.fleet__box {
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 9px 11px;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  color: var(--ink-2);
  display: grid; gap: 2px;
}
.fleet__box span { color: var(--ink-3); }
/* The entry point is the one filled object in this section, the way the CTA is in the hero. */
.fleet__box--action {
  background: var(--action-bg);
  border-color: var(--action-bg);
  color: var(--action-ink);
}
.fleet__box--action span { color: var(--action-ink); opacity: 0.72; }
.fleet__wires { height: 100%; min-height: 150px; }
.fleet__wires svg { width: 100%; height: 100%; }
.fleet__servers { display: grid; gap: var(--s-4); }
.fleet__server {
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 9px 11px;
  display: grid; gap: 2px;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
}
.fleet__server b { color: var(--ink); font-weight: 500; }
.fleet__server span { color: var(--ink-2); }
.fleet__server i { font-style: normal; color: var(--ink-3); display: block; }
@media (max-width: 620px) {
  .fleet__diagram { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .fleet__wires { display: none; }
}

.fleet__list { display: grid; gap: 0; border-top: 1px solid var(--rule); }
.fleet__list li { border-bottom: 1px solid var(--rule); padding-block: var(--s-4); display: grid; gap: 5px; }
.fleet__list .note__k { font-size: var(--t-mono); }
.fleet__list p:last-child { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; }

/* A surface that follows a full-width shot inside the same band. */
.surface--after-shot { margin-top: var(--s-7); }

/* ---- The sample: one note beside the assessment it produced ----
   The note sits on the veil because it is source material, like a log pane; the assessment is
   ruled rows on the ground, the same ledger the rest of the page uses. A quoted phrase is
   underlined in ink, never filled: the accent is not text, and a highlighter fill would be a
   second accent. */
.sample {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.sample__k {
  margin: 0 0 var(--s-4);
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.sample__note {
  margin: 0;
  background: var(--veil);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--s-5);
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  line-height: 1.7;
  color: var(--ink-2);
}
.sample__note p + p { margin-top: var(--s-3); }
.sample__note mark {
  background: none;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.sample__note s { color: var(--ink-3); }
.sample__vitals {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2) var(--s-5);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--rule-accent);
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.sample__vitals b { color: var(--ink); font-weight: 500; }
.sample__by { color: var(--ink-3); font-size: var(--t-mono-sm); }
.sample__rows { margin: 0; }
.sample__row {
  display: grid;
  grid-template-columns: minmax(0, 150px) minmax(0, 1fr);
  column-gap: var(--s-5);
  row-gap: var(--s-1);
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--rule);
}
.sample__row dt { grid-row: span 3; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.sample__row dd { margin: 0; grid-column: 2; }
.sample__v { font-family: var(--font-mono); font-size: var(--t-mono); color: var(--ink); font-variant-numeric: tabular-nums; }
.sample__d { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; }
.sample__miss { color: var(--ink-3); font-size: var(--t-mono-sm); font-family: var(--font-mono); line-height: 1.5; }
.sample__foot { margin-top: var(--s-4); color: var(--ink-3); font-size: var(--t-mono-sm); font-family: var(--font-mono); }
@media (max-width: 900px) { .sample { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 520px) {
  .sample__row { grid-template-columns: minmax(0, 1fr); }
  .sample__row dt { grid-row: auto; }
  .sample__row dd { grid-column: 1; }
}

/* ---- Specs: four facts on the ledger, a short value over a sentence ---- */
.specs { margin: 0; }
.specs dt { font-family: var(--font-mono); font-size: var(--t-mono-sm); letter-spacing: 0.04em; color: var(--ink-3); }
.specs dd { margin: 0; color: var(--ink-2); font-size: var(--t-meta); line-height: 1.55; }
.specs .specs__v { margin: var(--s-2) 0 var(--s-2); color: var(--ink); font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.015em; }

/* ---- Questions: ruled rows that open in place ---- */
.faq { border-top: 1px solid var(--rule); max-width: 860px; }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  padding-block: var(--s-4);
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--ink-3);
}
.faq details[open] summary::after { content: "\2212"; }
.faq summary:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.faq summary:focus-visible { outline: 2px solid var(--action-bg); outline-offset: 2px; }
.faq details p { padding-bottom: var(--s-5); max-width: 68ch; color: var(--ink-2); font-size: var(--t-body); line-height: 1.6; }

/* ==========================================================================
   7. Footer
   ========================================================================== */

.footer { border-top: 1px solid var(--rule-accent); padding-top: var(--s-7); padding-bottom: var(--s-6); }
.footer__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: var(--s-6);
  align-items: start;
}
.footer__brand { display: grid; gap: var(--s-3); justify-items: start; }
.footer__brand p { color: var(--ink-2); font-size: var(--t-meta); max-width: 42ch; }
.brand--footer .brand__mark { width: 78px; height: 26px; }
.brand--footer .brand__star { width: 18px; height: 15px; }

.footer__cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-5); }
.footer__cols > div { display: grid; gap: 7px; align-content: start; }
.footer__cols a { font-size: var(--t-meta); color: var(--ink-2); text-decoration: none; width: fit-content; }
.footer__cols a:hover { color: var(--ink); box-shadow: inset 0 -1px 0 currentColor; }
.footer__k { font-family: var(--font-mono); font-size: var(--t-mono-sm); color: var(--ink-3); letter-spacing: 0.05em; margin-bottom: var(--s-1); }

.footer__disclaimer {
  border-top: 1px solid var(--rule);
  margin-top: var(--s-7);
  padding-top: var(--s-5);
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 1fr);
  gap: var(--s-6);
}
.footer__disclaimer p { color: var(--ink-2); font-size: var(--t-meta); line-height: 1.6; max-width: 76ch; }
.footer__disclaimer strong { color: var(--ink); }

.footer__base {
  border-top: 1px solid var(--rule);
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  display: flex;
  justify-content: space-between;
  gap: var(--s-5);
  flex-wrap: wrap;
}
.footer__base p { color: var(--ink-3); font-size: var(--t-mono-sm); font-family: var(--font-mono); }
.footer__base strong { color: var(--ink-2); font-weight: 500; }

@media (max-width: 780px) {
  .footer__inner, .footer__disclaimer { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   8. Motion — one authored moment (the hero run), one quiet arrival elsewhere
   ========================================================================== */

@property --tick { syntax: "<integer>"; initial-value: 0; inherits: false; }

.tick { counter-reset: tick var(--tick-to); font-variant-numeric: tabular-nums; }
.tick::after { content: counter(tick); }

@keyframes tick-up { from { --tick: 0; } to { --tick: var(--tick-to); } }
@keyframes wipe-up { from { opacity: 0; transform: translateY(0.26em); } to { opacity: 1; transform: none; } }
@keyframes row-in  { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes rule-draw { from { transform: scaleX(0); } to { transform: none; } }
@keyframes sb-grow  { from { opacity: 0; transform: scale(0.2); } }
@keyframes sb-focus { from { opacity: 0; filter: blur(6px); transform: scale(0.8); } }
@keyframes sb-field { from { opacity: 0; transform: scale(0.92); } }
@keyframes sb-in    { from { opacity: 0; } }

@media (prefers-reduced-motion: no-preference) {
  /* The headline arrives line by line, the lede and the action follow, and the run card's
     four rows land as a wavefront with their elapsed times counting up under them. One
     clock, authored once — nothing else on the page animates on entrance. */
  .hero__head span { animation: wipe-up 0.9s var(--ease) both; }
  .hero__head span:nth-child(2) { animation-delay: 0.09s; }
  .hero__head span:nth-child(3) { animation-delay: 0.18s; }
  /* The bar draws left to right once the three lines are down — the one stroke that closes
     the headline, on the same clock as everything else. */
  .hero__bar { transform-origin: left; animation: rule-draw 0.9s var(--ease) 0.34s both; }
  .hero__copy > * { animation: wipe-up 0.8s var(--ease) 0.46s both; }
  .hero__cta { animation: wipe-up 0.8s var(--ease) 0.56s both; }

  .synboard, .herofilm { animation: wipe-up 0.7s var(--ease) 0.3s both; }
  /* The board nests as it arrives: the field settles, the four screens grow out of its
     centre to their places, and the narrower claims come into focus inside them last —
     the order a reader should take them in. */
  .sb-field { transform-box: fill-box; transform-origin: center; animation: sb-field 0.7s var(--ease) 0.2s both; }
  .sb-node:not(.sb-node--deep) {
    transform-box: view-box; transform-origin: 360px 330px;
    animation: sb-grow 0.8s var(--ease) calc(0.4s + var(--i) * 0.05s) both;
  }
  .sb-node--deep {
    transform-box: fill-box; transform-origin: center;
    animation: sb-focus 0.6s var(--ease) calc(1s + var(--i) * 0.05s) both;
  }
  .sb-case { animation: sb-in 0.6s ease 1.3s both; }
  .synboard figcaption { animation: wipe-up 0.7s var(--ease) 1.1s both; }
  .rstep { animation: row-in 0.62s var(--ease) calc(0.5s + var(--i) * 0.16s) both; }

  .tick { animation: tick-up 1s var(--ease) calc(0.56s + var(--i, 0) * 0.16s) both; }

  .reveal { opacity: 0; transform: translateY(14px); }
  .reveal.is-in { opacity: 1; transform: none; transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); }

  /* #why's comparison opts out of the block-level reveal and spends it on the rows instead:
     three tracks draw left to right in sequence and their figures count up under them, so
     the gap is read as it is drawn. One moment, on the page's own clock. */
  .runs.reveal { opacity: 1; transform: none; transition: none; }
  .runs.reveal .run { opacity: 0; }
  .runs.is-in .run { animation: row-in 0.7s var(--ease) calc(0.05s + var(--i) * 0.16s) both; }
  .runs.is-in .run__track > i { animation: rule-draw 1.15s var(--ease) calc(0.24s + var(--i) * 0.16s) both; }
  /* The animation goes on the counting span itself: --tick is registered inherits:false, so
     animating it on the enclosing <p> leaves the span reading the 0 initial value. */
  .runs.is-in .cnt { animation: tick-up 1.15s var(--ease) calc(0.24s + var(--i) * 0.16s) both; }

  /* The premise ledger spends its block reveal on the marks instead: each article lands, then
     its rules draw left to right in the order the run makes them. rule-draw's backwards fill
     is what holds them at zero width until the section arrives. */
  .ledger--figs.reveal { opacity: 1; transform: none; transition: none; }
  .ledger--figs.is-in > article { animation: row-in 0.7s var(--ease) calc(var(--i) * 0.12s) both; }
  .ledger--figs.is-in .pfig line { animation: rule-draw 0.5s var(--ease) calc(0.22s + var(--i) * 0.12s + var(--j) * 0.09s) both; }
}

/* ==========================================================================
   8b. #how, played back — the page's second authored moment
   ==========================================================================

   The first is the hero: one run lands, four rows, the counters under them. This one is the
   nine steps of that run PLAYING. It is the only other place on the page where motion is
   authored rather than quiet, and it is authored because the subject is sequence — what each
   step is handed and who decided it — which a reader gets from watching it happen and does not
   get from nine blocks stacked down a page.

   Three parts, one clock:

   1. THE STRIP IS THE TRACK. Each pip fills over its step's dwell (--dwell, set per step from
      the script), holds a dim fill once walked, and sits empty ahead of the playhead. Pausing
      is `animation-play-state: paused`, so the bar freezes exactly where the eye left it and
      resumes from there rather than restarting.

   2. EVERY STEP IS A SCENE. On becoming current a step choreographs its own contents in the
      order the run produces them: the sentence, then the panel, then the panel's rows, then
      the marks on those rows. Each scene is under 1.8s inside a dwell of 8, so a reader who
      pauses immediately still sees a finished frame.

   3. THE CUT IS DIRECTIONAL. Rows enter from the side the run is travelling (--dir, +1 going
      forward and -1 going back), so stepping backwards reads as rewinding rather than as nine
      identical entrances.

   Nothing here autoplays for a reader who asked for less motion: the whole block is in the
   no-preference query, and with it inactive the section is the stepper it always was. */

@keyframes pip-sweep  { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes scene-up   { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
@keyframes scene-row  { from { opacity: 0; transform: translateX(calc(var(--dir, 1) * 12px)); } to { opacity: 1; transform: none; } }
@keyframes scene-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes tick-draw  { from { stroke-dashoffset: 28; } to { stroke-dashoffset: 0; } }
@keyframes print-out  { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes wipe-right { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes mark-draw  { from { background-size: 0 1px; } to { background-size: 100% 1px; } }
@keyframes thr-drop   { from { opacity: 0; transform: translateY(-7px); } to { opacity: 1; transform: none; } }
@keyframes dot-land   { from { opacity: 0; transform: translateX(-50%) scale(0.2); } to { opacity: 1; transform: translateX(-50%) scale(1); } }
@keyframes mark-rise  { from { opacity: 0; transform: scaleY(0); } to { opacity: 1; transform: none; } }
@keyframes strike-in  { from { text-decoration-color: transparent; } to { text-decoration-color: var(--danger); } }

@media (prefers-reduced-motion: no-preference) {

  /* -- 1. The playhead ---------------------------------------------------- */

  .hiw.is-playing .hiw__pip[aria-current="step"] i::after {
    animation: pip-sweep var(--dwell, 8s) linear both;
  }
  .hiw.is-playing.is-paused .hiw__pip[aria-current="step"] i::after { animation-play-state: paused; }

  /* -- 2. The scene ------------------------------------------------------- */

  /* The sentence first, its own lines in reading order, then the panel beside it. */
  .hiw__step.is-current .hiw__said > *  { animation: scene-up 0.55s var(--ease) both; }
  .hiw__step.is-current .hiw__said > :nth-child(2) { animation-delay: 0.06s; }
  .hiw__step.is-current .hiw__said > :nth-child(3) { animation-delay: 0.12s; }
  .hiw__step.is-current .hiw__said > :nth-child(4) { animation-delay: 0.18s; }
  .hiw__step.is-current .hiw__shown > * { animation: scene-up 0.55s var(--ease) 0.1s both; }

  /* Rows land as a wavefront, the way the hero's run card lands. */
  .hiw .rsteps .rstep:nth-child(1), .hiw .hiw__frow:nth-child(1), .hiw .hiw__qrow:nth-child(1) { --i: 0; }
  .hiw .rsteps .rstep:nth-child(2), .hiw .hiw__frow:nth-child(2), .hiw .hiw__qrow:nth-child(2) { --i: 1; }
  .hiw .rsteps .rstep:nth-child(3), .hiw .hiw__frow:nth-child(3), .hiw .hiw__qrow:nth-child(3) { --i: 2; }
  .hiw .rsteps .rstep:nth-child(4), .hiw .hiw__frow:nth-child(4), .hiw .hiw__qrow:nth-child(4) { --i: 3; }
  .hiw .rsteps .rstep:nth-child(5), .hiw .hiw__frow:nth-child(5), .hiw .hiw__qrow:nth-child(5) { --i: 4; }

  .hiw__step.is-current .rsteps .rstep,
  .hiw__step.is-current .hiw__frow,
  .hiw__step.is-current .hiw__qrow {
    animation: scene-row 0.5s var(--ease) calc(0.26s + var(--i, 0) * 0.1s) both;
  }
  /* A row's verdict is the last thing to arrive, because in the run it is the last thing
     decided — the name of the check is not news, the answer is. */
  .hiw__step.is-current .rsteps .rstep__state,
  .hiw__step.is-current .rsteps .rstep__t {
    animation: scene-fade 0.34s var(--ease) calc(0.46s + var(--i, 0) * 0.1s) both;
  }

  /* Ticks and crosses draw rather than appear: a check is an act, not a label. */
  .hiw__step.is-current .hiw__frow svg path,
  .hiw__step.is-current .hiw__qrow svg path {
    stroke-dasharray: 28;
    animation: tick-draw 0.4s var(--ease) calc(0.44s + var(--i, 0) * 0.1s) both;
  }
  /* Where the phrase was found in the note, marked after the tick that says it was found. */
  .hiw__step.is-current .hiw__where i {
    transform-origin: center;
    animation: mark-rise 0.36s var(--ease) calc(0.56s + var(--i, 0) * 0.1s) both;
  }
  /* The deleted reading is struck last, after the three that survived have been ticked. */
  .hiw__qrow--gone .hiw__phrase { text-decoration-color: transparent; }
  .hiw__step.is-current .hiw__qrow--gone .hiw__phrase {
    animation: strike-in 0.3s linear 0.86s both;
  }

  /* The instrument takes its reading: the axis draws, the bad side of the line fills from the
     line outward, the threshold drops onto it, and the value lands last. Two gauges, one after
     the other, because they are two separate recomputations. */
  .hiw__gauge:nth-of-type(1) { --g: 0; }
  .hiw__gauge:nth-of-type(2) { --g: 1; }
  .hiw__step.is-current .hiw__gnum  { animation: scene-up 0.5s var(--ease) calc(0.6s + var(--g, 0) * 0.42s) both; }
  .hiw__step.is-current .hiw__axis  { transform-origin: left; animation: rule-draw 0.6s var(--ease) calc(0.2s + var(--g, 0) * 0.42s) both; }
  .hiw__step.is-current .hiw__zone  { transform-origin: left; animation: rule-draw 0.5s var(--ease) calc(0.42s + var(--g, 0) * 0.42s) both; }
  .hiw__step.is-current .hiw__thr   { animation: thr-drop 0.4s var(--ease) calc(0.52s + var(--g, 0) * 0.42s) both; }
  .hiw__step.is-current .hiw__thrlab { animation: scene-fade 0.4s var(--ease) calc(0.58s + var(--g, 0) * 0.42s) both; }
  .hiw__step.is-current .hiw__dot   { animation: dot-land 0.46s var(--ease) calc(0.66s + var(--g, 0) * 0.42s) both; }
  .hiw__step.is-current .hiw__verdict { animation: scene-fade 0.4s var(--ease) calc(0.82s + var(--g, 0) * 0.42s) both; }

  /* One slot, in the order the run uses it: the first server appears, is swept, and the second
     takes the space it left. Wiped in from the left rather than faded, so the lane reads as time
     passing rather than as two boxes arriving together. */
  .hiw__step.is-current .slot__blk:first-of-type { animation: wipe-right 0.5s var(--ease) 0.28s both; }
  .hiw__step.is-current .slot__gap { animation: scene-fade 0.36s var(--ease) 0.82s both; }
  .hiw__step.is-current .slot__blk:last-of-type { animation: wipe-right 0.5s var(--ease) 1s both; }
  .hiw__step.is-current .slot__axis span:first-child { animation: scene-fade 0.4s var(--ease) 0.6s both; }
  .hiw__step.is-current .slot__axis span:last-child { animation: scene-fade 0.4s var(--ease) 1.3s both; }

  /* The dictation and the ending page print rather than fade — top line first, the way both of
     them actually reach a person. Then the quoted phrase in the note underlines itself, which
     is the one thing step 1 is asking the reader to hold on to for eight steps. */
  .hiw__step.is-current .snippet--plain .code { animation: print-out 0.75s var(--ease) 0.22s both; }
  .hiw__step .code--wrap mark {
    box-shadow: none;
    background-image: linear-gradient(var(--action-bg), var(--action-bg));
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0 1px;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
  }
  .hiw__step.is-current .code--wrap mark { animation: mark-draw 0.6s var(--ease) 0.95s both; }
}

/* The theme swap is a change of ground under everything, so it crosses rather than snaps
   where the browser can do it. 0.32s: long enough to read as one surface replacing another,
   short enough that the control still feels instant. */
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: 0.32s;
  animation-timing-function: var(--ease);
}

@media print {
  .topbar, .copy-btn { display: none; }
  body { background: #fff; color: #000; }
}
