/* Writ — the signed-out front page (#100). Linked only from landing.html,
   after tokens.css, which supplies the scheme, the reset and the product's
   semantic accents (--meaning, --wording, --blocked, --focus). Nothing in here
   applies to an app page.

   Three type families, split strictly by role: the user's prose is a serif
   (Newsreader, self-hosted), the interface is a grotesque (Inter), and
   identifiers — slugs, branches, paths, rule ids, handles — are mono. Mono is
   never decorative.

   One idiom for status: the marginal mark. A rule beside the affected line, the
   label outside the column. No pills in prose, no colour behind sentences; the
   only exception is the word-level highlight inside a before/after pair, where
   the sentence itself is the subject.

   No shadows. Separation is borders and ground shifts. */

/* ------------------------------------------------------------ 1. tokens */

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/newsreader-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/newsreader-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/inter-normal.woff2") format("woff2");
}

:root {
  /* The landing's map, dark first; light is the same names on paper stock.
     light-dark() so one declaration carries both and neither drifts. */
  --bg:          light-dark(#f7f5f1, #0e0e0d);
  --surface:     light-dark(#fffefc, #181817);
  --surface-2:   light-dark(#f0eee9, #1f1f1e);
  --border:      light-dark(#d9d6cf, #2b2b29);
  --border-soft: light-dark(#e6e3dd, #212120);
  --text:        light-dark(#14130f, #ecebe7);
  /* --muted clears 4.5:1 on --surface-2 in both schemes; --muted-2 does not,
     and is used only where the words are not the point (the canvas's own
     base/head labels, which the figcaption states in prose underneath). */
  --muted:       light-dark(#5f5c56, #8c8b84);
  --muted-2:     light-dark(#8a857d, #6a6963);
  --btn:         light-dark(#14130f, #ece9e4);
  --btn-text:    var(--bg);

  --r-control: 6px;
  --r-box: 11px;

  --serif: "Newsreader", "Source Serif 4", "Iowan Old Style", Charter, Georgia, serif;
  --ui:    "Inter", "Segoe UI Variable Text", "Segoe UI", ui-sans-serif, system-ui,
           -apple-system, "Helvetica Neue", sans-serif;
  --mono:  "Cascadia Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* The margin every marked line hangs its label in. */
  --marg: 150px;
  --ease: cubic-bezier(.2, .6, .3, 1);
}

/* ------------------------------------------------------------ 2. ground */

html { scroll-behavior: auto; }

body.landing {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 16px/1.55 var(--ui);
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.landing a { color: inherit; text-decoration: none; }
.landing a:hover { text-decoration: underline; text-underline-offset: 2px; }
/* :where() so this reset carries no specificity at all. Written as `.landing p`
   it scored (0,1,1) and silently beat every single-class rule in this file that
   set a margin on one of these elements — sixteen of them, all computing to 0:
   .section-lede, .crumb, .lede, .review-path, .doc-h, .pair-label,
   .pair-before/.pair-after, .pair-verdict, .finding-head, .finding-text,
   .thread, .rule-text, .rule-stats, .checks-head, .disclosure. That is why a
   section lede sat hard against the document under it and a finding's text
   against its actions. The .menard note in §15 is this same trap, found once
   and patched only where it was noticed. (#144) */
:where(.landing) :is(p, h1, h2, h3, ul, ol, figure, pre) { margin: 0; }
.landing ul, .landing ol { padding: 0; list-style: none; }
.landing :focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 3px; }

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 32px; }
.section { padding: 96px 32px; border-top: 1px solid var(--border-soft); }
.section h2 {
  font: 600 30px/1.2 var(--ui);
  letter-spacing: -.015em;
  max-width: 760px;
  margin-bottom: 32px;
}
/* One line under a section's heading, on the history figure's own pattern: the
   heading's 32px is the gap to the thing it introduces, so the lede takes that
   space back and carries it itself, and the two read as one block. */
.section-lede {
  max-width: 620px;
  margin: -20px 0 32px;
  font-size: 17px;
  color: var(--muted);
}

.ident { font-family: var(--mono); font-size: .92em; }
.doc { font-family: var(--serif); font-size: var(--t-xl); line-height: 1.5; }
.muted { color: var(--muted); }
.aside { font: italic 400 18px/1.4 var(--serif); color: var(--muted); }

.skip {
  position: absolute; left: 16px; top: 12px; z-index: 30;
  padding: 6px 10px;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--text); border-radius: var(--r-control);
  font-size: var(--t-md);
  transform: translateY(-200%);
}
.skip:focus { transform: none; text-decoration: none; }

/* ------------------------------------------------------------ 3. buttons */

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 16px;
  min-height: 36px;
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  background: var(--surface);
  color: var(--text);
  font: 500 14px/1 var(--ui);
  cursor: pointer; white-space: nowrap;
}
.btn:hover { text-decoration: none; background: var(--surface-2); }
.landing .btn-fill { background: var(--btn); border-color: var(--btn); color: var(--btn-text); }
.landing .btn-fill:hover { background: var(--btn); color: var(--btn-text); opacity: .92; }
.btn-ghost { background: transparent; border-color: var(--border); }
.btn[disabled] { cursor: default; color: var(--muted); }

/* ------------------------------------------------------------ 4. marks */

/* The marginal mark. `.marked` is the affected block: a rule down its left
   edge, its label absolutely placed in the margin to the left of the rule.
   The label reads as a word, always; colour is redundant with it. */

.mark {
  display: inline-block;
  font: 500 13px/1.4 var(--ui);
  letter-spacing: 0;
  white-space: nowrap;
  color: var(--text);
}
/* The rule at the head of every mark, drawn rather than typed.

   It used to be the character ❙ (U+2759). Neither Inter nor Newsreader has it,
   so every one of these fell back to whatever face on the machine did, and at
   13px the result read as a 1 — or an l, or an I, depending on the fallback.
   A 3px box in currentColor is the same shape on every machine, takes the
   mark's own colour for free, and scales with the type. */
.mark::before, .writ-mark::before {
  content: "";
  display: inline-block;
  width: 3px;
  height: 0.82em;
  margin-right: 6px;
  vertical-align: -0.06em;
  border-radius: 1px;
  background: currentColor;
}
.mark-meaning { color: var(--meaning); }

.mark-margin {
  position: absolute;
  right: calc(100% + 14px);
  top: .2em;
  width: calc(var(--marg) - 14px);
  text-align: right;
}

/* ------------------------------------------------------------ 5. nav */

.nav {
  position: sticky; top: 0; z-index: 10;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border-soft);
}
.nav-row { display: flex; align-items: center; justify-content: space-between; height: 58px; }
.brand { display: inline-flex; align-items: center; gap: 10px; font: 600 16px/1 var(--ui); }
.logo { display: block; color: var(--text); }
.logo-overlap { fill: var(--meaning); }
.nav-links { display: flex; align-items: center; gap: 22px; font: 500 14px/1 var(--ui); }
.nav-links a { color: var(--muted); }
.nav-links a:hover { color: var(--text); }
.nav-links .btn { color: var(--btn-text); }

/* ------------------------------------------------------------ 6. hero */

.hero {
  display: grid;
  grid-template-columns: 1fr 520px;
  gap: 56px;
  align-items: center;
  padding-top: 72px;
  padding-bottom: 72px;
}
/* No --marg indent here (#142). The headline is the largest thing on the page,
   and it starts where the brand and every h2 start; a second left edge 150px in
   made the fold read as three columns. The mark it would have hung there takes
   the treatment §15 gives every mark below 900px — above its block, outside the
   prose still. The gutter bought little either way: .hero-mark is hidden for
   most of the headline's cycle, so it stood empty. */
.hero-copy { padding-left: 0; }
.crumb { color: var(--muted); font-size: var(--t-md); margin-bottom: 26px; }
.marked-line { position: relative; }
.hero h1 {
  font: 600 46px/1.1 var(--ui);
  letter-spacing: -.025em;
  margin-bottom: 22px;
}
/* Static, and its height reserved: the mark appears and disappears every cycle
   and nothing under it may move (landing_check §10). */
.hero-mark {
  position: static;
  display: block;
  width: auto;
  height: 1.4em;
  text-align: left;
  margin-bottom: 6px;
  visibility: hidden;
}
.hero-mark.on { visibility: visible; }

/* The headline's last word.

   .hl is a fixed-width slot, not a shrink-to-fit span. landing.js measures every
   word the cycle can show — the wrong ones and "changed." — and writes the widest
   into --hl-w. Without that the line reflowed on every 7-second cycle: the words
   differ by up to 106px at 46px type, which re-broke the h1 and shoved the lede,
   the buttons and (at 375px) the whole page below by 221px. The slot is the last
   thing on its line, so the reserved tail is empty space nobody sees.

   The strike is on .hl-word, not on .hl: it has to be the width of the word being
   struck, not of the slot. */
.hl { display: inline-block; inline-size: var(--hl-w, auto); vertical-align: top; }
.hl-word { position: relative; display: inline-block; white-space: pre; }
.hl-word::after {
  content: "";
  position: absolute; left: 0; right: 0; top: 54%;
  height: 2px;
  background: var(--blocked);
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.hl.struck .hl-word::after { transform: scaleX(1); transition: transform 380ms var(--ease); }
.hl.wrong .hl-word { color: var(--muted); }
.hl.decaying .hl-word { color: var(--muted-2); }

.lede { font-size: var(--t-xl); line-height: 1.5; max-width: 560px; margin-bottom: 14px; }
.hero .aside { margin-bottom: 30px; }
.cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
/* inline-block so the width landing.js reserves for the longer dialect actually
   applies — min-inline-size is ignored on an inline box, and this note sits
   last in a wrapping row, where 85px of growth re-wrapped the row. */
.cta-note { display: inline-block; color: var(--muted); font-size: 14px; margin-left: 4px; }

.dialect {
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--border-soft);
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px;
}
.dialect-buttons { display: inline-flex; gap: 6px; }
.dialect-btn[aria-pressed="true"] { background: var(--surface-2); border-color: var(--text); }
.dialect-aside { font-size: 16px; }

.hero-object { display: grid; gap: 12px; }
.hero-canvas {
  display: block;
  width: 100%;
  height: 470px;
  border: 1px solid var(--border);
  border-radius: var(--r-box);
  background: var(--surface);
}
.hero-caption {
  display: flex; justify-content: space-between; gap: 4px 12px; flex-wrap: wrap;
  color: var(--muted); font-size: var(--t-sm);
}
/* The epigraph's credit, in the amber the overlap is drawn in, so the colour
   does the pointing and the caption does not have to. The title is set in the
   prose face because it is a book; the rest of the caption is an identifier and
   stays mono. */
.hero-caption-mark { color: var(--meaning); }
.hero-caption-mark em { font: italic 400 1.15em/1 var(--serif); }

/* --------------------------------------------------- 6b. the graph band */

/* Full bleed inside the wrap rather than a column: the graph runs right to
   left, so width is the thing it needs, and at 1180px it gets all of it. No
   border and no ground shift — the canvas paints its own fades at both edges
   and the band should read as part of the page, not as a picture set into it. */
/* Full bleed, and no words of its own: both figures lost their heading and
   their caption, which between them said six times over what the pictures were
   already showing. */
.band { padding: 0 0 72px; }
/* Sized and weighted like the slogan over the figure above it, so the two read
   as one voice rather than as a caption and a headline. */
.band-title {
  font: 600 31px/1.25 var(--ui);
  letter-spacing: -.015em;
  max-width: 760px;
  margin-bottom: 26px;
}
/* The line under the history figure's claim: it carries what §6 used to say,
   that two changes which share no words can still contradict. Held to the
   title's own measure so the two read as one block. */
.band-lede {
  max-width: 760px;
  margin: -14px 0 26px;
  font-size: 17px;
  color: var(--muted);
}
.band-object { display: block; }
/* No border, no ground, no radius: the piece paints on the page and there is
   nothing to draw a box around. The script scales the composition from its
   authored size and sets this height to match, so declaring one here would
   fight it and leave a gap under the piece at every width but one. overflow is
   hidden because a branch swings past the composition's own edge. */
.band-stage-box {
  position: relative;
  width: 100%;
  overflow: hidden;
}
/* The figure's progress, and its pause: one ring beside the piece (#372).

   A circle that fills as the piece plays, and the same circle is the button.
   It replaces a vertical line and handle, which replaced a horizontal
   scrubber, which replaced a play button. The object keeps changing; the reason
   it exists does not, and it is worth saying once here too: a figure plays on
   its own for the better part of a minute, and WCAG 2.2.2 requires that
   anything moving for more than five seconds can be stopped.

   A ring cannot be mistaken for a video scrubber — it is the size of a mark
   rather than the width of the picture, it has no handle and no time on it. It
   also cannot carry a drag at 26px, so there is no seeking: 2.2.2 asks for the
   pause, not the position.

   It sits on the *heading's* line rather than beside the picture (#372): the
   eye should find the control where the piece is named. The slot is a
   zero-height first child of the heading's own `.wrap`, so `right: 100%` is the
   page column's content edge — the column the composition's ink is aligned to —
   and the ring hangs off it into the margin, taking no space and moving
   nothing. */
.ring-slot { position: relative; height: 0; }
.ring {
  position: absolute;
  right: 100%;
  margin-right: 10px;
  top: 5px;
}
.ring-press {
  display: block;
  width: 26px; height: 26px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  color: var(--muted);
}
.ring-press:hover { color: var(--text); }
.ring-press svg { display: block; width: 26px; height: 26px; }
/* The track is the page's own hairline; the fill is the product's red, which is
   what #372 asked for. `--blocked` is that red — the same one the strike under
   the headline uses and the same one a blocked change is marked in. */
.ring-track { stroke: var(--border); stroke-width: 2; }
.ring-fill {
  stroke: var(--muted);
  stroke-width: 2;
  stroke-linecap: round;
  transition: stroke-dashoffset 90ms linear;
}
/* The glyph is currentColor, so it follows the button's own hover rather than
   the ring's red: the ring says how far through, the glyph says what a click
   will do. */
.ring-bar, .ring-tri { fill: currentColor; }
.ring .ring-tri { display: none; }
.ring[data-playing="no"] .ring-bar { display: none; }
.ring[data-playing="no"] .ring-tri { display: inline; }

/* The still's own words, under the frame, for a reader who has asked for less
   motion: the account of the piece its `aria-label` already carried, shown
   rather than only announced. The same string, so there is nothing to fall out
   of step with. */
.figure-still {
  max-width: 640px;
  margin-top: 24px;
  font-size: 17px;
  line-height: 1.55;
  color: var(--muted);
}
/* The two used to be pressed together at 24px, on the argument that they read
   as one figure in two states. They do not any more: the second now carries a
   claim of its own over it rather than a line pointing back at the first, and
   the first ends on three outcome boxes. Two things that each finish need room
   between them. */
.band-live { padding-bottom: 88px; }

/* ------------------------------------------------------------ 13. projects */

.projects { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
.project {
  display: grid; gap: 8px;
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--r-box);
  background: var(--surface);
}
.project:hover { text-decoration: none; border-color: var(--text); }
.project-name { font-size: var(--t-lg); }
.project-desc { font-size: 17px; }
.project-owner { font-size: var(--t-md); color: var(--muted); }
.project-counts { display: flex; gap: 16px; font-size: var(--t-md); color: var(--muted); }
.project-counts strong { color: var(--text); font-weight: 600; }
.project-counts .is-blocked strong { color: var(--blocked); }

/* ------------------------------------------------------------ 14. close, footer */

.close { display: grid; gap: 22px; justify-items: start; }
.close h2 { margin: 0; }

.footer { border-top: 1px solid var(--border-soft); padding: 28px 0; }
.footer-row { display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; font-size: 14px; color: var(--muted); }
.footer-links { display: flex; gap: 20px; }

/* ------------------------------------------------------------ 15. responsive */

@media (max-width: 1100px) {
  .hero { grid-template-columns: 1fr 440px; gap: 40px; }
}

@media (max-width: 900px) {
  :root { --marg: 0px; }
  .band-title { font-size: 24px; }
  .band { padding-bottom: 56px; }
  .band-live { padding-bottom: 72px; }
  .hero { grid-template-columns: 1fr; padding-top: 48px; }
  .hero-object { order: 2; }
  .hero-canvas { height: 380px; }
  /* Below the margin's width the label sits above its block, outside the
     prose still — never inside the sentence. */
  .mark-margin { position: static; display: block; width: auto; text-align: left; margin-bottom: 6px; }
  .mark-stack { align-items: flex-start; }
}

@media (max-width: 560px) {
  .wrap, .section { padding-left: 20px; padding-right: 20px; }
  .section { padding-top: 64px; padding-bottom: 64px; }
  .hero h1 { font-size: 34px; }
  .section h2 { font-size: 25px; }
  .doc, .lede { font-size: 17px; }
  .hero-canvas { height: 300px; }

  /* Twenty pixels of padding cannot hold a 26px circle, so here the ring stops
     hanging in the margin and stacks above the heading instead — still on the
     heading's own left edge, still the first thing in the block the title
     names. It stays a special case for the one reason that it is a physical
     one: there is no margin at this width to put anything in. */
  .ring-slot { height: auto; margin-bottom: 14px; }
  .ring { position: static; margin: 0; }

  .nav-links { gap: 14px; }
}

@media (max-height: 820px) {
  .band-title { font-size: 26px; }
  .band-lede { font-size: 16px; margin: -12px 0 20px; }
  .band { padding-bottom: 48px; }
  .band-live { padding-bottom: 68px; }
  .hero { padding-top: 56px; padding-bottom: 56px; }
  .section { padding-top: 72px; padding-bottom: 72px; }
}

/* ------------------------------------------------------------ 16. motion */

/* Everything that moves is driven by landing.js and checks this query itself.
   Here: the two CSS transitions stop, and the headline holds its end state. */
@media (prefers-reduced-motion: reduce) {
  .hl.struck::after { transition: none; }
  .hero-mark { visibility: visible; }
}

/* An agent's mark, in front of its handle in both figures: a head and two eyes,
   sized in em so it follows whatever handle it sits in, and in currentColor so
   it works on the inverted caret label as well as on the page. Drawn rather
   than typed for the reason above — the one glyph this page used for a mark was
   in neither face and came out as a `1`. */
.bot {
  display: inline-block;
  position: relative;
  width: .92em;
  height: .78em;
  margin-right: 5px;
  vertical-align: -.08em;
  border: 1px solid currentColor;
  border-radius: .22em;
  opacity: .8;
}
.bot::before,
.bot::after {
  content: "";
  position: absolute;
  top: .22em;
  width: .15em;
  height: .15em;
  border-radius: 50%;
  background: currentColor;
}
.bot::before { left: .17em; }
.bot::after { right: .17em; }


/* ------------------------------------------------- 9b. what you can ask

   The third figure (#180). Everything here is scoped under .ask-fig because
   the names are generic — .commit, .slot, .frame — and the page is one
   stylesheet. Sizes are stage units: the script scales the whole composition,
   so these are authored once and never respond to the viewport themselves. */
.band-ask { padding-bottom: 96px; }

.ask-fig { position: absolute; }
.ask-fig > * { position: absolute; }

/* One line that rubs itself out and writes the next. */
.ask-title {
  font: 600 27px/1.3 var(--ui);
  letter-spacing: -.015em;
  color: var(--text);
  width: 900px;
}
.ask-bar {
  display: inline-block; width: 2px; height: .8em;
  margin-left: 4px; vertical-align: -.06em; background: var(--text);
}

/* The exchange: them on the left, you on the right, one size for both. */
.ask-chat { display: flex; flex-direction: column; gap: 11px; }
.ask-msg { display: flex; gap: 11px; align-items: flex-start; max-width: 700px; }
.ask-msg.ask-me { align-self: flex-end; flex-direction: row-reverse; }
.ask-who { flex: none; font: 400 11px/2.4 var(--mono); color: var(--muted); white-space: nowrap; }
/* The one rounded thing in any of the three figures, and deliberately:
   everything else is a document surface or a mark on one, and those are square.
   A bubble is neither — it is somebody talking. The corner nearest the speaker
   is tightened, which is what makes it read as a bubble and not a card. */
.ask-bub {
  border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
  border-radius: calc(var(--r-box) + 3px);
  padding: 9px 15px;
  font: 400 17px/1.5 var(--serif);
}
.ask-me .ask-bub { background: var(--surface-2); border-top-right-radius: 4px; }
.ask-them .ask-bub { background: var(--surface); border-top-left-radius: 4px; }

/* The phone: one column, smaller type, and the bubbles take the width they are
   given rather than a fixed 700. */
.ask-narrow .ask-title { font-size: 21px; width: 480px; }
.ask-narrow .ask-msg { max-width: 460px; }
.ask-narrow .ask-bub { font-size: 14px; padding: 7px 11px; }
.ask-narrow .ask-doc { padding: 16px 18px 18px; font-size: var(--t-lg); }
.ask-narrow .ask-what { font-size: 12.5px; }
.ask-narrow .ask-verdict { min-width: 132px; }
.ask-narrow .ask-say, .ask-narrow .ask-prop { font-size: var(--t-md); }
.ask-caret {
  display: inline-block; width: 2px; height: .86em;
  vertical-align: -.08em; background: var(--text); margin-left: 3px;
}
.ask-working { font: 400 var(--t-md)/1.5 var(--ui); color: var(--muted); }
.ask-working i { font-style: normal; letter-spacing: .18em; }

/* Figure 1's frame, to its own numbers. */
.ask-frame-head {
  height: 38px; display: flex; align-items: center;
  justify-content: space-between; padding: 0 16px;
}
.ask-path { font: 400 var(--t-md)/1 var(--mono); color: var(--muted); }
.ask-counts {
  display: flex; gap: 14px;
  font: 400 var(--t-md)/1 var(--ui); color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ask-counts b { color: var(--text); font-weight: 500; }
.ask-doc {
  padding: 26px 32px 30px;
  font: 400 21px/1.75 var(--serif);
  color: var(--text);
  text-wrap: pretty;
}
.ask-slot {
  padding: 0 2px; margin: 0 -2px; border-radius: 2px;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

/* The rail: what the agent is doing, beside the thing it is doing it to. */
.ask-rail-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font: 500 12.5px/1.4 var(--ui); color: var(--muted);
}
.ask-rail-who { font-family: var(--mono); color: var(--text); }

/* A change is a commit: an id, what it does, and a verdict once it has been
   through. The verdict is in the row's own margin as well as at its end — a
   colour at the far right of a 430-unit row is not what a reader scans. */
.ask-commit {
  display: flex; align-items: baseline; gap: 11px; padding-left: 11px;
  font: 400 var(--t-md)/1.5 var(--ui);
}
.ask-commit::before {
  content: ""; position: absolute; left: 0; top: 3px; bottom: 3px;
  width: 3px; border-radius: 1px; background: transparent;
}
.ask-done-w::before { background: var(--wording); }
.ask-done-m::before { background: var(--meaning); }
.ask-id { flex: none; width: 54px; font: 400 11.5px/1.7 var(--mono); color: var(--muted); }
/* One line each, ellipsised: the rows sit on a fixed pitch, so a row that
   wrapped ran straight through the row under it. A commit list truncates. */
.ask-what {
  flex: 1 1 auto; min-width: 0;
  font: 400 14.5px/1.5 var(--serif);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ask-verdict {
  flex: none; min-width: 152px; text-align: right;
  font: 500 11.5px/1.5 var(--ui); color: var(--muted);
}
.ask-verdict.on::before {
  content: ""; display: inline-block; width: 3px; height: .82em;
  margin-right: 5px; vertical-align: -.06em; background: currentColor;
}
.ask-v-wording { color: var(--wording); }
.ask-v-meaning { color: var(--meaning); }
.ask-tally {
  font: 500 var(--t-md)/1.5 var(--ui); color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ask-tally b { color: var(--text); }
.ask-wait { color: var(--meaning); }

.ask-node-label { font: 400 11px/1.4 var(--mono); color: var(--muted); text-align: center; }
.ask-said-row { display: flex; gap: 10px; align-items: baseline; }
.ask-who-m { flex: none; width: 92px; font: 400 11.5px/1.7 var(--mono); color: var(--muted); }
.ask-say { font: 400 14.5px/1.5 var(--serif); color: var(--text); }

.ask-fix { font: 400 var(--t-md)/1.55 var(--ui); color: var(--muted); }
.ask-why {
  display: block; margin-bottom: 2px;
  font: 500 11.5px/1.4 var(--ui); color: var(--meaning);
}
.ask-why::before {
  content: ""; display: inline-block; width: 3px; height: .82em;
  margin-right: 5px; vertical-align: -.06em; background: currentColor;
}
.ask-prop {
  padding: 0 3px;
  font: 400 14.5px/1.5 var(--serif); color: var(--text);
  background: color-mix(in srgb, var(--wording) 20%, transparent);
}

/* The caret on a figure's own line, for the two the script writes: it edits
   itself as the piece plays, so it reads as somebody typing rather than as a
   heading that happens to change. */
.band-bar {
  display: inline-block;
  width: 2px;
  height: .82em;
  margin-left: 4px;
  vertical-align: -.04em;
  background: var(--text);
}
