/* SaveMeTibo — Evidence Flight Recorder.
   Tokens and rules are owned by web/DESIGN.md. Two hues only: amber appears
   solely while a WATCH is open, cyan marks evidence that resolved. Everything
   else is grey ink. No shadow, no glow, no gradient — depth is plane
   separation and rule weight. No third-party font is loaded. */

:root {
  color-scheme: dark;

  --bg: #0A0C0E;
  --panel: #11151A;
  --panel-raised: #151B21;
  --rule: #1E262D;
  --rule-strong: #2A343C;

  --ink: #E4EAEE;
  /* the pressed/hover step above --ink. A neutral, not a hue, so it does
     not spend against the two-hue rule. */
  --ink-hi: #FFFFFF;
  /* --ink-2 and --ink-3 were 14 luminance points apart — one grey doing two
     jobs, which is why nothing below the hero had tonal hierarchy. --ink-2
     carries body content (.ro-changed, .lr-head) and was dimmer than its job,
     so it moves up. --ink-3 does not move: 20 uses at 10-13px already sit near
     the AA floor, and pulling the smallest type down to widen the gap is the
     wrong end to pull. */
  --ink-2: #AFB8BE;
  --ink-3: #85929B;

  --trace-quiet: #5B6870;
  --primary: #F2A63B;
  --watch-deep: #7A5520;
  --resolved: #6FD3E8;
  --resolved-deep: #2C5967;
  /* The receipt rail — the 2px edge that means "this is what backs the reading"
     — was `--resolved-deep`, which measures **2.55** against the page ground and
     **2.44** on a plate: under the 3.0 non-text floor in both places, on the one
     mark this world uses to say a source is evidence. It is its own token now
     rather than a fourth job for `--resolved-deep`, which also underlines
     receipt labels and fills a pipeline tick and should not be dragged brighter
     for those. One token for one mark, and the event page and the readout stay
     the same rail. Measured after: 3.53 on the ground, 3.34 on a plate. */
  --rail: #35707F;

  /* Hill picked the grotesque of the earlier build over SF Pro. Inter is not
     loaded — it is only used where the reader already has it; everyone else
     lands on Helvetica Neue / Arial / Roboto, which are the same neutral
     grotesque rather than a humanist fallback. No webfont request is made. */
  --sans: Inter, "Helvetica Neue", Helvetica, Arial, Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --max: 1180px;
  /* The page measure is min(100% - 2*gutter, --max), and the gutter was a
     flat 16px. Above --max that is invisible, but between 901px and
     1276px the measure is width-bound and every band on the page — hero
     included — ran to a 16px edge, which is a phone's gutter on a
     desktop window. One token, so the bands cannot drift apart. */
  --gut: 16px;
  /* the phone's artwork band — art, scrim and masthead padding all read it */
  --art-band: 340px;
  --tap: 44px;
  --s-xs: 8px;
  --s-sm: 12px;
  --s-md: 18px;
  --s-lg: 26px;
  --s-xl: 40px;
  --s-2xl: 64px;
  /* Every gap below the hero was 64px except the CTA at 40px, so nothing read
     as a new chapter — not even evidence -> trace, which is where the page stops
     answering and starts showing its work. One larger interval, continuing the
     scale's own ~1.6 ratio. */
  --s-3xl: 104px;
}

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

[hidden] { display: none !important; }

html { background: var(--bg); }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--resolved);
  outline-offset: 3px;
}

.skip-link {
  position: fixed;
  inset-inline-start: var(--s-sm);
  inset-block-start: var(--s-xs);
  z-index: 30;
  transform: translateY(-160%);
  padding: var(--s-sm) var(--s-md);
  background: var(--ink);
  color: var(--bg);
  font-weight: 640;
}
.skip-link:focus { transform: translateY(0); }

.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s-sm);
  margin: 0;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.eyebrow i { flex: 1; height: 1px; background: var(--rule-strong); }

.section-head { margin-bottom: var(--s-lg); }
/* The `section` role. This size existed in the CSS and DESIGN.md never named it,
   which is how it stayed at 1.4rem while the hero grew to clamp(4.5rem, 11vw,
   8.5rem). It is up, and still nowhere near competing with the figure. */
.section-head h2 {
  margin: var(--s-sm) 0 0;
  max-width: 30ch;
  font-size: clamp(1.625rem, 3.4vw, 2.5rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
/* The `lede` role. Nothing existed between 16.8px and 22.4px, so a heading sat
   only ~1.4x above its own body copy at the small end and every section below
   the fold had to carry its hierarchy on letter-spacing alone. */
.lede {
  margin: var(--s-sm) 0 0;
  max-width: 52ch;
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  line-height: 1.45;
  color: var(--ink-2);
}

/* ---------------------------------------------------------------- header */

/* The header rides on the masthead picture, and measured contrast decided how.
   A gradient scrim big enough to carry 11px mono over sunlit cloud (nav came
   back at 1.89:1) would have been a black wash across the sky. A translucent
   rail is smaller, honest, and the picture still moves behind it — the bezel
   floats on the sky instead of covering it. Every label stays engraved. */
.site-head {
  display: flex;
  align-items: center;
  gap: var(--s-md);
  flex-wrap: wrap;
  width: 100%;
  padding: var(--s-md) max(var(--gut), calc(50% - var(--max) / 2));
  background: rgba(8, 9, 12, 0.68);
  border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
@supports (backdrop-filter: blur(1px)) {
  .site-head {
    background: rgba(8, 9, 12, 0.6);
    backdrop-filter: blur(16px) saturate(115%);
  }
}

/* Small chrome on the masthead sits on a painting, not on a panel, so it
   carries a lighter ink than the same labels do everywhere else. Measured,
   not guessed: --ink-3 came back at 1.70:1 over sunlit cloud. */
.masthead .tagline,
.masthead .site-head nav a,
.masthead .live-chip,
.masthead .ro-figure small {
  color: #CBD5DA;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: var(--tap);
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.035em;
}
/* the product's own artwork carries the header — a mascot, not a glyph.
   Square and unrounded so it sits on the panel like a sticker, not a chip. */
.brand-mark {
  width: 44px;
  height: 44px;
  flex: none;
  display: block;
}

/* the positioning line is locked copy (brief v3) but it is not the answer, so
   it sits with the mark, engraved, and lets the artwork lead */
.tagline {
  margin: 0;
  padding-inline-start: var(--s-md);
  border-inline-start: 1px solid var(--rule-strong);
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.site-head nav { display: flex; gap: var(--s-md); margin-inline-start: auto; }
.site-head nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  border-bottom: 1px solid transparent;
}
.site-head nav a:hover { color: var(--ink); border-bottom-color: var(--rule-strong); }

.live-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  border: 1px solid var(--rule-strong);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.live-chip::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--resolved);
}
.is-stale .live-chip::before { background: var(--watch-deep); }

/* The measure moved off main and onto its sections (2026-08-12): the masthead
   is a full-bleed picture, and a page that wants one full-bleed band cannot
   put its rail on the container. Everything else keeps the 1180px measure. */
/* No padding-bottom here. `footer` carries `margin-top: var(--s-3xl)` and this
   rule added 64px on top of it, so the interval before the foot measured 167px
   at every viewport — the largest gap on the page, in the one place the page has
   stopped talking, and a value nobody chose. Same class of defect as the
   `body { padding-bottom: 92px }` the body round removed: two rules spacing the
   same seam without knowing about each other. The chapter interval is one token. */
main {}
/* `main > .stale-banner` used to close this list and never matched anything:
   the banner is a child of .masthead, not of main (public_status.py). */
main > .evidence,
main > .trace,
main > .signal-desk,
main > .more,
main > .clock,
main > .proof,
main > .recent,
main > .method {
  width: min(calc(100% - 2 * var(--gut)), var(--max));
  margin-inline: auto;
}
/* .cta-band left this list on 2026-08-17: it is full-bleed now and carries the
   measure as inner padding instead, the way .site-head and .stale-banner do. */

/* ------------------------------------------------------------ the tape */

/* The chapter break. Above this line the page answers a question; below it the
   page shows its work. That deserves a bigger interval than the one between two
   sections of working-out. */
.trace { margin-top: var(--s-3xl); }

.deck {
  border: 1px solid var(--rule-strong);
  background: var(--panel);
}

/* The 42 quiet days are 5px marks sitting 26px above .tape's bottom border, so
   they read as a dashed line floating in space — a broken loading bar rather
   than "the recorder was running and nothing happened". A hairline at the bars'
   own baseline puts them on a ruled axis. `.tape`'s bottom border cannot do this
   job: it is below the padding, which is what the week gridlines are measured
   against. Excluded inside a log row, where padding is 0 and the border already
   lands on the baseline. */
.lane .tape::after {
  content: "";
  position: absolute;
  inset-inline: var(--pad);
  bottom: var(--floor);
  height: 1px;
  background: var(--rule-strong);
  pointer-events: none;
}

.lane { display: block; min-width: 0; }
.lane + .lane { border-top: 1px solid var(--rule); }

/* a legend, because a mark's height and hue are the whole reading and nobody
   is born knowing them */
.legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-xs) var(--s-lg);
  margin: var(--s-md) 0 0;
  padding: 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-2);
}
.legend li { display: flex; align-items: center; gap: 8px; }
/* The key carries its own palette rather than borrowing the chart's, because the
   chart's paint is scoped to `.tape` — it has to be, to sit above the button
   reset (see the tape block). Stating it twice is the honest cost of that: a
   swatch is a reading of a mark, not a copy of one, which is already true of
   every height here, and the alternative was a key that silently changed shape
   whenever the chart's specificity moved. */
.legend .tk {
  position: static;
  flex: none;
  width: 9px;
  max-width: none;
  height: 16px;
  background: var(--trace-quiet);
  opacity: 0.55;
}
.legend .tk-watch { background: var(--primary); opacity: 1; }
.legend .tk-confirmed, .legend .tk-landed { background: var(--resolved); opacity: 1; }
.legend .tk-cooled { background: var(--watch-deep); opacity: 1; }
.legend .tk-retracted {
  opacity: 1;
  background: repeating-linear-gradient(
    45deg, var(--trace-quiet) 0 2px, transparent 2px 4px);
}
.legend .tk-watch, .legend .tk-cooled { height: 10px; }
.legend .tk-retracted { height: 12px; }
/* The swatch teaches the mark, not the cell. On the tape "a reset landed" is
   the tick below the axis, and this legend already shows heights that are
   readings rather than reproductions — so the swatch IS the tick. Written here
   rather than asking the renderer for `tk-reset-day` on an <i> that has no axis
   to hang under. */
.legend .tk-reset {
  box-sizing: border-box;
  height: 5px;
  padding: 0;
  margin: 0;
  opacity: 1;
  background: var(--ink-3);
  background-image: none;
}

.lane-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: var(--s-lg) var(--s-lg) var(--s-sm);
}
.lane-head b { font-size: 0.875rem; font-weight: 640; letter-spacing: 0.01em; }
.lane-qual {
  font-size: 0.625rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* the trace sits on the floor of the lane and the space above it is chart
   headroom, so bar heights are absolute: a taller lane must never inflate a
   mark into meaning something bigger than it is */
/* --pad and --floor exist because four things have to agree on where the chart
   ends: the bars' feet (this padding), the axis hairline, the playhead, and the
   week gridlines. They were four hard-coded `--s-lg`s, and the phone override
   moved only ONE of them — so at 390 the "bars' own baseline" hairline floated
   14px above the bars and the gridlines were inset 8px further than the track.
   One token per edge; a breakpoint retunes the token, not four call sites. */
.tape {
  --bar: 190px;
  --days: 42;
  --pad: var(--s-lg);
  --floor: var(--s-lg);
  position: relative;
  flex: 1;
  display: grid;
  grid-template-columns: repeat(var(--days), 1fr);
  align-items: end;
  min-height: calc(var(--bar) + 14px);
  padding: 0 var(--pad) var(--floor);
  border-bottom: 1px solid var(--rule-strong);
  /* week rules behind the trace: real boundaries, so the eye can count
     "that was two weeks ago" without reading the axis. They run the full
     height of the chart like any gridline — an earlier build faded them out
     at the top, which also silently ate the tops off every mark. */
  background-image:
    repeating-linear-gradient(
      90deg,
      transparent 0 calc((100% - var(--pad) * 2) / 6 - 1px),
      var(--rule) calc((100% - var(--pad) * 2) / 6 - 1px)
        calc((100% - var(--pad) * 2) / 6));
  background-position: var(--pad) 0;
  background-size: calc(100% - var(--pad) * 2) 100%;
  background-repeat: no-repeat;
}
.lane-claude .tape { --bar: 140px; }

/* PREMISE, and the reason every rule below is written `.tape .tk-<state>` rather
   than `.tk-<state>`: a mark's paint IS its data, and the marks are <button>s,
   so they carry `.ex` — the text-button reset — whose `background: none` and
   `border: 0` sit 1,800 lines further down at the same (0,1,0) weight and win
   on order alone. That shipped: measured on savemetibo.com against
   styles-13bb278e0b8b.css, NINE of the ten bars on the live tape computed
   `background-color: rgba(0,0,0,0)` — six confirmed resets at 190px and three
   watches at 91px, all invisible, plus their caps, which take `background:
   inherit`. The one bar a visitor could see was the single non-interactive
   <span>. The page promised "the last six weeks, as recorded", printed a legend
   teaching a cyan "Reset confirmed", said "tap a lit mark", and drew an empty
   strip. `height` survived because `.ex` never sets it, which is why every
   sweep passed: the class audit saw `.tk-confirmed` styled (it was — just
   outspecified), the contrast harness measures text, the hit-test measures
   geometry, and "caps equal to bars" was true with both at zero ink.

   Third instance of one failure: a rule that was right for the markup it was
   written against and silently wrong once the markup moved under it. Marks were
   <a>, then <button>; `.ex` was written for buttons with text in them.

   Out-specifying is the fix rather than splitting `.ex`, for two reasons. `.ex`
   is shared with 22 other buttons, and — measured, not assumed — taking the
   author background off a mark does not leave it transparent, it leaves the UA
   `ButtonFace` showing through as rgb(107,107,107): a plausible mid-grey bar,
   which is worse than a missing one because it looks like data.

   The weight comes from `.tape ` and NOT from doubling the class, which was the
   first attempt and broke the legend in one pass: `.tk.tk-watch` also outranks
   `.legend .tk-watch`, so a swatch inherited `height: calc(var(--bar) * .48)`
   with no `--bar` in scope, computed invalid, and every legend swatch collapsed
   to nothing. Scoping says the true thing instead — this is how a mark paints
   INSIDE the tape — and leaves the legend's swatches, which are readings rather
   than reproductions, to their own block. Neither selector names an element
   type, and the renderer emits `f"tk tk-{state}"` inside `.tape` as one string,
   so the premise cannot come apart the way `a.tk-link + a.tk-link` did.

   Asserted from the harness side too: no `.tape > .tk` may compute to a
   transparent background with no background-image, and `.tk-retracted` must
   keep its 1px border-top — `.ex { border: 0 }` eats that one, and no retracted
   mark is in the current window to show it. */
.tape .tk-quiet,
.tape .tk {
  position: relative;
  justify-self: center;
  width: 100%;
  max-width: 13px;
  height: 5px;
  background: var(--trace-quiet);
  opacity: 0.55;
}
.tape .tk-watch { height: calc(var(--bar) * 0.48); background: var(--primary); opacity: 1; }
.tape .tk-confirmed,
.tape .tk-landed { height: var(--bar); background: var(--resolved); opacity: 1; }
.tape .tk-cooled { height: calc(var(--bar) * 0.48); background: var(--watch-deep); opacity: 1; }
.tape .tk-retracted {
  height: calc(var(--bar) * 0.64);
  opacity: 1;
  background: repeating-linear-gradient(
    45deg, var(--trace-quiet) 0 2px, transparent 2px 4px);
  border-top: 1px solid var(--trace-quiet);
}
.tape .tk-experimental { height: 5px; }

/* ------------------------------------------- the record, below the axis line

   Two registers, and the line between them is the argument. ABOVE it is OUR
   record — five states, a height and a hue, unchanged. BELOW it is THE RECORD:
   one identical mark on every day a reset landed, whether we called it or not.
   That is the whole repair. The strip used to draw nine marks while the archive
   under it counted sixteen resets in the same six weeks, and nothing on the page
   reconciled them.

   Why one token and not two. `.tk-reset-day` rides on any cell that carries a
   reset — fifteen of forty-two here — and eight of those are `.tk-reset`, a day
   the vendor reset and we published nothing. The deck note now says out loud
   "16 confirmed resets, and every one is marked here … we published nothing on
   8 of those days", and a reader can only check that sentence if all fifteen
   marks are the SAME mark. Give the silent days their own distinct bar and the
   series stops being countable — the page would still be under-reporting, just
   more subtly. So the reset mark never varies, and what varies is whether one of
   our bars stands above it.

   Which makes `.tk-reset` itself correct as a quiet tick: our record for that
   day IS empty, and eight ticks with nothing above them is exactly the claim.

   Hueless, necessarily and rightly. Amber is an open watch and nothing else,
   cyan is evidence that resolved one of ours; a reset we never spoke about is
   neither, and `--ink-3` is the ink the axis labels under it already use — the
   record's own register, at the record's own weight. Same reasoning that keeps
   a retraction and a late lead hueless: not our signal, not a third colour.

   The alphabet is the tape's own: a 5px mark with a 7px gap, which is the cap
   above a bar read in a mirror. Nothing new to learn.

   Drawn with a background layer rather than a pseudo-element because BOTH are
   already spoken for on every one of these cells and have drawn blood here
   before: `::after` is `.tk-mark`'s cap (a blanket rule on it shipped the tape
   as T-glyphs) and `::before` is `.tk-link`'s measured hit area. A third layer
   needs a third mechanism, so: `background-clip: border-box, content-box` gives
   the tick the padding strip to paint in while the bar's own colour still stops
   at the baseline, and the negative margin keeps the bar's foot ON the baseline
   with the register hanging below it. Widths are `calc(100% - 3px)` so two
   resets on consecutive days never fuse into one longer mark — at 390 the cell
   pitch is 7.6px and full-width ticks would touch, and a drawing whose point is
   a count must stay countable. */
.tape .tk-reset-day {
  /* the strip hangs the full depth of the floor, less a 3px standoff so the
     marks stand ABOVE the tape's bottom rule rather than sitting on it as if
     they were part of the chrome. Seated shallow — 7px under the axis, which
     was the first attempt — each tick reads as a foot on the bar above it and
     the two registers collapse into one; down here it is a row of its own,
     next to the dates, which is whose register it belongs to. */
  --reg: calc(var(--floor) - 3px);
  box-sizing: content-box;
  padding-bottom: var(--reg);
  margin-bottom: calc(-1 * var(--reg));
  /* The second, invisible layer is load-bearing: `background-clip` is a list
     matched to the image layers and TRUNCATED to their count, and the colour is
     painted with the LAST layer's clip. With one layer the list collapsed to
     `border-box` and every bar's own hue bled 21px below the baseline — cyan and
     amber under the axis line, measured and visible. Two layers, so the colour
     gets `content-box` and stops at the bar's foot where the data ends. */
  background-image:
    linear-gradient(var(--ink-3), var(--ink-3)),
    linear-gradient(transparent, transparent);
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: calc(100% - 3px) 5px;
  background-origin: border-box;
  background-clip: border-box, content-box;
}
/* `.tk-mark::after` is `background: inherit`, so the cap would faithfully
   reproduce this tick 7px above the bar — the shorthand carrying the optional
   layer down onto the honest one, which is the trap this file has hit before. */
.tape .tk-reset-day.tk-mark::after { background-image: none; }
/* A day the vendor reset and we said nothing: rendered exactly as a quiet tick,
   because that is what our record holds. The 0.55 is composited into the colour
   instead of applied to the element, because element opacity would take the
   reset tick down with the bar and the mark below the axis must read identically
   on all fifteen days. */
.tape .tk-reset {
  height: 5px;
  opacity: 1;
  background-color: color-mix(in srgb, var(--trace-quiet) 55%, var(--panel));
}
/* and no cap: the cap means one of ours closed here, and nothing of ours did */
.tape .tk-reset.tk-mark::after { display: none; }
/* the mark that closed an event gets a cap so the resolution day is findable */
.tk-mark::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: -7px;
  height: 5px;
  background: inherit;
}
.tk-retracted.tk-mark::after { background: var(--trace-quiet); }
.tk-now { outline: 1px solid var(--primary); outline-offset: 2px; }

/* ------------------------------------------------- the tape's own readout */

/* Only a day that resolved something carries one — about six marks in
   forty-two. Pointing at a spike should answer "what was that", and nothing
   else: date, what happened, the same headline the log uses.
   Without a pointer there is no way to ask, so the readout does not exist:
   on a phone every one of these events is a real link in the log below. */

/* The readout also needs somewhere to go. It is anchored to its own mark and
   only the last twelve of the forty-seven cells right-anchor (`index > last-12`
   in public_status.py), so cell 34 — about 74% across the tape — is the last one
   that opens rightward. A 268px panel from there clears the viewport until the
   page measure is wide enough to absorb it: solving
   `244.6 + 0.7234*vw <= vw` puts the boundary at **884px**, and below it a live
   mark landing in cells 30-34 pushes the document wider than the window and the
   page scrolls sideways. Today's eight events miss that zone by luck; events
   land there routinely (28 Jul is cell ~25 in a 42-day window).
   Measured worst case, any event layout: +137px at 520, +92px at 768, safe with
   82px to spare at 1180. Right-anchoring is not the escape — mirrored, it puts
   an early mark's readout 47px left of the viewport at 390.
   So the readout exists where there is a pointer *and* room for it. Below that
   the log carries every one of these events as a real link, which is the same
   reason the readout never existed on a phone. */
.playhead {
  position: absolute;
  inset-block: 0 var(--floor);
  inset-inline-end: calc(var(--pad) - 1px);
  width: 1px;
  background: var(--primary);
  opacity: 0.55;
}
.lr-tape .playhead { display: none; }

.axis {
  display: flex;
  justify-content: space-between;
  padding: var(--s-sm) var(--s-lg) 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.ax-now { color: var(--primary); }

.deck-note {
  margin: var(--s-sm) 0 0;
  padding: 0 var(--s-lg) var(--s-md);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}


/* ------------------------------------------------- the tape's registers */

/* Three readings taken off the tape, and therefore the tape plate's own header
   rather than a fourth band in the stack. They arrive between .section-head and
   .deck, so they take the .sc-head treatment exactly — --panel-raised on a 2px
   edge — and the deck's border continues underneath. A recorder has registers
   above its trace; a dashboard has widgets under a title. The page is the first
   one, and eleven peer-level bands would have made it the second.

   Each cell is label over value because the label is machine-set and the value
   is the answer: the split is the same semantic one the whole page uses for
   mono against sans. */
.pulse {
  display: grid;
  /* Columns from the child count, not a hard 3: the rail carries two readings
     when no call is live and three when one is, and `repeat(3, 1fr)` left a third
     of the plate header empty in the quiet state — which is the state the page is
     in most of the time. */
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  background: var(--panel-raised);
  border: 1px solid var(--rule-strong);
  border-bottom-width: 2px;
}
.pulse-row {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  min-height: var(--tap);
  margin: 0;
  padding: var(--s-sm) var(--s-lg);
  border-inline-start: 1px solid var(--rule);
}
.pulse-row:first-child { border-inline-start: 0; }
/* the strip's own 2px edge is the plate header's edge; the deck must not draw a
   second one under it */
.pulse + .deck { border-top: 0; }
/* THE LABEL ROLE. `mono` is for values, timestamps, axes and IDs — things a
   machine produced. A word that orients a reader is the page talking, and it
   belongs in the prose face. This class is the boundary the old rule never
   stated, and stating it is what stops the split eating the page again. */
.lbl {
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}
.pl-label {
  font-size: 0.8125rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}
/* The value is the link, and the whole row's height is its target: a 10px label
   with a 15px value under it is 44px of plate, so the anchor is stretched to
   claim all of it rather than leaving a 15px strip to hit. */
.pl-value {
  position: relative;
  align-self: start;
  font-size: 0.9375rem;
  font-weight: 640;
  letter-spacing: -0.01em;
  color: var(--ink);
  /* text-decoration rather than a border, so the rule stops at the words and the
     arrow is not struck through — and it is the same underline the receipt rail
     already uses for a link at reading size. */
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 4px;
  transition: color 110ms linear, text-decoration-color 110ms linear;
}
.pl-value::after { content: ""; position: absolute; inset: -14px -20px -13px; }
.pulse-row:hover .pl-value { color: var(--ink-hi); text-decoration-color: var(--ink-2); }
.pl-value i {
  text-decoration: none;
  font-style: normal;
  margin-inline-start: 5px;
  color: var(--ink-3);
  transition: transform 110ms linear;
  display: inline-block;
}
.pulse-row:hover .pl-value i { transform: translateX(2px); color: var(--ink-2); }
@media (prefers-reduced-motion: reduce) {
  .pl-value, .pl-value i { transition: none; }
  .pulse-row:hover .pl-value i { transform: none; }
}

/* --------------------------------------------------------- the masthead */

/* The picture stopped being a panel beside the answer and became the ground
   the answer is written on (Hill, 2026-08-12). Brand bar, state, figure and
   safe action all sit inside one image that runs edge to edge. */
.masthead {
  /* full-bleed: main no longer carries the measure, so this needs no vw
     trickery — a sky with a margin is not a sky */
  position: relative;
  isolation: isolate;
  display: grid;
  /* the answer leads: no header chrome over the painting, just a slim stale
     strip (when stale) and the hero readout. Nothing sits between the viewer
     and Tibo's face. */
  grid-template-rows: auto 1fr;
  /* The picture takes the whole first screen. The old cap — min(86vh, 880px) —
     was doing real damage above 1024px tall: at 2560x1440 it held the picture
     to 880px, so a 16:9 painting was being poured into a 2.9:1 letterbox and
     `cover` answered by cutting 235px off the top, which is Tibo's head. Full
     height fixes the framing rather than papering over it: a 1920x1080 or
     2560x1440 viewport IS 16:9, the same aspect as the source, so the crop
     goes to zero and the whole painting is finally on screen. */
  min-height: 100vh;
  padding-bottom: var(--s-2xl);
  overflow: clip;
}
.masthead > .stale-banner { grid-row: 1; }
.masthead > .hero { grid-row: 2; }
.stage-art {
  position: absolute;
  inset: 0;
  z-index: -2;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The masthead is a full-height 16:9 window onto a 16:9 painting, so on the
     common desktop sizes nothing is cropped and this does nothing. It only
     takes effect when a viewport is WIDER than 16:9 — an ultrawide, or a short
     laptop window — and that is exactly the case where `cover` starts eating
     the top of the frame. So the anchor sits high: whatever has to go, goes
     from the floor of the picture, never off Tibo's head. */
  object-position: 50% 18%;
}

/* A film of the same wind-up used to lie over this still and run once to
   today's level. It was dropped 2026-08-16: Flow returns 720p on every tier, so
   against a full-height masthead it measured 30-64 detail-energy at 2560 wide
   against this still's 91.6, and its agent treats attached stills as style
   references rather than as first and last frames, so it would not start where
   we told it to. The still was always the artwork of record; now it is the
   whole masthead. History and renders: luxy/library/shipped/. */

/* Two washes, and each one is doing a job — this is not the tape's fade.
   LEFT: the reading is white type on a photograph, so the field under it is
   pulled down to a guaranteed contrast floor instead of trusting whatever the
   picture happens to be doing there.
   BOTTOM: the picture has to end somewhere, and a hard edge would put a seam
   across the page. Falling into the page's own ground means it does not end,
   it arrives.

   The ground stop is var(--bg), not var(--ground): --ground was never defined,
   and one undefined custom property makes the whole `background` shorthand
   invalid at computed-value time, so it fell back to `none` and this entire
   scrim silently never painted. Every contrast figure the comments above cite
   was measured on a page that had no scrim at all — the copy was reading
   straight off the painting, which is why 10px mono over the landed frame came
   back at 1.87:1 on a phone. Do not reintroduce an undefined token here: a
   typo in this one declaration takes the whole legibility floor with it. */
.masthead::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(to right,
      rgba(8, 9, 12, 0.88) 0%,
      rgba(8, 9, 12, 0.66) 32%,
      rgba(8, 9, 12, 0.12) 58%,
      rgba(8, 9, 12, 0) 74%),
    /* the header rail now carries the chrome, so this only has to soften the
       top edge rather than make 11px mono legible over sunlit cloud */
    linear-gradient(to bottom,
      rgba(8, 9, 12, 0.34) 0%,
      rgba(8, 9, 12, 0) 16%),
    linear-gradient(to top,
      var(--bg) 0%,
      var(--bg) 4%,
      rgba(8, 9, 12, 0.72) 13%,
      rgba(8, 9, 12, 0.28) 24%,
      rgba(8, 9, 12, 0) 40%);
}

.hero {
  /* Bottom-aligned was right when the masthead was a 880px band: the reading
     sat on the picture's floor and the floor was close. Against a full-height
     painting it dropped the whole block into the busiest, brightest part of the
     frame — the title ran into the plinth and the crowd — while the quiet dark
     field the picture actually composes on the left was left empty above it.
     So the reading sits where the picture leaves room for it. */
  align-self: center;
  width: min(calc(100% - 2 * var(--gut)), var(--max));
  margin: 0 auto;
  padding-top: var(--s-2xl);
}
/* The reading is a column laid into the quiet left field, not a panel. It grows
   with the picture: a 34rem column and 52px of title held a 880px masthead, but
   against a full-screen painting they read as a caption someone left in the
   corner. The measure and the type scale together so the ratio between them —
   which is what makes it look composed rather than dropped — stays put. */
.readout {
  display: block;
  max-width: clamp(34rem, 40vw, 48rem);
}

/* no panel and no rule: on the masthead the reading floats on the picture,
   and a box drawn around it would put the artwork back in its old frame */
.ro-head {
  padding: 0;
}

/* THE MASTHEAD READING, rebuilt after Hill's outsider review (2026-08-19).
   Measured on the live page: the figure was 176px and the only text saying what
   it measured was 10px — 16:1 — with no product name and no verb anywhere above
   the fold. Separately, 78 of 114 visible text elements were mono and all 15
   orienting labels were mono + UPPERCASE + <=11px, so every word that could
   orient a stranger was dressed as machine output. A page whose founding idea
   rejects "a terminal implies a person typed something" was reading as a
   terminal. The semantic split was right; unbounded, it ate the page. */

/* the sentence that says what this is. It did not exist in any form. It sits on
   the painting, so it takes the masthead's lighter chrome ink like every other
   word up there. */
.hero > .lede {
  max-width: 34ch;
  margin: 0 0 var(--s-lg);
  font-size: clamp(1rem, 1.6vw, 1.125rem);
  line-height: 1.45;
  color: #CBD5DA;
  text-wrap: balance;
}

/* the subject. The product was named nowhere above the fold — only in an
   aria-label — so a visitor met a bare number belonging to nothing. */
.ro-subject {
  margin: 0 0 var(--s-xs);
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--ink);
}

/* The state, as a sentence a person says rather than an engraved chip. It lost
   its `mono` class in the same round: this is the page speaking, not a recorded
   value, and it was the clearest single case of the rule over-reaching.
   Hill chose the figure-led fold, so the number holds its size in BOTH states —
   which leaves the state word as the only thing that can tell a live signal from
   a historical rate. That is not a workaround; it is the carrier hard rule 8
   already nominates ("the state word keeps the accent... a visitor reads what to
   do before how sure we are"). On a watch day the words get loud and the number
   does not move. Three other answers were closed before this one: no bounded
   plane (the masthead is "no panel and no rule"), no amber on the figure (rule
   8), no size change on the figure (the choice Hill just made). */
.ro-state {
  margin: 0;
  font-family: var(--sans);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.35;
  letter-spacing: 0;
  text-transform: none;
  color: #CBD5DA;
}
.tone-watch .ro-state {
  font-size: clamp(1.25rem, 4.2vw, 1.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--primary);
}
.tone-resolved .ro-state { color: var(--resolved); font-weight: 640; }

/* Only when freshness withdraws the reading. The  half is
   gone: there is ALWAYS a figure now — a quiet day carries the base rate rather
   than nothing — and Hill objected to exactly what that rule did, a state word at
   six rem reading as though nothing were there. The percentage carries the size;
   the state word is a label. */
.is-stale .ro-state {
  display: block;
  padding: 0;
  border: 0;
  font-family: var(--sans);
  font-size: clamp(2.25rem, 5.4vw, 6rem);
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: -0.042em;
  text-transform: none;
  /* The measure is in ch, so it holds whatever the type is doing: the state
     phrase breaks into a stack instead of running out of the dark field and
     across Tibo's sleeve, and it breaks at the same place at every size
     because the limit scales with the font rather than against it. */
  max-width: 10ch;
  text-wrap: balance;
}

/* .ro-base is the quiet day's figure — a base rate from the archive rather than a
   live reading of current evidence. It carries NO separate treatment on purpose.
   Dimming it would recreate exactly what Hill objected to, a quiet day reading as
   though nothing were there; the caption already says which number this is
   ("48h base rate" against "48h signal confidence"), and .ro-basis underneath
   says where in the gap you are. A third visual treatment would be decoration. */
.ro-figure {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px;
  margin: var(--s-sm) 0 0;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 0.82;
}
/* the figure grew when the picture went full-bleed: it is now competing with a
   whole sky rather than with a 420px panel, and it still has to win */
.ro-figure b {
  font-size: clamp(5.25rem, 13vw, 11rem);
  font-weight: 700;
  letter-spacing: -0.055em;
  text-shadow: 0 2px 40px rgba(8, 9, 12, 0.55);
}
.ro-figure i {
  font-style: normal;
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  font-weight: 400;
  color: var(--ink-2);
}
/* The caption sits under its figure, not beside it. Beside it, the caption
   reached past the protected left field into whatever the painting was doing
   — measured at 3.99:1 against the crowd's glow on the top-hype frame. Under
   it, the whole reading block stays inside the dark column, and a label under
   its number is the plainer relationship anyway. */
/* The caption is what makes the number mean anything, and it was 10px uppercase
   mono under a 176px figure — 16:1, the widest gap on the page between a thing
   and its own explanation. At reading size the ratio is 4.8:1 and a stranger can
   take the two in as one object. It is a full sentence now, so it loses the
   uppercase and the tracking: those are for labels, and this stopped being one. */
/* A zero-height full-basis break, because neither `width: 100%` nor
   `flex-basis: 100%` will do it: a flex item's hypothetical main size is clamped
   by its own max-width BEFORE line-breaking is decided, so `max-width: 34ch`
   silently cancelled the break wherever 34ch fitted beside the number. Below 768
   it looked correct and from 768 up the caption sat to the RIGHT of the figure,
   which is precisely where the two stop reading as one object. The break is its
   own element now, so the measure and the line-breaking stop fighting. */
/* on .ex-figure, not .ro-figure: the <b>, the <i> and the caption all live INSIDE
   the button, so the button is the flex container and `.ro-figure`'s own flex
   properties govern a single child. Styling the wrong container is invisible —
   the rules apply, nothing errors, and the layout simply never changes. */
.ex-figure::before {
  content: "";
  order: 2;
  flex-basis: 100%;
  height: 0;
}
.ro-figure .ro-cap {
  order: 3;
  max-width: 34ch;
  margin-top: 0.55em;
  font-size: clamp(0.9375rem, 1.3vw, 1.0625rem);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.4;
  text-transform: none;
  color: #CBD5DA;
}
/* a live reading and an archival one, told apart without a third colour */
.tone-watch .ro-figure .ro-cap { color: var(--ink); }

/* .ro-justreset is the answered forecast — the 48-hour question closed at
   certainty because the reset actually happened, so the number stays, struck
   through, instead of being replaced by the archive's rate for a question
   nobody is asking yet. The strike sits on <b> alone: the % sign is a quarter
   of the size, and one shared rule draws two different line weights that read
   as a rendering artifact rather than as one deliberate gesture. Green says
   the call closed correctly; red would read as an error the page is
   apologising for. The thickness is em-based so the line scales with the
   numeral's clamp instead of thinning to a hairline at phone widths. */
.ro-justreset b {
  text-decoration: line-through;
  text-decoration-thickness: 0.055em;
  text-decoration-color: var(--resolved);
}

/* Claude has no instrument — not a greyed-out one, an absent one. */
.shutter {
  display: flex;
  align-items: center;
  margin: var(--s-sm) 0 0;
  height: 22px;
  background: repeating-linear-gradient(
    -45deg, var(--rule-strong) 0 6px, var(--panel-raised) 6px 12px);
}
.shutter span {
  padding: 2px 9px;
  background: var(--panel-raised);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.ro-action {
  margin: var(--s-md) 0 0;
  padding-top: var(--s-sm);
  border-top: 1px solid var(--rule-strong);
  font-size: clamp(1.0625rem, 1.45vw, 1.625rem);
  line-height: 1.35;
  letter-spacing: -0.012em;
  max-width: 34ch;
}
/* "What to do" is the page speaking to a person, not a value a machine produced,
   and it was the clearest single case in the audit of the mono rule over-reaching
   — 10px, uppercase, letterspaced, ink-3, directly above the sentence it labels.
   It takes the sans label role like every other orienting word now. */
.ro-action b {
  display: block;
  margin-bottom: 5px;
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}

/* why we say so — its own band under the picture, so the picture keeps its air.
   The negative margin lifts the panel into the picture's foot on purpose, and
   `position: relative` is what makes that overlap land the right way round:
   .masthead carries `isolation: isolate`, so it paints in the positioned pass,
   while a static .evidence paints in the in-flow pass before it — the picture
   came down over the panel and took the top of the first receipt line with it.
   Positioning the panel puts it back on top, which is what "under the picture"
   was always describing. */
.evidence {
  position: relative;
  width: min(calc(100% - 2 * var(--gut)), var(--max));
  /* No lift on a full-height hero. Against the old 880px band the panel rose
     into the picture's foot and that read as one composition; against a picture
     that ends exactly at the fold it reads as 26px of a bordered box peeking
     over the bottom edge, which looks like a mistake rather than an invitation.
     The picture falling into the page's own ground is the invitation. */
  margin: 0 auto;
}
.ro-why {
  padding: var(--s-lg);
  border: 1px solid var(--rule-strong);
  background: var(--panel);
}

.ro-changed {
  margin: 0;
  font-size: 1rem;
  line-height: 1.45;
  max-width: 58ch;
  color: var(--ink-2);
}

.ro-rail {
  margin-top: var(--s-sm);
  padding-inline-start: var(--s-sm);
  border-inline-start: 2px solid var(--rail);
}
/* a receipt is set as a dateline: source first, then what it says. A host
   trailing the label cannot hold its line at every label length, so it breaks
   away as an orphan; leading it also puts the judgeable half where the eye
   lands first. The whole row is one link. */
.ro-rail a {
  display: block;
  min-height: var(--tap);
  padding: 7px 0;
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--resolved);
  text-decoration: none;
}
.r-src {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  color: var(--ink-3);
  white-space: nowrap;
}
.r-src::after {
  content: "\00b7";
  margin: 0 5px 0 6px;
  color: var(--rule-strong);
}
.r-label {
  text-decoration: underline;
  text-decoration-color: var(--resolved-deep);
  text-underline-offset: 3px;
}
.ro-rail a:hover .r-label { text-decoration-color: var(--resolved); }
.ro-rail a:hover .r-src { color: var(--ink-2); }
.r-none { margin: 6px 0; font-size: 0.75rem; color: var(--ink-3); }

.ro-fresh {
  /* --s-lg, not --s-sm: the checked-at line is a control now (it explains what
     freshness means), and at 12px of clearance it could not reach 44px without
     lapping the receipt link above it. The extra air is also the right reading —
     when the page was last checked is a different kind of fact from who vouched
     for the event, and they were sitting like two lines of one block. */
  margin: var(--s-lg) 0 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

.stale-banner {
  /* a slim full-bleed alert strip, not a slab: it owns its own grid row but
     never the sky behind it. One line, edge to edge, amber on dark ink. */
  margin: 0;
  padding: 10px max(var(--gut), calc(50% - var(--max) / 2));
  background: var(--watch-deep);
  color: var(--ink);
  font-size: 0.9375rem;
  text-align: center;
}


/* ------------------------------------------------------ freshness tiers */

/* Three tiers now, and only the last one is allowed to interrupt the page.
   `is-aging` (15-30m) and `is-outage` (>60m) are BOTH hueless, and that is the
   whole point: amber means an open WATCH and nothing else, so a cron running
   nine minutes late may not spend it. If lateness could turn the page amber then
   "if the page is amber anywhere, there is something to do" stops being true,
   and the reader learns to discount the one colour the page cannot afford to
   have discounted. Staleness is also not actionable by the reader — there is
   nothing for them to do about it but know it.
   Weight carries the tier instead of hue: the checked-at line steps from ink-3
   to ink-2 as it ages, which is the same "weight, not colour" move the late
   meter bar makes. */
.is-aging .ro-fresh { color: var(--ink-2); }
/* An aging or stale reading gets a notice in the flow of the evidence band,
   where the reading it qualifies actually is — not a full-bleed strip across the
   top of the page. A banner is an interruption and should be reserved for the
   grade where the page genuinely cannot answer; below that it cries wolf over
   the picture, which is exactly what the tier split was for. */
.fresh-note {
  margin: var(--s-sm) 0 0;
  padding-inline-start: var(--s-sm);
  border-inline-start: 2px solid var(--rule-strong);
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--ink-2);
}
/* The banner returns only at outage grade, and it returns hueless. --watch-deep
   is amber's dark step and was the old banner's fill; at outage the page is not
   asking for action, it is admitting it lost the thread, so it takes the ink
   plane and a strong rule instead of the signal colour. */
.is-outage .stale-banner {
  background: var(--panel-raised);
  color: var(--ink);
  border-block: 1px solid var(--rule-strong);
}

/* -------------------------------------------------- a mark as a real link */

/* A resolved mark now goes to its own event page. The mark itself is ~7px wide,
   so the target is the full height of its cell plus a few px either side — a
   tall thin hit area rather than a 7px one.

   Adjacent-day links can still sit ~17px apart at 390, which is inside WCAG
   2.5.8's 24px spacing circle. The escape used here is the criterion's own
   *Equivalent* exception, not an approximation of it: every event drawn on this
   tape is also a full-width row of at least --tap in the register below, on the
   same page, and that is the path a phone reader gets anyway — the readout these
   marks open does not exist without a pointer and room for it.

   Hover and focus draw a 1px guide up the mark's own column, because this world
   already says "a vertical hairline is where you are reading" with .playhead.
   The guide is ink, never amber: the playhead is amber because it marks *now*,
   which is a fact about the tape, and pointing at something is not a signal. */
.tk-link { position: relative; cursor: pointer; }
/* The hit area rides ::before, NOT ::after — `.tk-mark::after` is already the
   cap that makes a resolution day findable, and every link is also a `.tk-mark`.
   The first version of this rule cascaded onto that same pseudo-element: the
   cap's own `height: 5px` kept the box five pixels tall so it never became a
   target, and `inset-inline: -7px` widened the CAP to 21.6px on a 7.6px bar, so
   the tape shipped as a row of T-glyphs. A geometry harness reported 21.6px and
   was right about the box and wrong about everything that mattered.
   Two rules: never reuse a pseudo-element without checking who already owns it,
   and a target is verified by HIT-TESTING it, never by measuring its box.

   The mark is one cell wide — 7.6px at 390 — so the target takes the full height
   of the lane plus as much width as it can without stealing its neighbour's tap.
   Measured on the deployed tape: cell pitch 5.9/6.9/7.6/8.2px at 320/360/390/414
   and the smallest gap between two link centres is ONE CELL, because confirmed
   resets do land on consecutive days. A blanket 24px target would put mark A's
   area over mark B's centre and open the wrong event on a precise tap — worse
   than a small honest one. So the reach is conditional: a cell either way unless
   another link sits within two cells, in which case this mark keeps its own edge
   on that side. `opacity: 0` still hit-tests, unlike visibility or display.

   Reachability was never the issue: every event here is also a full-width --tap
   row in the register below — WCAG 2.5.8's Equivalent exception, and the path a
   phone reader gets anyway. Focus stays visible through the global
   `:focus-visible` outline, which is measured working on the live page. */
.tk-link::before {
  content: "";
  position: absolute;
  inset-block: -4px -1px;
  inset-inline: -7px;
  opacity: 0;
}
/* PREMISE, stated because this rule cannot state it itself: marks are ADJACENT
   SIBLINGS inside `.tape`, with nothing wedged between them. Anything that breaks
   that breaks the suppression silently and every reach reverts to unconditional
   — which on a 7.26px pitch means one mark swallows its neighbour whole. Rezet
   asserts the premise from the markup side with a test that no panel is emitted
   inside a `.tape`; this comment is the other half of that contract.

   It has failed twice, both silently, both times because the selector made a
   promise the markup never made:
     · written `a.tk-link + a.tk-link`, it stopped matching the moment the marks
       became <button> — a selector that names an element type breaks when the
       markup is refactored under it;
     · then a `<div popover>` was emitted after every trigger, so no two marks
       were adjacent any more. Measured live at 390 before the fix: the 28 Jul
       mark had a **1px** hit area and had lost its own centre pixel, so a tap
       precisely on it opened 29 Jul. Only reachable with two confirmed resets on
       consecutive days — the live archive had that pair and neither preview
       bundle did, so both sweeps passed clean.

   The interleaved-panel case is kept below as defence in depth. It costs nothing
   when the panels sit outside the tape and it would have held the reach correct
   through that entire incident. */
.tk-link:has(+ .tk-link)::before,
.tk-link:has(+ .tk + .tk-link)::before,
.tk-link:has(+ [popover] + .tk-link)::before,
.tk-link:has(+ [popover] + .tk + .tk-link)::before { inset-inline-end: 0; }
.tk-link + .tk-link::before,
.tk-link + .tk + .tk-link::before,
.tk-link + [popover] + .tk-link::before,
.tk-link + [popover] + .tk + .tk-link::before { inset-inline-start: 0; }
/* below ~380 the cell pitch drops under 7px, so a 7px reach clears a mark three
   cells away and the areas would overlap again */
@media (max-width: 379px) {
  .tk-link::before { inset-inline: -4px; }
}

/* ------------------------------------------------------------- the ask */

/* A full-bleed band on its own plane, not a bordered box in a stack of bordered
   boxes. It is the only thing on the page asking for something, so it gets an
   interval and a ground of its own rather than a rule around it. The inner
   alignment trick is the one already proven on .site-head and .stale-banner. */
.cta-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-lg);
  flex-wrap: wrap;
  width: auto;
  max-width: none;
  margin-top: var(--s-3xl);
  padding: var(--s-2xl) max(var(--gut), calc(50% - var(--max) / 2));
  background: var(--panel);
  border-block: 1px solid var(--rule-strong);
}
.cta-copy {
  margin: 0;
  max-width: 26ch;
  font-size: clamp(1.625rem, 3.4vw, 2.5rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
/* Ink, not amber. The palette reserves amber for an open WATCH — "if the page
   is amber anywhere, there is something to do" — and this button was the one
   place that spent the signal on chrome, which is also why DESIGN.md listed
   "CTA fill" as a job of `primary` while the rule above it said otherwise.
   Hill resolved it on 2026-08-17: the rule wins. */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: var(--tap);
  padding: 15px 24px;
  background: var(--ink);
  color: var(--bg);
  font-weight: 660;
  font-size: 1rem;
  transition: background 120ms linear;
}
.cta:hover { background: var(--ink-hi); }


/* ---------------------------------------------------------- on the clock */

/* A docket of dated vendor commitments: what was promised, when it runs out,
   whether it still holds. Its own chapter, because forward obligation is a
   different argument from the register of what already happened — and the only
   band this round adds, which is deliberate. Four new peer-level strips would
   have turned a recorder into a dashboard, and this page's one idea rejects
   exactly that.

   The spine is the visual object. Every row carries a 2px rail whose treatment
   is the status, so reading down the plate the verdicts are a column you can
   scan before you read a word of it. Dates hold their own column for the same
   reason: a register aligns, a list does not. */
.clock { margin-top: var(--s-3xl); }

.clock-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--panel);
  border: 1px solid var(--rule-strong);
}
.clock-row {
  display: grid;
  /* Fixed columns with the slack trailing, which is how .scorecard dd already
     works. `1fr auto auto` right-aligned the date and the chip against a 1180px
     measure, leaving 1200px of dark between a subject and its own verdict — the
     same fault the scorecard fixed by putting the value next to the thing it
     measures rather than flinging it to the far edge. */
  grid-template-columns: minmax(0, 54ch) 9.5rem auto;
  grid-template-areas:
    "subject due    status"
    "src     .      chain";
  justify-content: start;
  align-items: baseline;
  gap: 4px var(--s-xl);
  min-height: var(--tap);
  padding: var(--s-md) var(--s-lg) var(--s-md) calc(var(--s-lg) - 2px);
  border-top: 1px solid var(--rule);
  border-inline-start: 2px solid transparent;
}
.clock-list li:first-child .clock-row { border-top: 0; }

/* One hue in the whole docket, and it goes to the row that earned it: a kept
   commitment is evidence that resolved something, which is cyan's entire job.
   Everything else is grey at two weights, and a lapsed promise is hatched
   rather than coloured — the same move the retracted mark and the empty meter
   make, because a correction is the absence of a signal colour, not a third
   one. No amber here, not even on lapsed. A hatched row in a register of intact
   ones is louder than a colour, and amber has one meaning on this page. */
.status-open { border-inline-start-color: var(--ink-2); }
.status-extended { border-inline-start-color: var(--trace-quiet); }
.status-honoured { border-inline-start-color: var(--resolved); }
/* The rail only, drawn as its own layer. `border-image` was tried and paints
   every edge, so a lapsed row came back hatched all the way round like a
   ransom note. */
.status-lapsed { position: relative; }
.status-lapsed::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: -2px;
  width: 2px;
  background-image: repeating-linear-gradient(
    45deg, var(--ink-3) 0 2px, transparent 2px 5px);
}

.ck-subject {
  grid-area: subject;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink);
}
.ck-due {
  grid-area: due;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--ink-2);
  white-space: nowrap;
}
.ck-status {
  grid-area: status;
  padding: 3px 7px 4px;
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  border: 1px solid var(--rule-strong);
  color: var(--ink-3);
}
.status-open .ck-status { color: var(--ink-2); }
.status-extended .ck-status { border-style: dashed; }
.status-honoured .ck-status {
  color: var(--resolved);
  border-color: var(--resolved-deep);
}
.status-lapsed .ck-status {
  color: var(--ink-3);
  background-image: repeating-linear-gradient(
    45deg, var(--rule-strong) 0 3px, transparent 3px 6px);
}

/* The receipt is a dateline, set the way every other receipt on the page is:
   host first in engraved mono, label underlined at reading size, whole row one
   link. Host-first is structural — a host trailing the label cannot hold its
   line at every label length. */
.ck-src {
  grid-area: src;
  display: inline-flex;
  align-items: center;
  gap: var(--s-sm);
  /* Hard rule 4 names receipt links explicitly, and this is one: --tap, not the
     24px WCAG floor. The register pays a little height for it, which is the right
     trade — the whole point of the row is that the promise is checkable. */
  min-height: var(--tap);
  margin-top: 2px;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.ck-src:hover { color: var(--ink-2); }
.ck-src span { text-decoration: underline; text-decoration-color: var(--rule-strong); }
.ck-src:hover span { text-decoration-color: var(--resolved); }

/* The supersede chain is a fold because it is provenance, not the reading: a
   commitment that moved twice is one line of history the reader can open, and
   four lines of it in the flow would bury the row that still holds. */
.ck-chain {
  grid-area: chain;
  justify-self: start;
  align-self: center;
  margin-top: 2px;
}
.ck-chain > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  cursor: pointer;
  list-style: none;
}
.ck-chain > summary::-webkit-details-marker { display: none; }
.ck-chain > summary::after {
  content: "+";
  font-size: 0.75rem;
  color: var(--trace-quiet);
}
.ck-chain[open] > summary::after { content: "\2212"; }
.ck-chain > summary:hover { color: var(--ink-2); }
.ck-chain ol, .ck-chain ul {
  list-style: none;
  margin: var(--s-xs) 0 0;
  padding: var(--s-xs) 0 0 var(--s-sm);
  border-top: 1px solid var(--rule);
  border-inline-start: 1px solid var(--rule);
}
.ck-chain li {
  font-family: var(--mono);
  font-size: 0.6875rem;
  line-height: 1.6;
  color: var(--ink-3);
}

/* ---------------------------------------------------------- scorecards */

.proof, .recent, .method { margin-top: var(--s-2xl); }
.method { margin-top: var(--s-3xl); }

.score-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--s-md);
}
/* A plate with an engraved header, because depth here is plane separation and
   rule weight and nothing else. Three plane tokens exist and only one was being
   spent; the header takes --panel-raised and a 2px edge so the card reads as a
   case around an instrument instead of a grey rectangle among grey rectangles. */
.scorecard {
  background: var(--panel);
  border: 1px solid var(--rule-strong);
}
.sc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-md);
  flex-wrap: wrap;
  margin: 0;
  padding: var(--s-md) var(--s-lg);
  background: var(--panel-raised);
  border-bottom: 2px solid var(--rule-strong);
}
.sc-head .eyebrow { order: 2; }
.sc-head h3 {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.scorecard dl {
  margin: 0;
  padding: var(--s-sm) var(--s-lg) var(--s-lg);
}
/* label · then drawing and value together, with the value next to the thing it
   measures rather than flung to the far edge of the measure.
   `_meter` returns the drawing and the value as two spans inside ONE <dd>, so
   the second track has to be an inner grid — laying them out as sibling columns
   of the outer grid dropped the value onto its own line, and an empty drawing
   (a count of zero) collapsed `minmax(0, …)` and slid the value leftwards. */
.scorecard dl > div {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  align-items: center;
  gap: var(--s-md);
  padding: var(--s-sm) 0;
  border-top: 1px solid var(--rule);
}
.scorecard dl > div:first-child { border-top: 0; }
.scorecard dd {
  /* the UA gives dd a 40px inline-start margin; without this reset every
     drawing on the plate sits 40px right of its own label */
  margin: 0;
  display: grid;
  grid-template-columns: 24rem 6.5rem 1fr;
  align-items: center;
  gap: var(--s-md);
}
.scorecard dt { font-size: 0.9375rem; color: var(--ink); }
/* the scale, and which way a signed value points, said in words under the label */
.scorecard dt small {
  display: block;
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}

/* A count is a tally you can count with your eyes. It used to be a bar scaled
   against a ceiling of 30 that appears nowhere in the data, so `Truths 8`
   rendered as 26.7% of nothing in particular. */
.m-tally {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 26px;
}
.m-tally i {
  width: 11px;
  height: 22px;
  background: var(--resolved);
}
/* A count of watches that have already closed is history, not an open watch —
   amber would say there is something to do, and --watch-deep sits at 2.75 on
   this plane. --trace-quiet is the token for "the recorder was running": 3.19. */
.sc-count:nth-of-type(2) .m-tally i {
  height: 14px;
  background: var(--trace-quiet);
}
.m-tally b {
  align-self: center;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--ink-3);
}

/* A rate is one solid bar of exact length over a tick ruler you read it off.
   Lighting whole slots was tried and rounded 12.5% of twenty down to two, so
   the drawing said 10% while the number said 12.5%. */
.m-slot {
  position: relative;
  display: block;
  height: 26px;
}
.m-base {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 1px;
  background: var(--rule-strong);
}
.m-ticks {
  position: absolute;
  inset-inline: 0;
  bottom: 1px;
  height: 12px;
  background-image: repeating-linear-gradient(
    90deg, var(--trace-quiet) 0 1px, transparent 1px 5%);
  opacity: 0.5;
}
.m-val {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 22px;
  background: var(--resolved);
}
/* A value on the wrong side of zero is drawn, and named, never clamped away:
   the old meter clamped to [0,1] so -0.62h and 0h were the same picture.
   Hueless on purpose, and for the same reason a retracted mark is hueless —
   "a correction is not a third signal colour, it is the absence of one". Being
   late is a correction to the reading, not a state to alert on. It also clears
   the 3.0 non-text floor, which --watch-deep does not on this plane (2.75). */
.m-val.is-late { background: var(--ink-3); }
/* Same ink, and deliberately the SAME ink, because it is the same statement:
   **length here is not a credit.** Six of the seven rows on this card are read
   "longer is better" and are filled `--resolved` for it. False alarms is the one
   row where longer is worse — 1.25 a week against a ceiling of 3 — and drawn in
   the same cyan it joined a column of wins, so the eye scanning the card read a
   bar that had more than doubled (0.54 -> 1.25) as another good number. The
   drawing said improvement while the number said the opposite, which is the
   whole failure this round exists to stop, committed by the chart instead of the
   data. Hueless is not a demotion and not a warning: cyan on this page means
   evidence that resolved something, and a false alarm resolved nothing. */
.m-val.is-ceiling { background: var(--ink-3); }
.m-empty {
  position: relative;
  display: block;
  height: 26px;
  opacity: 0.55;
  background: repeating-linear-gradient(
    45deg, var(--rule-strong) 0 3px, transparent 3px 6px);
}
.m-value {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  text-align: right;
}
.m-none { color: var(--ink-3); font-size: 1rem; }
.as-of {
  margin: 0;
  padding: var(--s-sm) var(--s-lg) var(--s-md);
  border-top: 1px solid var(--rule);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}


/* ------------------------------------------------- rhythm, and the badge */

/* The track record and the rhythm are one chapter, and this instrument is the
   reason they had to be. The seven-meter scorecard moved into a fold, and a
   collapsed drawing is not a drawing — so with the scorecard closed the section
   would have rendered as a heading, a chip and a summary line. That is a
   typography-only section, which is hard rule 1's exact failure mode: it killed
   v1, and the rule's second clause was written on 2026-08-17 because four of
   five body sections failed it and Hill read the page and said the same three
   words twice. The fold holds the detail; this holds the reading.

   The gaps between resets, newest at the top, each an exact bar over a tick
   ruler — the same "a rate is one solid bar over a ruler you read it off"
   grammar the meters use. Horizontal and hueless on purpose: these are
   durations ranked by length, not events in time, so the longest drought is
   simply the longest bar, and nothing here may read as a second tape four
   hundred pixels under the first.

   The median is drawn as a line through the distribution it describes, which is
   the honest form of a median. As a figure in a list it is one more number; as a
   datum across ten bars you can see how many fell short of it. */
/* The rhythm panel. Three siblings — the register of figures, the gap bars and
   the hour histogram — that must read as ONE instrument case, so each takes the
   edge of the one above it rather than floating as three lists in a column.

   ONE scale for the bars, the ruler, the datum and the axis. The first build had
   two: the bars sat in a grid column that excluded the day-label gutter while the
   ruler and the median line measured the full content width, so the longest bar
   stopped short of its own axis label and the median stood at 32% of a drawing it
   was meant to mark at 30.4%. Two scales in one drawing is a worse fault than a
   coarse one — "a drawn value is only honest if the reader can see what it is
   drawn against", and this showed the reader the wrong thing to read it against.
   One --rh-track token feeds all four now, so they cannot drift. */
.rhythm,
.rh-gaps,
.hour-hist {
  --rh-gutter: 3.25rem;
  --rh-track: min(46rem, 100% - var(--rh-gutter) - var(--s-sm));
  background: var(--panel);
  border: 1px solid var(--rule-strong);
}
.rhythm {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  /* The dividers are the grid's own gap with the rule colour behind it, not a
     border on each cell. auto-fit rewraps to two columns on a phone and to four
     on a desktop, so `:first-child` cannot know which cells start a row — a
     border-per-cell left a stray rule down the middle of the second row. This
     way every seam is drawn by the geometry and none by a guess. */
  gap: 1px;
  margin: 0;
  background: var(--rule);
}
/* The case is joined by whichever block follows whichever block. A caption can
   land between two drawings — `.rh-note` does — and an adjacent-sibling chain
   that only knew the three plates would have let the histogram draw a second
   top border and shown page ground through the seam. */
.rhythm + .rh-gaps,
.rh-gaps + .hour-hist,
.rhythm + .hour-hist,
.rh-gaps + .rh-note,
.rh-note + .hour-hist,
.rh-note + .rh-gaps { border-top: 0; }

/* The gap chart's caption, and it belongs ON the plate: it names what the bars
   measure and — the part only it can say — that their ORDER is time, newest
   first. The drawing's row order carries meaning that nothing else on the page
   states, and an aria-label does not reach a sighted reader. Set as the same
   engraved chrome as .hist-note, but carrying the case's own background and
   edges so the instrument stays one object rather than two plates with a gap. */
/* it carries the one panel that replaced ten, so it holds a control now */
.rh-note .ex { color: var(--ink-2); }
.rh-note .ex:hover { color: var(--ink); }
.rh-note {
  margin: 0;
  padding: 0 var(--s-lg) var(--s-md);
  background: var(--panel);
  border: 1px solid var(--rule-strong);
  border-block: 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

/* A figure and its label, stacked, in the same register idiom as .pulse. */
.rh-metric {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--s-md) var(--s-lg);
  background: var(--panel);
}
.rh-metric dt {
  font-size: 0.8125rem;
  line-height: 1.35;
  color: var(--ink-3);
}
.rh-metric dd {
  /* The UA gives dd a 40px inline-start margin. Dropping this reset is what put
     every drawing on the scorecard 40px right of its own label, and it looks like
     boilerplate right up until it is load-bearing. */
  margin: 0;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.rh-gaps {
  position: relative;
  list-style: none;
  margin: 0;
  /* the extra bottom room is the datum's label lane */
  padding: var(--s-lg) var(--s-lg) var(--s-lg);
  /* Ruler and datum are background layers, not absolutely-positioned
     pseudo-elements, so every percentage resolves against the same box the bars
     are laid out in. An abs-positioned ::before measures the padding box while a
     grid column measures the content box — which is exactly how the two scales
     got apart. background-origin removes the choice.
     10% of the gradient box, not calc(track/10): a percentage inside a repeating
     gradient resolves against background-size, so it lands exactly ten times,
     where the calc form left a doubled tick to subpixel rounding. .m-ticks uses a
     percentage for the same reason.
     The ruler is what the bars are read off, so it sits under them rather than
     competing — --trace-quiet at 45%, the strength the first version carried. */
  background-image:
    linear-gradient(var(--ink-2), var(--ink-2)),
    repeating-linear-gradient(90deg,
      color-mix(in srgb, var(--trace-quiet) 45%, transparent) 0 1px,
      transparent 1px 10%);
  background-size:
    1px calc(100% - var(--s-lg) - var(--s-md) + 8px),
    var(--rh-track) calc(100% - var(--s-lg) - var(--s-md) + 8px);
  background-position:
    calc(var(--rh-frac, 0) * var(--rh-track)) var(--s-lg),
    0 var(--s-lg);
  background-repeat: no-repeat;
  background-origin: content-box;
}
/* The datum has to say what it is. Drawn alone it is a bright vertical line a
   reader can mistake for a chart edge, and this file's own standard is that a
   drawn value is only honest if the reader can see what it is drawn against —
   which covers the mark as well as the scale. The figure sits in the register
   above, so the line only needs its name, not its number, and naming it in CSS
   keeps the renderer out of it.

   THIS guard is narrow on purpose: it suppresses the label pseudo-element only.
   The earlier version guarded `background-image`, and that shorthand carries the
   ruler as well as the datum, so it deleted the thing the bars are read off. */
.rh-gaps::after {
  content: "median";
  position: absolute;
  inset-block-end: 0;
  /* Clamped to the track so a very small fraction cannot hang the caption off
     the left edge of the plate: median/max is data-driven and a 0.5d median
     against a 16d drought puts the datum inside the label's own half-width.
     A caption drifting a few px off its line is not a lie about the data; a
     caption clipped by the plate is a defect. 23px is half of "MEDIAN" at
     9px mono. */
  inset-inline-start: clamp(
    calc(var(--s-lg) + 23px),
    calc(var(--s-lg) + var(--rh-frac, 0) * var(--rh-track)),
    calc(var(--s-lg) + var(--rh-track) - 23px));
  translate: -50% 0;
  font-family: var(--mono);
  font-size: 0.5625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink-2);
}
.rh-gaps:not([style*="--rh-frac"])::after { content: none; }
/* No guard on the background here. The first version disabled `background-image`
   when --rh-frac was absent, which took the RULER down with the datum — one
   shorthand, two layers, and the drawing lost the thing it is read against.
   When the fraction is missing the datum falls at 0 and hides under the axis
   origin, which is a harmless degradation; the ruler always draws. --rh-frac has
   to ride `.rh-gaps` itself, because a custom property only travels down and the
   register that prints the median is a sibling, not an ancestor. */

/* The row carries its own two columns again. Ten per-gap popovers collapsed into
   one strip-level panel on .rh-note, so `li.rh-gap` is a plain list item — no
   button, no target of its own — and the grid comes back here. The title
   attribute carries the end date for anyone who wants a single row's detail. */
.rh-gap {
  display: grid;
  grid-template-columns: var(--rh-track) var(--rh-gutter);
  align-items: center;
  gap: var(--s-sm);
  /* 24px, not 15: the row IS the target now, and 24 is WCAG 2.5.8's minimum met
     outright rather than argued around. It costs 60px across ten rows and the
     bar keeps its own 9px weight, so the chart reads the same and the control
     stops being technically-present. Rule 4's stricter 44px is still not met —
     that one leans on the Equivalent path, every gap being a full-width row in
     the archive. */
  height: 24px;
  margin-bottom: 2px;
}
.rh-gap:last-child { margin-bottom: 0; }
/* A real distribution is skewed — the catalog's gaps run 0.1d to 16.2d against a
   1.4d median — so on a linear scale most bars are sub-pixel. They keep a 3px
   floor so every gap is present as a mark rather than vanishing, and the exact
   value is printed beside it: the bar carries the shape, the label carries the
   number. The skew is the true reading and is left visible rather than flattened;
   a log scale would make ten gaps look alike, and "a drawing that rounds is a
   drawing that lies". 3px says "short" without claiming a magnitude. */
.rh-bar {
  display: block;
  height: 9px;
  min-width: 3px;
  background: var(--trace-quiet);
}
/* The longest gap is the drought the register names, so it earns the readable
   weight — but only when the renderer says which one it is. Position cannot say
   it: these arrive newest-first, so `:first-child` is the most recent gap and
   highlighting it would draw one claim beside a figure stating another. Hueless
   either way: a long wait is the shape of the history, not a call to act. */
.rh-gap.is-longest .rh-bar { background: var(--ink-3); }
.rh-d {
  font-size: 0.6875rem;
  font-weight: 400;
  color: var(--ink-3);
  text-align: right;
}

/* An hour-of-day histogram is a count per slot, so it is drawn as counts: 24
   exact bars on a shared baseline. It is not a rate and carries no ceiling it did
   not measure — --hh-max is the tallest observed hour, printed by the note under
   it. Twenty-four slots always render, including the empty ones, because an hour
   with no reset is the same kind of content as a quiet day on the tape: never
   compress quiet. */
.hour-hist {
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  align-items: end;
  gap: 2px;
  list-style: none;
  margin: 0;
  padding: var(--s-lg) var(--s-lg) var(--s-sm);
}
.hh {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
  height: 104px;
  justify-content: flex-end;
}
.hh-bar {
  display: block;
  min-height: 2px;
  background: var(--resolved);
}
/* An empty hour is drawn as the baseline it sits on, not as a 2px cyan stub that
   would read as one reset. Same reason the quiet tick is quiet and not blank. */
.hh-bar[style*="height: 0"] { background: var(--trace-quiet); }
.hh-l {
  font-family: var(--mono);
  font-size: 0.5625rem;
  font-weight: 400;
  letter-spacing: 0;
  text-align: center;
  color: var(--ink-3);
}
/* 24 labels in a phone's measure is 13px each, so every other one is dropped —
   the drawing keeps every slot and only the labels thin out. */
@media (max-width: 760px) {
  .hh:nth-child(even) .hh-l { visibility: hidden; }
}
.hist-note {
  margin: var(--s-sm) 0 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

/* Not a maturity label in the old sense — rule 9 threw `Beta` off the page for
   telling a reader nothing they could check. This one is backed by the numbers
   directly under it and it changes what the reader should believe, which is the
   test rule 9 sets. Hueless, because "measured" is a claim about the sample, not
   an event that resolved and not something to act on. */
.trust-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0 0 var(--s-lg);
  padding: 4px 9px 5px;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: var(--panel-raised);
  border: 1px solid var(--rule-strong);
}
.trust-badge.forming { color: var(--ink-3); border-style: dashed; }
.trust-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--resolved);
}
.trust-badge.forming::before { background: var(--trace-quiet); }

/* A fold, set so it reads as *more detail* rather than *the content is hidden* —
   the difference is whether the summary states what is inside and what it costs
   to trust it. The plate keeps its own edge so the closed state still looks like
   a case, not a link. */
/* inside the fold the scorecard is already a plate; drop its second edge so the
   fold does not draw a box inside a box */

/* ----------------------------------------------------------- event log */

/* A register on one plate. Each row's strip is the SAME 42-day window as the
   tape above with only its own event lit, so reading down the list the lit mark
   walks backwards in time as a staircase — which is the whole reason the window
   is shared. It used to be an 18-day window ending at each event's own
   `updated_at`, which pinned every mark to the right edge and left 17 of 18
   marks identical, so rows two and three drew byte for byte the same. */
.event-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--panel);
  border: 1px solid var(--rule-strong);
}
.logrow {
  display: block;
  min-height: var(--tap);
  padding: var(--s-sm) var(--s-lg);
  border-top: 1px solid var(--rule);
}
.event-list li:first-child .logrow { border-top: 0; }
.logrow:hover { background: var(--panel-raised); }
.lr-tape { display: block; margin-top: var(--s-xs); min-width: 0; }
.lr-tape .tape {
  --bar: 22px;
  --pad: 0px;
  --floor: 0px;
  background-image: none;
  display: grid;
  flex: none;
  width: 100%;
  min-height: 24px;
  height: 24px;
  padding: 0;
  border-bottom: 1px solid var(--rule);
}
.lr-tape .tk { min-width: 0; }
.lr-tape .tk-mark::after { display: none; }
.lr-tape .tk-now { outline: 0; }
/* 24px tall and no floor at all, so there is no register below the axis to hang
   a reset in — same reason the cap is suppressed one line up. The row itself is
   already the disclosure here. */
.lr-tape .tk-reset-day {
  padding-bottom: 0;
  margin-bottom: 0;
  background-image: none;
}
.lr-body { display: flex; align-items: baseline; gap: var(--s-sm); min-width: 0; flex-wrap: wrap; }
/* the date the register never had */
.lr-when {
  flex: none;
  width: 4.25rem;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem;
  color: var(--ink-2);
}
.lr-kind {
  flex: none;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.lr-kind.tone-watch { color: var(--primary); }
.lr-kind.tone-resolved { color: var(--resolved); }
/* the headline is the content, so it wraps rather than truncating, and the
   receipt count sits next to it instead of being flung to the far edge */
.lr-head {
  min-width: 0;
  font-size: 1rem;
  color: var(--ink);
}
.lr-meta {
  flex: none;
  font-size: 0.625rem;
  color: var(--ink-3);
  white-space: nowrap;
}
.event-list .empty { padding: var(--s-md) var(--s-lg); color: var(--ink-3); }

/* -------------------------------------------------------- the pipeline */
/* not a row of numbered cards — a line with a gate on it, because the
   human-approval step is the claim worth making */

/* Drawn, not listed. Rule 7: this section "earns its place only if it SHOWS the
   pipeline". It was four text columns with a 7px grey square each, which is a
   list wearing a bullet. Now one rail runs through four stations and each
   station is drawn in the tape's own marks.

   Every multiplicity in the drawing is one the copy already states: three
   sources in, a gate that discards, two readers that must agree, two
   destinations out. How much the scoring rules actually cut is not in the
   contract, so the gate is a gate and never a funnel with a ratio — the round
   that produced this section had already caught itself inventing dates for the
   eight truths, and a fabricated width here would be the same sin. */

.pipeline {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  margin: var(--s-xl) 0 0;
  padding: 0;
}
.pipeline li {
  position: relative;
  padding: var(--s-xl) var(--s-md) 0 0;
}
/* the rail: one continuous 2px line through every station */
.pipeline li::before {
  content: "";
  position: absolute;
  top: 21px;
  inset-inline: 0;
  height: 2px;
  background: var(--rule-strong);
}
/* the rail stops at the last station rather than running off the measure */
.pipeline li:last-child::before { inset-inline-end: calc(100% - 13px); }

.p-mark {
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 22px;
}
.p-mark i {
  width: 5px;
  height: 22px;
  background: var(--resolved);
}
/* Collect: three sources arriving, at three depths */
.p-collect .p-mark i:nth-child(1) { height: 10px; }
.p-collect .p-mark i:nth-child(2) { height: 16px; }
.p-collect .p-mark i:nth-child(3) { height: 22px; }
/* Score: a gate — two uprights the rail passes between, and two stubs that
   fall away below it, because most of what arrives does not survive */
.p-score .p-mark { gap: 6px; }
.p-score .p-mark i { width: 2px; height: 22px; background: var(--ink-3); }
.p-score .p-mark u {
  position: absolute;
  top: 26px;
  width: 5px;
  height: 7px;
  background: var(--trace-quiet);
  opacity: 0.6;
}
.p-score .p-mark u:nth-of-type(1) { inset-inline-start: 1px; }
.p-score .p-mark u:nth-of-type(2) { inset-inline-start: 11px; top: 30px; }
/* Cross-check: two readers side by side; nothing ships unless they agree */
.p-check .p-mark i { width: 8px; }
.p-check .p-mark i:nth-child(2) { background: var(--watch-deep); }
/* Publish: one call leaving for two destinations, the page and Telegram */
.p-publish .p-mark i:nth-child(1) { height: 22px; }
.p-publish .p-mark i:nth-child(2) { height: 12px; background: var(--resolved-deep); }

.pipeline b {
  display: block;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.p-copy {
  display: block;
  margin-top: 6px;
  padding-inline-end: var(--s-md);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ink-2);
}


/* -------------------------------------------- the glossary, and the way on */

/* The method section explains how a mark gets on the tape; the glossary explains
   the words the whole page uses. It is a fold for the same reason the scorecard
   is: a reader who already knows what a watch is should not scroll past four
   definitions to reach the footer, and one who does not must be able to find them
   without leaving. Same fold grammar as the chapters, so opening one teaches the
   other — and the native marker goes, because a UA triangle beside engraved mono
   is the one piece of chrome on this page nobody designed. */

/* Term and definition on one row, the term holding its own column so the eye can
   run down the terms alone — a definition list read as a register, not as prose
   with bold words in it. */
.glossary { margin: 0; }
.glossary > div {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  gap: var(--s-md);
  padding: var(--s-md) var(--s-lg);
  border-top: 1px solid var(--rule);
}
.glossary > div:first-child { border-top: 0; }
.glossary dt {
  font-size: 0.9375rem;
  font-weight: 640;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.glossary dd {
  /* the UA's 40px dd indent again — load-bearing every time it is dropped */
  margin: 0;
  max-width: 62ch;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-2);
}

/* The way out of a chapter and into the archive. Not a button and not a nav item:
   it is one sentence that happens to be a link, set as engraved chrome on the
   page ground so it reads as a continuation of the section it closes rather than
   a second call to action competing with the one band that is allowed one. */
/* Inline, not inline-flex. As a flex row the sentence and the arrow were two
   flex items, so when the copy wrapped at 320 the text took one column and the
   arrow was stranded at the far right of the measure, vertically centred between
   two lines and attached to nothing. The arrow belongs after the last word, which
   is what normal inline flow does. The 44px target then comes from an inset
   ::after — the same way .pl-value claims one without inflating its line box. */

@media (max-width: 900px) {
  /* a 13rem term column plus a definition needs more than a phone has, so the
     term takes its own line above what it means */
  .glossary > div {
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
    padding-inline: var(--s-md);
  }
}



/* The published-call archive. `.cl-row` is an <a> wrapping four inline children
   and it shipped with no rules at all, so on the live page the stamp, the kind,
   the headline and the receipt count flowed as raw inline boxes and printed on
   top of one another at 320, 390 and 768 — text on text, a grade-1 fail.

   It takes the same register grammar as the truth log directly above it, and the
   SAME 13.5rem stamp column, so reading down the page the two archives share one
   left edge instead of looking like two different tables. `.cl-head`/`.cl-meta`
   are the doc-page twins of the index's `.lr-head`/`.lr-meta`, and `.lr-kind`
   already carries the tone inks — `tone-void` deliberately has no rule, so a
   retraction falls to hueless ink, which is this world's law for a correction. */
.cl-list > li { border-top: 1px solid var(--rule); }
.cl-list > li:first-child { border-top: 0; }
.cl-row {
  display: grid;
  /* The kind column is fixed, not `auto`. Sized to `auto` the chip shrank to its
     own text, so COOLED and WATCH started their headlines ~90px left of the
     RESET CONFIRMED rows and the register lost the left edge that makes it
     readable as a column. 11rem clears the longest label at 10px mono. */
  grid-template-columns: 13.5rem 11rem minmax(0, 1fr) auto;
  grid-template-areas: "when kind head meta";
  align-items: baseline;
  gap: 4px var(--s-lg);
  min-height: var(--tap);
  padding: var(--s-md) var(--s-lg);
}
.cl-row:hover { background: var(--panel-raised); }
.cl-head {
  grid-area: head;
  min-width: 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink);
}
.cl-meta {
  grid-area: meta;
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  white-space: nowrap;
}
.cl-row .lr-kind { grid-area: kind; white-space: nowrap; }

@media (max-width: 900px) {
  /* four columns need well over 500px; the phone has 358. Same restructure the
     truth log takes, for the same reason. */
  .cl-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "when meta"
      "kind kind"
      "head head";
    gap: var(--s-xs) var(--s-sm);
    padding-inline: var(--s-md);
  }
  .cl-row .tl-when { white-space: normal; }
  .cl-meta { justify-self: end; }
}

/* ------------------------------------------- prose objects on a doc page */

/* A list on an instrument page is a register of statements, so the marker is a
   rule rather than a bullet: a 6px dash on the baseline, in the same engraved grey
   the axis labels use. A disc would be the only round mark on a page whose whole
   vocabulary is ticks and rules. */
.doc-list {
  margin: var(--s-md) 0 0;
  padding: 0;
  list-style: none;
}
.doc-list > li {
  position: relative;
  max-width: 68ch;
  padding-inline-start: var(--s-lg);
  margin-top: var(--s-sm);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-2);
}
.doc-list > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.72em;
  width: 6px;
  height: 1px;
  background: var(--trace-quiet);
}

/* An aside: true, worth knowing, not the answer. It takes the hairline-and-indent
   treatment the evidence band already uses for a secondary line, so a reader
   learns one shape for "this qualifies what you just read". */
.doc-note {
  max-width: 66ch;
  margin: var(--s-md) 0 0;
  padding-inline-start: var(--s-md);
  border-inline-start: 1px solid var(--rule-strong);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-3);
}

/* The one place on these pages worth spending emphasis: the line that says the
   percentage is not the reader's own remaining quota. It is spent as **weight and
   plane**, never as hue — amber means an open WATCH and a standing clarification
   is not a watch, and rule 6 forbids the glow or shadow a warning usually reaches
   for. So: the raised plane, a 2px ink edge, reading-size type at full ink. It
   outranks everything around it without borrowing a signal. */
.doc-warn {
  max-width: 62ch;
  margin: var(--s-md) 0 0;
  padding: var(--s-md) var(--s-lg);
  background: var(--panel-raised);
  border-inline-start: 2px solid var(--ink);
  font-size: 1rem;
  font-weight: 560;
  line-height: 1.55;
  color: var(--ink);
}

/* A note inside a scorecard plate, under the drawings it qualifies. */
.sc-note {
  margin: 0;
  padding: var(--s-sm) var(--s-lg) var(--s-md);
  max-width: 68ch;
  border-top: 1px solid var(--rule);
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--ink-3);
}

/* A field name is a machine-produced value, so it belongs to the mono role the
   rest of the page uses for exactly that — and it takes a plane, because on the
   schema page there are forty-five of them running through prose and they have to
   be pickable out of a sentence without shouting. No radius: nothing on this
   surface is rounded except the mascot, which is a sticker. */
code {
  padding: 1px 5px 2px;
  background: var(--panel-raised);
  border: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.8125em;
  color: var(--ink-2);
}
.doc-warn code { color: var(--ink); }

@media (max-width: 900px) {
  .doc-warn { padding-inline: var(--s-md); }
  .sc-note { padding-inline: var(--s-md); }
}

.pipeline b > a,
.pipeline b > a::after,


/* ------------------------------------------------- annotation, and popovers */

/* Twenty-two things on this page now explain themselves in place. They are real
   <button>s because a popover invoker has to be one, and every one of them must
   read as the thing it wraps — a number, a state word, a tape mark — never as a
   button. So: total reset, inherit everything, and then ONE affordance so a
   reader learns it once.

   The page now has two kinds of interactive text and the difference is worth
   drawing:
     · a SOLID underline goes somewhere      (receipts, .pop-go)
     · a DOTTED rule explains in place       (.ex)
   That is the print convention for an annotated term, it costs no box, it scales
   from an 11px caption to a state word, and it cannot be confused with a link.
   Rule 6 forbids the glow or shadow an affordance usually reaches for; a hairline
   is the whole budget and it is enough. */
.ex {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  text-align: inherit;
  text-transform: inherit;
  cursor: pointer;
  text-decoration: underline dotted var(--trace-quiet);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: text-decoration-color 110ms linear, color 110ms linear;
}
.ex:hover { text-decoration-color: var(--ink-2); }
/* the state is already an engraved plate, so its rule hugs the word instead of
   floating four pixels below it inside the border */
.ex-state { text-underline-offset: 2px; }

/* Hard rule 4 wants 44px on everything focusable, and these are controls, not
   links inside a sentence — so each claims its target with an inset ::after
   rather than by inflating a line box inside a dense readout. The reach is sized
   per control from its MEASURED clearance to the nearest other control, because
   an expansion that laps a neighbour makes a precise tap open the wrong thing:
     ex-state   13px below to the figure  -> take it upward, into the artwork
     ex-action  67px clear                -> symmetric
     ex-stat    74px clear                -> symmetric
     ex-read    already 52px via .pl-value::after
     ex-figure  98-166px tall already
     ex-fresh   6px to a receipt link     -> horizontal, and only 5px vertical
     ex-gap     gone - the ten per-gap popovers became one on .rh-note */
.ex { position: relative; }
/* :not(.ex-mark) is load-bearing and this is the SECOND time it has bitten.
   `.tk-mark::after` is the tape's cap, and a mark is both — so a blanket
   `.ex::after` overwrites the cap, and `content: none` on it deletes the cap
   outright. Marks carry their own hit area on ::before for exactly this reason;
   nothing here may touch their ::after. */
.ex:not(.ex-mark)::after { content: ""; position: absolute; inset: -14px -10px; }
/* Two classes each, so these tie with `.ex:not(.ex-mark)` on specificity and win
   on source order. Written singly they lost to it silently — which is how a
   per-control reach that was measured for its own clearance gets replaced by the
   generic one without anything appearing to be wrong. */
.ex.ex-state::after { inset: -21px -10px -6px; }
.ex.ex-fresh::after { inset: -15px -12px; }
.ex.ex-figure::after { content: none; }

/* The gap labels are a stack of 15px rows with 5px between them: adjacent labels
   have ZERO clearance, so any vertical reach would put one row's target over the
   next row's label and open the wrong gap. It reaches sideways instead, across
   its own row's bar track, which holds no controls — a wide, shallow target
   rather than a tall one that lies.
   It cannot make 44px, and the escape is rule 4's Equivalent path, which is real
   here: every one of these gaps is also a full-width row in the archive chapter,
   carrying `.tl-gap` ("2.2d after the previous one") at --tap height. */
.ex:focus-visible { outline: 2px solid var(--resolved); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .ex { transition: none; } }

/* The figure is eleven rem of numeral; a dotted rule under it would be a bar.
   The annotation belongs to the caption, which is the part that names what the
   number is — and that is the thing the popover actually explains. */
.ex-figure {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px;
  text-decoration: none;
}
.ex-figure small { text-decoration: underline dotted var(--trace-quiet); text-underline-offset: 4px; }
.ex-figure:hover small { text-decoration-color: var(--ink-2); }

/* A mark has no text to underline, so its affordance is the deck note's own
   instruction plus the mark being hittable. Last night's law still holds and is
   the reason this is not simply padded out: the cap stays the width of the bar,
   and a mark reaches only as far as it can without answering for its neighbour.
   The UA gives a button padding and a min-width; both go, or a 7px bar renders
   16px wide and the tape stops being a tape. */
/* Only the button reset. The conditional reach lives ONCE, on `.tk-link`, which
   the mark still carries — two overlapping reaches on one element is how a mark
   starts answering for its neighbour again, and duplicating the rule would mean
   two places to keep the `:has()` conditions in step. */
.ex-mark {
  display: block;
  width: 100%;
  min-width: 0;
  padding: 0;
  text-decoration: none;
}

/* -------------------------------------------------------------- the popovers */

/* The UA default is `position: fixed; inset: 0; margin: auto; border: solid;
   padding: .25em` — a centred box with a hairline browser border. Anchor
   positioning only reached all three engines in Jan 2026 and Safari and Firefox
   are not at parity, so a real share of readers gets the centred fallback. It is
   styled as a deliberate card FIRST and anchored second, so the floor is a
   design and not a degradation: same plate, same edges, same type, just centred
   in the viewport instead of hung off its trigger. */
.pop {
  width: min(32ch, calc(100vw - 2rem));
  max-height: min(30rem, calc(100vh - 3rem));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0;
  background: var(--panel-raised);
  color: var(--ink);
  border: 1px solid var(--rule-strong);
  opacity: 0;
  transition: opacity 0.2s, overlay 0.2s allow-discrete, display 0.2s allow-discrete;
}
.pop:popover-open { opacity: 1; }
@starting-style { .pop:popover-open { opacity: 0; } }
.pop::backdrop { background: rgba(8, 9, 12, 0.5); }
@media (prefers-reduced-motion: reduce) { .pop { transition: none; } }

@supports (position-area: top) {
  .pop {
    margin: 0;
    inset: auto;
    position-area: top;
    position-try-fallbacks: flip-block, flip-inline;
    position-visibility: anchors-visible;
    justify-self: anchor-center;
    max-inline-size: min(32ch, calc(100vw - 2rem));
  }
}

/* the kicker names what KIND of thing is being explained, so a reader who opens
   three of these in a row learns the taxonomy without being told */
.pop-k {
  margin: 0;
  padding: var(--s-sm) var(--s-md) 0;
  font-size: 0.5625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.pop-t {
  margin: 4px 0 0;
  padding: 0 var(--s-md) var(--s-sm);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  border-bottom: 1px solid var(--rule);
}
.pop-b { padding: var(--s-sm) var(--s-md) var(--s-md); }
.pop-b p {
  margin: var(--s-sm) 0 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-2);
}
.pop-b p:first-child { margin-top: 0; }

/* label/value rows, same register grammar as the rhythm readouts */
.pop-d {
  margin: 0;
  padding: 0 var(--s-md) var(--s-sm);
}
.pop-d > div {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--s-sm);
  padding: 6px 0;
  border-top: 1px solid var(--rule);
}
.pop-d > div:first-child { border-top: 0; }
.pop-d dt { font-size: 0.8125rem; color: var(--ink-3); }
.pop-d dd {
  margin: 0;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.8125rem;
  color: var(--ink);
}

/* receipts keep the dateline shape they have everywhere else: host first in
   engraved mono, then the label underlined at reading size */
.pop-r {
  list-style: none;
  margin: 0;
  padding: 0 var(--s-md) var(--s-sm);
}
.pop-r li { border-top: 1px solid var(--rule); }
.pop-r li:first-child { border-top: 0; }
.pop-r a {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-height: var(--tap);
  justify-content: center;
  padding: 6px 0;
  font-size: 0.75rem;
}
.pop-r .r-src { font-size: 0.625rem; letter-spacing: 0.06em; color: var(--ink-3); }
.pop-r .r-label {
  color: var(--ink-2);
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 3px;
}
.pop-r a:hover .r-label { text-decoration-color: var(--resolved); }

/* the way out of a popover and into the chapter that covers it properly */
.pop-go {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: var(--tap);
  padding: var(--s-sm) var(--s-md);
  background: var(--panel);
  border-top: 1px solid var(--rule-strong);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.pop-go:hover { color: var(--ink-hi); background: var(--rule); }
.pop-go i { font-style: normal; color: var(--trace-quiet); }


/* -------------------------------------------------- the chapters, and the fold */

/* Seven chapters, all shipping closed, one open at a time (`name="more"`). This
   is the whole of /timeline/, /guide/ and /data/ folded back into the page Hill
   asked for, so the summaries are the table of contents and have to read like
   chapter titles rather than like disclosure widgets. */
.more { margin-top: var(--s-3xl); }
.ch {
  background: var(--panel);
  border: 1px solid var(--rule-strong);
  border-top: 0;
}
.more .ch:first-of-type { border-top: 1px solid var(--rule-strong); }
.ch-sum {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-md);
  min-height: 60px;
  padding: var(--s-sm) var(--s-lg);
  font-size: 1.0625rem;
  font-weight: 640;
  letter-spacing: -0.015em;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}
.ch-sum::-webkit-details-marker { display: none; }
.ch-sum::after {
  content: "+";
  flex: none;
  font-family: var(--mono);
  font-size: 1.125rem;
  font-weight: 400;
  color: var(--trace-quiet);
}
.ch-sum:hover { background: var(--panel-raised); }
.ch[open] > .ch-sum {
  background: var(--panel-raised);
  border-bottom: 2px solid var(--rule-strong);
}
.ch[open] > .ch-sum::after { content: "\2212"; }
.ch-body { padding: var(--s-lg); }
.ch-body > :first-child { margin-top: 0; }
.ch-body p {
  max-width: 68ch;
  margin: var(--s-md) 0 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-2);
}
.ch-body h3 {
  margin: var(--s-xl) 0 var(--s-sm);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
/* inside a chapter these plates already carry their own edge; a second one
   inside the chapter's edge would draw a box in a box */
/* Inside a chapter the plate is the chapter, so these lose their own side edges
   AND their own inline padding — with both, a glossary term sat 26px right of the
   prose directly above it and the chapter lost its left edge. */
.ch-body .glossary,
.ch-body .tl-list,
.ch-body .cl-list,
.ch-body .rhythm,
.ch-body .rh-gaps,
.ch-body .hour-hist,
.ch-body .hh-note { border-inline: 0; }
.ch-body .glossary > div { padding-inline: 0; }
.ch-body .glossary > div:first-child { border-top: 0; }
.ch-body .tl-row,
.ch-body .cl-row { padding-inline: 0; }

/* ------------------------------------------------------------ the table */

/* Nineteen rows of numbers. It scrolls inside its own box and never takes the
   page with it — a table that h-scrolls the document on a phone is a grade-1
   hard fail, and the escape is a scroll container, not a smaller font. */
.nums-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  margin-top: var(--s-md);
  border: 1px solid var(--rule-strong);
}
.nums {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.nums th,
.nums td {
  padding: var(--s-sm) var(--s-md);
  text-align: left;
  white-space: nowrap;
  border-top: 1px solid var(--rule);
}
.nums thead th {
  position: sticky;
  top: 0;
  background: var(--panel-raised);
  border-top: 0;
  border-bottom: 2px solid var(--rule-strong);
  font-family: var(--mono);
  font-size: 0.5625rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.nums tbody th {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--ink);
  white-space: normal;
  min-width: 14rem;
}
.nums td {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--ink-2);
}

/* ------------------------------------------- the lines that carry a quiet day */

/* On most days nothing is happening, and this line is the whole reason the page
   is still worth opening: it says where you are inside the current gap and what
   the record says about gaps this long. It is secondary to the figure and it is
   not throwaway — reading size, ink-2, its own measure, sitting directly under
   the number it qualifies. */
.ro-basis {
  max-width: 46ch;
  margin: var(--s-sm) 0 0;
  font-size: clamp(0.9375rem, 1.35vw, 1.0625rem);
  line-height: 1.5;
  color: var(--ink-2);
}
/* on the painting, not on a panel — the masthead's small chrome runs lighter */
.masthead .ro-basis { color: #CBD5DA; }

/* the histogram finally says what it counts and in what unit */
.hh-note {
  margin: 0;
  padding: 0 var(--s-lg) var(--s-md);
  background: var(--panel);
  border: 1px solid var(--rule-strong);
  border-block: 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.hour-hist + .hh-note { border-top: 0; }

/* the gap since the previous reset, on every row of the archive */
.tl-gap {
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  white-space: nowrap;
}

@media (max-width: 900px) {
  .ch-sum { padding-inline: var(--s-md); min-height: var(--tap); }
  .ch-body { padding: var(--s-md); }
  .hh-note { padding-inline: var(--s-md); }
  .nums tbody th { min-width: 11rem; }
}


/* ---------------------------------------------- an event opens where it sits */

/* The register rows became <details>: a row still shows its stamp, its verdict,
   its headline and its own slice of the shared window, and opening one drops the
   receipts underneath instead of navigating away. The summary keeps the exact
   layout the row had as a link, so nothing moves when the behaviour changes —
   only the marker is new, and it is the same +/- the chapters use. */
.logrow > .lr-sum {
  display: flex;
  align-items: flex-start;
  gap: var(--s-md);
  min-height: var(--tap);
  padding: var(--s-sm) var(--s-lg);
  cursor: pointer;
  list-style: none;
}
.logrow > .lr-sum::-webkit-details-marker { display: none; }
.logrow > .lr-sum::after {
  content: "+";
  flex: none;
  /* on the first line, not floating in the middle of a wrapped headline */
  align-self: flex-start;
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 1rem;
  line-height: 1.4;
  color: var(--trace-quiet);
}
.logrow[open] > .lr-sum::after { content: "\2212"; }
.logrow[open] > .lr-sum { background: var(--panel-raised); }
.lr-body { flex: 1 1 auto; min-width: 0; }

.lr-open {
  padding: 0 var(--s-lg) var(--s-md);
  border-top: 1px solid var(--rule);
}
.lr-receipts { list-style: none; margin: 0; padding: 0; }
.lr-receipts li { border-top: 1px solid var(--rule); }
.lr-receipts li:first-child { border-top: 0; }
.lr-receipts a {
  display: flex;
  align-items: baseline;
  gap: var(--s-sm);
  min-height: var(--tap);
  font-size: 0.75rem;
}
.lr-receipts .r-src { font-size: 0.625rem; letter-spacing: 0.06em; color: var(--ink-3); }
.lr-receipts .r-label {
  color: var(--ink-2);
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 3px;
}
.lr-receipts a:hover .r-label { text-decoration-color: var(--resolved); }
.lr-go {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: var(--tap);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.lr-go:hover { color: var(--ink); }
.lr-go i { font-style: normal; color: var(--trace-quiet); }

@media (max-width: 900px) {
  .logrow > .lr-sum { padding-inline: var(--s-md); }
  .lr-open { padding-inline: var(--s-md); }
  /* on a phone the receipt's host stacks above its label, as it does everywhere */
  .lr-receipts a { flex-direction: column; gap: 1px; justify-content: center; }
}


/* ------------------------------------------------------ the second lane */

/* Claude, finally visible above the archive. Hard rule 3 is explicit about the
   shape this must take: **structurally distinct, never greyed out** — a sparse
   lane, not a dimmed copy of the first, and never amber, which belongs to an
   open WATCH alone. The reservation has been carried in this file since the
   provider was cut from the page; this is it being spent.

   What makes it structurally distinct is not a treatment, it is the truth: Claude
   carries NO PERCENTAGE by policy, because Anthropic announces rarely enough that
   a rate cannot be measured honestly. So the strip has no figure at all — where
   Codex has an eleven-rem number, this has a qualifier saying why there isn't
   one. A reader can see the difference is a decision rather than a gap in the
   data, which is exactly what rule 9 asks a qualifier to earn its slot by doing.

   A rule above it, not a box around it: the masthead is "no panel and no rule"
   for the READING, and this is a second reading sharing the same picture — one
   hairline is the least that can separate two voices without framing either. */
.lane-claude {
  margin-top: var(--s-lg);
  padding-top: var(--s-md);
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  max-width: 34ch;
}
.cl-subject {
  margin: 0 0 2px;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.cl-state {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.4;
  color: #CBD5DA;
}
/* the qualifier is the whole point of the strip, so it is a phrase and not a
   chip — a chip would read as a status, and this is a scope */
.cl-qual {
  font-size: 0.8125rem;
  color: var(--ink-3);
}
/* no leading middot: the qualifier wraps to its own line at 390 and a separator
   stranded at the start of a line reads as a bullet point. The size step and the
   gap already separate it from the state. */
.cl-line {
  display: block;
  width: 100%;
  margin-top: 3px;
  font-size: 0.9375rem;
  color: var(--ink);
}
/* the heartbeat: without a percentage, "when did you last look" is the only
   thing that proves this lane is alive rather than abandoned */
.cl-checked {
  margin: var(--s-xs) 0 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.is-aging .cl-checked { color: var(--ink-2); }
/* scoped deliberately: `.cl-` is also the archive's call-log prefix, and those
   names live inside `.cl-list`. Nothing here may reach them. */
.lane-claude .ex { text-decoration-color: var(--trace-quiet); }
.lane-claude .ex:hover { text-decoration-color: var(--ink-2); }


/* -------------------------------------- the sentences the audit asked for */

/* Small print under the one thing on the page asking for something. It answers
   the questions a stranger has at the moment of deciding — what it covers, how
   often, what actually arrives — which is the only place they matter. */
.cta-sub {
  max-width: 52ch;
  margin: var(--s-md) 0 0;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--ink-3);
}

/* The scorecard's two new sentences. The card grades a named span, not the whole
   record, and a stranger reading "25 resets" above and a smaller number here has
   no way to know that without being told. `.sc-defs` carries the terms the rows
   cannot say inside a label. Both sit on the plate under the drawings, above the
   as-of line, in the same quiet ink the rest of the plate's prose uses. */
.sc-recon,
.sc-defs {
  max-width: 68ch;
  margin: 0;
  padding: var(--s-sm) var(--s-lg) 0;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--ink-3);
}
.sc-recon { padding-top: var(--s-md); border-top: 1px solid var(--rule); }
.sc-defs { padding-bottom: var(--s-sm); }

/* the budget under a rate's label — the scale a reader judges it against, said
   in words, the same job `_meter_note` does under the drawn value */
.scorecard dt small {
  display: block;
  margin-top: 2px;
  font-family: var(--sans);
  font-size: 0.75rem;
  letter-spacing: 0;
  color: var(--ink-3);
}

/* The short form of the same correction, visible while the row is closed. It
   shipped inheriting body style — 16px in full ink, identical to the headline
   directly above it — so an event's own sentence and the page's note about that
   sentence read as one run-on, and the lowercase opening made it look like a
   continuation rather than a separate claim.
   It is not demoted for being self-critical: it stays in reading ink with the
   hairline that marks a qualifying line everywhere else on this surface. It is
   the teaser for `.lr-note` below, so it is set as a mark on the row rather than
   as prose — the prose is what opens underneath. */
.lr-flag {
  display: inline-block;
  margin-top: 3px;
  padding-inline-start: var(--s-sm);
  border-inline-start: 2px solid var(--rule-strong);
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--ink-2);
}

/* An event whose day later verified a reset says so on its own row. This is the
   page correcting itself in public, which is the whole proposition — so it reads
   as a statement in ink, not as an apology in grey, and it takes the hairline
   indent that marks a qualifying line everywhere else on this surface. */
.lr-note {
  max-width: 68ch;
  margin: 0 0 var(--s-sm);
  padding-inline-start: var(--s-sm);
  border-inline-start: 2px solid var(--rule-strong);
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--ink-2);
}

/* three paragraphs now, and the middle one is a person taking responsibility for
   the page — set at the same weight as the legal floor around it, because that
   is what makes it read as a fact rather than a flourish */
.foot-legal p + p { margin-top: 6px; }

/* ---------------------------------------------------------------- foot */

/* .foot-nav is gone with the three pages; .foot-links stays. These were one
   grouped ruleset and deleting by selector prefix took BOTH — the footer shipped
   as `status.jsontimeline.jsonRSSbadge` until it was looked at. */
.foot-links { display: flex; gap: var(--s-lg); flex-wrap: wrap; }
/* one ruleset for both link groups — they were byte-identical — and the
   underline treatment that already works on .ro-rail rather than a border,
   which reads unfinished */
.foot-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-2);
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 4px;
  transition: color 120ms linear;
}
.foot-links a:hover {
  color: var(--ink);
  text-decoration-color: var(--ink-3);
}


/* Three zones with real intervals between them, not seven items stacked at one
   size and one gap. Who this is and whether it is live · where to go · the legal
   floor. */
footer {
  width: min(calc(100% - 2 * var(--gut)), var(--max));
  margin: var(--s-3xl) auto 0;
  padding: var(--s-lg) 0 var(--s-xl);
  border-top: 1px solid var(--rule);
}
footer p { margin: 0; font-size: 0.75rem; color: var(--ink-3); max-width: 62ch; }
/* the masthead dropped its header so the answer could lead; the brand, nav
   and live chip live here now, demoted to foot chrome on the page ground */
.foot-top,
.foot-mid {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-md) var(--s-lg);
  flex-wrap: wrap;
}
.foot-mid {
  margin-top: var(--s-lg);
  padding-top: var(--s-sm);
  border-top: 1px solid var(--rule);
}
.foot-legal { margin-top: var(--s-lg); display: grid; gap: 6px; }
.foot-brand { display: flex; align-items: center; gap: var(--s-md); flex-wrap: wrap; }
.foot-brand .brand { font-size: 1.125rem; }
.foot-brand .brand-mark { width: 32px; height: 32px; }
/* one ruleset for both link groups — they were byte-identical — and the
   underline treatment that already works on .ro-rail rather than a border,
   which reads unfinished */

@media (min-width: 901px) {
  :root { --gut: 48px; }
}


/* ------------------------------------------------- the document pages */

/* the h3 that opens an archive inside a chapter — a heading between two
   instruments, so it takes the chapter's interval above and the plate's below */

/* An anchor row, not a nav bar: it is a table of contents for one page, so it is
   set as engraved chrome on a rule rather than as buttons. */

/* A prose column inside an instrument page. 68ch because these are answers, not
   headlines, and the page measure is far too wide to read a paragraph across. */

/* ----------------------------------------------- the archive registers */

/* One plate, one row per record, in the same grammar as the index's event log:
   the stamp in engraved mono holds its own column so the dates align down the
   register, the kind is the content, and the receipts are datelines.
   A row is not a link — the receipts are — so nothing here pretends to be
   clickable that isn't. */
.tl-list,
.cl-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--panel);
  border: 1px solid var(--rule-strong);
}
.tl-row {
  display: grid;
  grid-template-columns: 13.5rem minmax(0, 1fr) auto;
  grid-template-areas:
    "when kind  scope"
    "when refs  refs";
  align-items: baseline;
  gap: 4px var(--s-lg);
  padding: var(--s-md) var(--s-lg);
  border-top: 1px solid var(--rule);
}
.tl-list > li:first-child,
.cl-list > li:first-child { border-top: 0; }
.cl-list > li { border-top: 1px solid var(--rule); }
.cl-list > li:first-child { border-top: 0; }

/* one provider's slice of the archive: a heading, what it amounts to, then the
   two registers. The lane exists because two providers' records must not read as
   one continuous list. */
.tl-lane + .tl-lane { margin-top: var(--s-2xl); }
.tl-lane h3 {
  margin: 0 0 var(--s-xs);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.tl-lane h4 {
  margin: var(--s-lg) 0 var(--s-sm);
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.tl-lane .doc-note { margin-top: 0; }
.tl-when {
  grid-area: when;
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--ink-3);
  white-space: nowrap;
}
.tl-kind {
  grid-area: kind;
  font-size: 0.9375rem;
  font-weight: 640;
  letter-spacing: -0.01em;
  color: var(--ink);
}
/* The scope is a qualifier, not a status, so it is engraved chrome rather than a
   chip — a chip here would compete with the docket's chips, where the shape does
   carry a verdict. */
.tl-scope {
  grid-area: scope;
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.tl-refs {
  grid-area: refs;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-xs) var(--s-lg);
}
.tl-ref {
  display: inline-flex;
  align-items: center;
  gap: var(--s-sm);
  min-height: var(--tap);
  font-size: 0.6875rem;
}
.tl-ref .r-src { color: var(--ink-3); }
.tl-ref .r-label {
  color: var(--ink-2);
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 3px;
}
.tl-ref:hover .r-label { text-decoration-color: var(--resolved); }
.tl-ref:hover .r-src { color: var(--ink-2); }

/* Zero records is a reading, not a blank: the archive says so in its own plate
   rather than disappearing and leaving a heading over nothing. */


/* An hour-of-day histogram is a count per slot, so it is drawn as a count —
   twenty-four exact bars over the ruler they are read off, in the meter's own
   language. It is not a rate and carries no ceiling it did not measure. */

/* -------------------------------------------------------------- mobile */
/* the deck is not a shrunken desktop deck: each provider becomes one unit
   of lane + reading, so both providers clear the fold at 390x844 */

@media (max-width: 900px) {
  /* the answer must still arrive first, so the artwork is a band rather than
     a column and the figure sits directly under it */
  /* 230px, not 168: a square source cropped into a 390-wide band shows
     height/390 of its own height, and the artwork's payload — both faces and
     the button — spans about 57% of the square. Below ~222px the band starts
     eating a face, which is the only thing in there worth keeping. */
  /* a phone crops a 16:9 painting down to a narrow central column, and the
     centre of a 16:9 frame is not where the subject is — the composition puts
     Tibo and the button right of centre so the left stays clear for the
     figure. Pull the crop across to them; the empty left field is what a
     phone gives up. */
  .stage-art { object-position: 66% 36%; }
  /* no header over the painting anymore, so the subject is never clipped —
     just reserve enough band for Tibo to read above the bottom-aligned
     readout */
  /* The picture gets a clean band and the reading sits under it, on the page's
     own ground. At 390 the masthead crops nothing vertically — a 1.78:1
     painting fitted to a 0.98:1 window loses only its sides — so the button and
     the creature sit wherever the painter put them, which is low, which is
     exactly where a bottom-up scrim is heaviest. Any wash strong enough to
     carry 10px mono buried the two things the picture is actually about.
     Below the band the copy needs no wash at all: --bg is a guaranteed floor,
     the picture keeps every pixel of its payload, and the band still dissolves
     into the ground so it arrives rather than stopping. */
  .masthead {
    min-height: 0;
    padding-top: var(--art-band);
    padding-bottom: var(--s-lg);
  }
  .stage-art { height: var(--art-band); }
  /* the full-height hero centres its reading in the quiet left field; a
     400px band has no such field, so here the reading keeps the floor */
  /* The reading overlaps the band's foot rather than clearing it. Measured on
     the at-rest frame, the picture's payload — the button, the creature, its
     screen — ends by y=295 of a 340px band, and everything below that is the
     dissolve. So the type is pulled up into the dissolve and stops short of the
     subject: one object, not two stacked, and nothing covered. 56px of dead
     ground read as two things; clearing it exactly still read as a seam. */
  .hero {
    align-self: start;
    margin-top: calc(-1 * var(--s-2xl) - var(--s-xs));
    padding-top: var(--s-xs);
  }
  /* That pull is measured against the picture's dissolve. When the pipeline is
     stale a banner takes the row above the reading, and the pull rode the
     headline up onto it — cyan on amber, 1.65:1. The banner keeps its own space
     and the reading only overlaps painting, never chrome. */
  .stale-banner:not([hidden]) ~ .hero { margin-top: 0; }
  .readout:not(.has-figure) .ro-state,
  .is-stale .ro-state { max-width: none; }
  /* The desktop scrim is a LEFT-to-right ramp because the desktop reading is a
     column in the left third. A phone has no left third: the readout runs the
     full 390 and lands square on the painting's payload, which at the landed
     frame is the lit button and a congregation holding up phone screens. Run
     the desktop ramp here and it darkens the face to buy contrast for copy
     that is nowhere near the left edge — 39% of the light off the top of the
     band for a floor it clears anyway.
     So on a phone the field is built on the other axis: the picture keeps its
     top, and its bottom falls into the ground the reading is written on. Same
     floor, 25% picture cost instead of 39%, and no weak spot — the headline's
     hardest tenth goes from 3.7:1 to 9.7:1 because the ramp no longer depends
     on where a bean happens to be standing.
     Measured on the settled landed frame at 390x844, which is the worst
     backdrop this copy ever gets. */
  /* The foot has to melt, not stop. Two things were making it a horizon line
     rather than a dissolve.
     First it was linear and short — 32px from lit picture to solid ground, with
     its steepest step right where the reading starts, so the eye caught the
     shoulder. This ramp is a smoothstep over 61px: imperceptible where it
     begins (0.03 at y=286), gentle past the payload (0.13 at y=293, and the
     button and creature end at 295), and only decisive in the last 20px where
     there is nothing left to protect.
     Second, and this is the one that showed: the scrim was mixing rgba(8,9,12)
     with var(--bg) #0A0C0E, so the picture faded to a black two points off the
     page's own black and left a seam at the band's edge. Every stop is the
     ground colour now, so the picture lands exactly on the page. */
  .masthead::after {
    height: var(--art-band);
    background:
      linear-gradient(to bottom,
        rgba(10, 12, 14, 0.300) 0%,
        rgba(10, 12, 14, 0.269) 2.4%,
        rgba(10, 12, 14, 0.194) 4.7%,
        rgba(10, 12, 14, 0.106) 7.1%,
        rgba(10, 12, 14, 0.031) 9.4%,
        rgba(10, 12, 14, 0) 11.8%),
      linear-gradient(to top,
        rgb(10, 12, 14) 0%,
        rgba(10, 12, 14, 0.972) 2.6%,
        rgba(10, 12, 14, 0.896) 5.3%,
        rgba(10, 12, 14, 0.784) 7.9%,
        rgba(10, 12, 14, 0.648) 10.6%,
        rgba(10, 12, 14, 0.500) 13.2%,
        rgba(10, 12, 14, 0.352) 15.9%,
        rgba(10, 12, 14, 0.216) 18.5%,
        rgba(10, 12, 14, 0.104) 21.2%,
        rgba(10, 12, 14, 0.028) 23.8%,
        rgba(10, 12, 14, 0) 26.5%);
  }
  /* the whole readout shares one horizontal inset so the state label, the big
     number and the caption align on the same left edge — otherwise the figure
     hugs the hero gutter while the label sits 18px further in */
  .readout { padding-inline: var(--s-md); }
  .ro-head { padding: 0 0 var(--s-sm); }
  .ro-figure { margin-top: var(--s-xs); }
  .ro-figure small { padding-bottom: 0.7em; }
  .ro-action { margin-top: var(--s-sm); padding-top: var(--s-xs); font-size: 1.0625rem; }
  .ro-why { padding: var(--s-sm) var(--s-md) var(--s-md); }
  /* the 400px band still wants the panel lifted into its foot */
  .evidence { margin-top: calc(-1 * var(--s-lg)); }
  .trace { margin-top: var(--s-xl); }
  .lane-head { padding: var(--s-md) var(--s-md) var(--s-xs); }
  /* --floor was --s-sm and the axis hairline was hard-coded --s-lg, so the line
     the bars are supposed to stand on floated 14px above their feet on every
     phone. It is --s-md now for a second reason as well: the reset register
     needs 12px under the baseline and 12px of floor left it sitting on the
     tape's own bottom border. */
  .tape { --bar: 116px; --pad: var(--s-md); --floor: var(--s-md);
          min-height: calc(var(--bar) + 10px); }

  /* a truncated receipt is not a receipt: full label, one per row, source
     dateline above it so a long headline never has to be clipped to fit */
  .ro-rail { margin-top: var(--s-xs); }
  .ro-rail a {
    padding: 5px 0;
    font-size: 0.875rem;
    line-height: 1.3;
  }
  .r-src { display: block; font-size: 0.5625rem; }
  .r-src::after { content: none; }
  .axis, .deck-note { padding-inline: var(--s-md); }

  /* the page's job is to answer three questions; section nav is exploration,
     so on a phone it moves out of the way of the answer and sits above the
     footer instead of eating 44px of the first screen */
  .site-head { padding: 6px 0; gap: var(--s-sm); }
  .brand-mark { width: 34px; height: 34px; }
  .brand { font-size: 1.1875rem; gap: 9px; }
  .site-head nav {
    order: 4;
    width: min(calc(100% - 2 * var(--gut)), var(--max));
    margin: var(--s-xl) auto 0;
    padding-top: var(--s-md);
    border-top: 1px solid var(--rule);
    position: absolute;
    inset-inline: 0;
    bottom: 0;
  }
  /* brand on its own line, then the plate line: tagline left, live state
     right — three header rows was a row too many on a phone */
  .tagline {
    order: 2;
    flex: 1;
    padding-inline-start: 0;
    border-inline-start: 0;
    font-size: 0.625rem;
    letter-spacing: 0.12em;
  }
  .live-chip {
    order: 3;
    margin-inline-start: 0;
    padding: 4px 8px;
    font-size: 0.5625rem;
    letter-spacing: 0.1em;
  }

  .deck { margin-top: var(--s-xs); }
  .lane-head { padding: 5px var(--s-md) 2px; }
  .ro-changed { font-size: 0.9375rem; max-width: none; }
  /* not 6px: this line is a control on a phone too, and at 6px of clearance its
     44px target lapped the receipt link above it — on the one device where a
     mistaken tap actually costs something. */
  .ro-fresh { margin-top: var(--s-md); font-size: 0.625rem; }

  /* the row is a block stack now, not a grid: date and state on one line, the
     headline under them, the shared strip last */
  .logrow { padding: var(--s-sm) var(--s-md); }
  .lr-body { flex-wrap: wrap; gap: 4px var(--s-sm); }
  .lr-head { flex: 1 1 100%; font-size: 0.9375rem; }
  .lr-meta { flex: 1 1 100%; }

  /* Below md a metric row restructures to a stack rather than forcing the page
     sideways — a table that h-scrolls on a phone is a hard fail (Hill, grade 1).
     `24rem 6.5rem 1fr` needs 488px and the viewport has 390, and the earlier
     `64px 58px` was a squeeze of the old 6px meter, not of this one. */
  .scorecard dl { padding: var(--s-xs) var(--s-md) var(--s-md); }
  .scorecard dl > div {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--s-xs);
    padding: var(--s-sm) 0;
  }
  .scorecard dd {
    grid-template-columns: minmax(0, 1fr) 5.5rem;
    align-items: end;
    gap: var(--s-sm);
  }
  .scorecard dt { font-size: 0.875rem; }
  .m-value { font-size: 1.125rem; }
  .sc-head { padding: var(--s-sm) var(--s-md); }
  .as-of { padding: var(--s-sm) var(--s-md) var(--s-sm); }
  .event-list .empty { padding: var(--s-md); }

  /* the rail turns vertical: one continuous edge down the stations */
  .pipeline { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .pipeline li { padding: var(--s-md) 0 var(--s-md) var(--s-xl); }
  .pipeline li::before {
    top: 0;
    bottom: 0;
    inset-inline: 10px auto;
    width: 2px;
    height: auto;
  }
  .pipeline li:last-child::before { inset-inline-end: auto; bottom: calc(100% - 34px); }
  .p-mark { top: var(--s-md); inset-inline-start: 0; }
}

/* between a phone and the two-column lane the readout drops below the trace,
   which frees vertical room — so the tape keeps a chart's height here instead
   of inheriting the phone's compressed strip */
@media (min-width: 641px) and (max-width: 900px) {
  .tape { --bar: 150px; --floor: var(--s-md); min-height: calc(var(--bar) + 14px); }
  .lane-head { padding: var(--s-md) var(--s-md) var(--s-xs); }
}


/* -------------------------------------- the new components on a phone */

/* Three registers side by side need about 200px each before the values start
   wrapping mid-phrase; a phone has 358px of measure. So they stack, and the
   divider turns from a column edge into a row rule — the strip is still the
   tape plate's header, just three rows of it instead of three columns. */
@media (max-width: 700px) {
  .pulse { grid-auto-flow: row; grid-auto-columns: auto; }
  .pulse-row {
    border-inline-start: 0;
    border-top: 1px solid var(--rule);
    padding-inline: var(--s-md);
  }
  .pulse-row:first-child { border-top: 0; }
}

@media (max-width: 900px) {
  /* The docket drops to a stack for the same reason the metric rows and the log
     rows do: `1fr auto auto` wants about 480px and a phone has 390, and a
     register that h-scrolls on a phone is a grade-1 hard fail. The date and the
     chip stay on one line together, because the pair is the reading. */
  .clock-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "subject subject"
      "due     status"
      "src     src"
      "chain   chain";
    gap: var(--s-xs) var(--s-sm);
    padding-inline: var(--s-md) var(--s-md);
    padding-inline-start: calc(var(--s-md) - 2px);
  }
  .ck-due { align-self: center; }
  .ck-status { justify-self: end; }
  /* "On a phone the host stacks above its label and each receipt takes a full
     row" — DESIGN.md's receipt rule, and the same treatment .r-src already takes
     here. As an inline-flex the wrapped label indented itself under the host's
     column, which is the accidental-looking rail the host-first rule exists to
     prevent. The chain takes its own row rather than sharing one with a receipt
     that now wraps. */
  .ck-src { display: block; }
  .ck-src b { display: block; }
  .ck-chain { justify-self: start; margin-top: var(--s-xs); }

  /* The track token is what everything measures from, so the phone only has to
     restate the gutter and the padding — the ruler, the datum and the axis
     follow it without a second set of rules. That is the point of the token. */
  .rhythm, .rh-gaps, .hour-hist { --rh-gutter: 2.75rem; }
  .rh-gaps, .hour-hist, .rh-note { padding-inline: var(--s-md); }
  .rh-metric { padding-inline: var(--s-md); }

  /* `13.5rem minmax(0,1fr) auto` needs well over 400px and a phone has 358, so
     the kind ran straight into the scope and printed "GlobalBAL reset" — text on
     top of text, a grade-1 fail, and precisely what DESIGN.md already says about
     log rows below md. The stamp and the scope share a chrome line, the kind gets
     the full measure, the receipts get their own row. */
  .tl-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "when  scope"
      "kind  kind"
      "refs  refs";
    gap: var(--s-xs) var(--s-sm);
    padding-inline: var(--s-md);
  }
  .tl-when { white-space: normal; }
  .tl-scope { justify-self: end; }
  .tl-list, .cl-list { border-inline: 0; }
  /* 24 bars in 358px is 13px each and the axis stops being readable long before
     the bars do — so the chart keeps every slot and the axis prints fewer of
     them. The drawing is never thinned; the labels are. */
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ============================================================ the event page

   /events/<id>/ is the permanent record — the page the tape's "The permanent
   record" link opens, the page every receipt in the archive resolves to, and the
   thing a stranger checks when they want to know whether this site is honest.
   It loaded this stylesheet and matched almost none of it: measured on the live
   page, TEN of its sixteen classes had no rule at all, so the product's proof
   surface rendered as a browser default — prose running to x=0 with no gutter,
   UA list numerals, a UA definition-list indent, and a light-grey system button
   on a near-black page.

   Nothing below is invented. Every rule here restates a treatment the index
   already teaches — the plate, the rules, the mono eyebrow, the receipt set as a
   dateline, the ruled lifecycle — because a record page that looked like a
   different product would undercut the same trust the styling is there to earn.
   And nothing below can reach the index: all ten class names appear on event
   pages only (checked against the rendered index, zero occurrences each), which
   is also why this could be done in one pass. */
.event-page {
  max-width: min(100% - var(--gut) * 2, 720px);
  margin: 0 auto;
  padding: var(--s-xl) 0 var(--s-3xl);
}
/* 720px, not --max: this page is a document to be read, and the index's 1180
   measure is for a chart. A receipt headline at 1180 runs past comfortable. */

.event-page .back {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  text-decoration: none;
}
.event-page .back:hover { color: var(--ink-2); }

.event-page .kicker {
  margin: var(--s-md) 0 0;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.event-page h1 {
  margin: var(--s-xs) 0 0;
  font-size: clamp(2rem, 5.5vw, 2.75rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
}
/* the headline is the event in the vendor's terms; it is the sentence the
   reader came for, so it is set as body prose at reading size rather than as a
   deck under a deck */
.event-headline {
  margin: var(--s-md) 0 0;
  font-size: 1.125rem;
  line-height: 1.5;
  color: var(--ink-2);
  max-width: 46ch;
}

/* the advice as it stood AT PUBLICATION — a plate, because it is the one thing
   on this page that is no longer true and the frame is what says so */
.event-action {
  margin-top: var(--s-xl);
  padding: var(--s-md) var(--s-lg) var(--s-lg);
  border: 1px solid var(--rule-strong);
  background: var(--panel);
}
.event-action .eyebrow { color: var(--ink-3); }
.event-action p + p { margin: var(--s-xs) 0 0; font-size: 1.0625rem; color: var(--ink); }
.event-action small {
  display: block;
  margin-top: var(--s-sm);
  padding-top: var(--s-sm);
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

.event-columns {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-2xl);
  margin-top: var(--s-3xl);
}
.event-columns h2 {
  margin: 0 0 var(--s-sm);
  padding-bottom: var(--s-xs);
  border-bottom: 1px solid var(--rule-strong);
  font-size: 0.6875rem;
  font-family: var(--mono);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Receipts, set exactly as `.ro-rail` sets them on the index: source first as a
   dateline because the judgeable half should land where the eye does, the whole
   row one link, --tap tall. The 2px `--rail` edge is the index's own sign for
   "this is what backs the reading". */
.receipt-list {
  list-style: none;
  margin: 0;
  padding-inline-start: var(--s-sm);
  border-inline-start: 2px solid var(--rail);
}
.receipt-list > li { position: relative; }
.receipt-list > li + li { border-top: 1px solid var(--rule); }
.receipt-list a {
  display: block;
  min-height: var(--tap);
  padding: 9px 0;
  font-size: 0.9375rem;
  line-height: 1.4;
  text-decoration: none;
}
.receipt-list .r-src { display: block; }
.receipt-list .r-src::after { content: none; }
.receipt-list a:hover .r-label { text-decoration-color: var(--resolved); }
.receipt-list a:hover .r-src { color: var(--ink-2); }

/* ---- the source that argued against

   A cited counter-argument used to be dropped, which let the archived page read
   more certain than the Telegram message a subscriber actually got. Publishing
   it is the point, so it is a receipt in the same shape as the others — same
   row, same dateline, same tap target — with one qualifier.

   It is drawn by SUBTRACTION, and that is the whole idea: the rail's cyan is the
   page's mark for "this backs the reading", so a source that argued the other way
   keeps the rail and loses the hue. Same move as a retraction and a late lead,
   both of which are hueless here for the same stated reason — a correction is not
   a third signal colour, it is the absence of one. Nothing is dimmed and nothing
   is struck through: this source is not weaker evidence, it is evidence pointing
   the other way, and a page that greys out its own inconvenient citation has
   quietly gone back to hiding it.

   The rail on `.receipt-list` is ONE continuous border and cannot change colour
   part-way down, so the item paints its own segment over it — as a positioned
   ::before rather than by pulling the item 14px leftwards with a negative
   margin, which was the first attempt and dragged the row's separator out with
   it, leaving one rule in four starting at a different x. Paint the mark, do not
   move the box. */
.receipt-list .r-counter::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(-1 * var(--s-sm) - 2px);
  width: 2px;
  background: var(--trace-quiet);
}
.receipt-list .r-counter .r-label { text-decoration-color: var(--trace-quiet); }
.receipt-list .r-counter a:hover .r-label { text-decoration-color: var(--ink-2); }
/* the qualifier is a note, not a badge: no pill, no box, no colour — the same
   register `.lr-note` uses for the page correcting itself, one line under the
   thing it qualifies */
.r-against {
  display: block;
  padding-bottom: 9px;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.r-against::before {
  content: "";
  display: inline-block;
  width: 12px;
  margin-inline-end: 7px;
  border-top: 1px solid var(--trace-quiet);
  vertical-align: 0.28em;
}

/* the lifecycle is a ruled list of states in order — the same shape the archive
   row uses, so an event reads the same way in both places */
.timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}
.timeline li {
  padding: var(--s-sm) 0;
  border-top: 1px solid var(--rule);
}
.timeline li:first-child { border-top: 0; }
.timeline b {
  font-size: 0.9375rem;
  font-weight: 660;
  letter-spacing: -0.01em;
}
.timeline time {
  display: block;
  margin-top: 3px;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.timeline small {
  display: block;
  margin-top: 5px;
  font-size: 0.875rem;
  line-height: 1.45;
  color: var(--ink-2);
}

/* the three facts that date the record. The UA gives dd a 40px indent, which is
   what put every value in orbit around its own label on the live page. */
.event-meta {
  margin-top: var(--s-3xl);
  border-top: 1px solid var(--rule-strong);
}
.event-meta dl { margin: 0; }
.event-meta dl > div {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  gap: var(--s-md);
  padding: var(--s-sm) 0;
  border-top: 1px solid var(--rule);
}
.event-meta dl > div:first-child { border-top: 0; }
.event-meta dt {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.event-meta dd { margin: 0; font-size: 0.9375rem; color: var(--ink-2); }

.event-cta { margin-top: var(--s-2xl); text-decoration: none; }

/* Above the phone the two lists sit side by side — receipts are the argument and
   the lifecycle is its chronology, and reading them together is the point of the
   page. Below it they stack, receipts first. */
@media (min-width: 720px) {
  .event-columns { grid-template-columns: 1.35fr 1fr; gap: var(--s-2xl); }
}
@media (max-width: 640px) {
  .event-page { padding-top: var(--s-lg); }
  .event-action { padding: var(--s-sm) var(--s-md) var(--s-md); }
  .event-meta dl > div { grid-template-columns: 1fr; gap: 2px; }
}

/* -------------------------------------------- the moved log + signal desk */

/* "Why the number moved" sits under the hero's answer (P0, 2026-08-28): the
   number is a claim and this is its seven-day audit trail. The signal desk
   after the evidence section names the lanes behind the number. Neither
   block recomputes anything — they explain, the hero answers. */
.moved {
  margin-top: var(--s-xl);
  padding-top: var(--s-md);
  border-top: 1px solid var(--rule);
}

.moved-title {
  margin: 0 0 var(--s-sm);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.moved-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-sm);
}

.moved-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-md);
  align-items: baseline;
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-2);
}

.mv-empty { margin: 0; color: var(--ink-3); }

.mv-day {
  min-width: 5ch;
  color: var(--ink-3);
}

.mv-delta {
  min-width: 12ch;
  color: var(--ink);
}

.mv-why a { color: var(--resolved); }

.hero-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-md);
  margin-top: var(--s-md);
}

.copy-forecast {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: var(--panel-raised);
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  padding: 0.45rem 0.8rem;
  cursor: pointer;
}

.copy-forecast:hover { border-color: var(--ink-3); }
.copy-forecast:disabled { opacity: 0.7; cursor: default; }

.hero-tg {
  font-size: 0.8125rem;
  color: var(--resolved);
  text-decoration: none;
}

.hero-tg:hover { text-decoration: underline; }

.signal-desk { margin-top: var(--s-3xl); }

.desk-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-sm);
  max-width: 46rem;
}

.desk-row {
  display: flex;
  align-items: flex-start;
  gap: var(--s-md);
  padding: var(--s-md);
  border: 1px solid var(--rule);
  background: var(--panel);
}

.desk-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 0.4rem;
  flex: none;
  background: var(--trace-quiet);
}

.desk-live .desk-dot { background: var(--resolved); }
.desk-degraded .desk-dot,
.desk-down .desk-dot { background: var(--primary); }

.desk-copy { flex: 1; }

.desk-copy b {
  display: block;
  font-size: 0.9375rem;
  color: var(--ink);
}

.desk-copy p {
  margin: 2px 0 0;
  font-size: 0.8125rem;
  color: var(--ink-2);
}

.desk-row time,
.desk-row > .mono {
  font-size: 0.6875rem;
  color: var(--ink-3);
  white-space: nowrap;
}
