/* ============================================================================
   THE INPUT REGISTRY KIT: COMPONENT CSS
   No raw hex lives here. Build assertion 19 sweeps this file and fails on one.
   Everything reads through the tokens in tokens.css.

   Shadow, non-zero elevation and backdrop blur are FORBIDDEN on the dark
   theme (P1A C30). On dark, separation is bought with a border. On light, a
   soft shadow carries it and the border is only definition (P1A C29). The
   component does not branch on theme; the token does.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: 1.5;
  padding-bottom: var(--dock-inset);            /* nothing hides behind the dock */
}

/* Focus: defined ONCE globally (P1A B12). :focus-visible only. */
:focus-visible {
  outline: 2px solid var(--accent-ui);
  outline-offset: 2px;
  border-radius: var(--radius-focus);
}
.ledger :focus-visible { outline-color: var(--accent); }

/* Motion: the chevron rotates. NOTHING ELSE ANIMATES. Contract 1.4. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

a { color: var(--accent-ui); }
h1, h2, h3 { line-height: 1.25; margin: 0; }

.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.caption { font-size: var(--t-caption); color: var(--text-muted); }
.muted { color: var(--text-muted); }
.tertiary { color: var(--text-tertiary); }

/* Kicker: mono, uppercase, tracked, accent at 80 per cent. Contract 1.4. */
.kicker {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--accent-ui);
  opacity: 0.8;
  display: block;
  margin-bottom: var(--sp-1);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- SYNCBAR
   Its HEIGHT NEVER CHANGES, which is what stops the layout shifting on every
   state change (contract 3.11). Teal is BANNED for "synced", because teal is
   spent on actions. Never a toast, banner or modal. */
.syncbar { position: sticky; top: 0; height: 4px; width: 100%; z-index: 40; }
.syncbar[data-state="synced"]  { background: var(--success); }
.syncbar[data-state="queued"]  { background: var(--warning); }
.syncbar[data-state="partial"] { background: var(--warning); opacity: 0.6; }
.syncbar[data-state="error"]   { background: var(--danger); }

/* ------------------------------------------------------------ LEDGER HEADER
   Always open. Never collapsible. At the top of <main>, ABOVE the h1
   (GOV.UK error-summary placement). Contract 3.5. */
.ledger {
  background: var(--ledger-bg);
  color: var(--ledger-text);
  padding: var(--sp-6) var(--sp-4) var(--sp-8);
  border-bottom: 1px solid var(--ledger-line);
}
.ledger a { color: var(--ledger-accent); }
.ledger .kicker { color: var(--ledger-accent); }
.ledger-inner { max-width: 1240px; margin: 0 auto; }
.ledger h1 { font-size: var(--t-headline); margin: var(--sp-2) 0 var(--sp-1); }
.ledger .scopeline { color: var(--ledger-muted); font-size: var(--t-caption); }

/* ---------------------------------------------------------- THE ANSWER
   AMENDED P6. The commission is "what do I do next", on a phone, at 7am, and
   it was 2,358px and 2,604px below the fold. Ninety per cent of the first
   screen was a kicker, a title, two paragraphs of scope prose, a count, a
   split of counts, a deadline line, a section heading and an eighty five pixel
   paragraph explaining an attribution rule.

   This block is the answer, and it is FIRST. Nothing was collapsed to make
   room for it: the full blocking list, the loud list, the conflicts, the
   aborts, the caveats and the rollup rule are all still open, still in the
   document and still reachable by find in page, BELOW it. The order changed,
   not the contents.

   Budget at 358px content width: kicker 18, name up to two lines 46, owed
   label 20, why up to two lines 36, count strip 22, button 44. Under 220px of
   text plus 32px of padding, so the answer AND the counts AND the control are
   above a 684px fold with the whole title block still to come. */
.answer {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: var(--sp-3) var(--sp-4);
  align-items: start;
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--ledger-line);
  border-radius: var(--radius-card);
}
.answer[data-tone="green"] { border-color: color-mix(in srgb, var(--success) 55%, transparent); }
.answer[data-tone="amber"] { border-color: color-mix(in srgb, var(--warning) 55%, transparent); }
.answer[data-tone="unknown"] { border-color: var(--danger); border-width: 2px; }
.answer-text { min-width: 0; }
.answer-kicker {
  display: block; font-family: var(--font-mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: 0.16em; color: var(--ledger-accent);
}
.answer-what { font-size: var(--t-section); font-weight: 700; line-height: 1.2; margin-top: 4px; }
.answer-what a { color: var(--ledger-text); text-decoration: none; border-bottom: 1px solid var(--ledger-accent); }
.answer-owed { font-weight: 600; margin-top: var(--sp-2); }
.answer-why { font-size: var(--t-caption); color: var(--ledger-muted); margin-top: 2px; max-width: 62ch; }
.answer-counts {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-top: var(--sp-3); font-size: var(--t-caption); color: var(--ledger-muted);
}
.answer-counts b { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ledger-text); font-size: var(--m-body); }
/* The control sits on its own row below the text on a phone and beside it on a
   wider screen, so it is never the thing that pushes the answer off the fold. */
.answer-go { grid-column: 2; justify-self: start; min-height: 44px; display: inline-flex; align-items: center; }
@media (min-width: 720px) {
  .answer { grid-template-columns: 44px minmax(0, 1fr) auto; align-items: center; }
  .answer-go { grid-column: 3; align-self: center; }
}

/* The per disposition dates. AMENDED P6-B6: they are separate lines, each
   carrying its own label and its own instance, because the single collapsed
   line paired an authored label with a date from a different disposition. */
.deadlines { list-style: none; padding: 0; margin: var(--sp-3) 0 0; }
.deadlines li { padding: var(--sp-2) 0; border-top: 1px solid var(--ledger-line); display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: baseline; }
.deadlines .owed { min-width: 190px; font-weight: 600; }
.deadlines .what { color: var(--ledger-muted); font-family: var(--font-mono); }

/* The effective readiness rule, rendered from the array the function iterates.
   AMENDED P6-B2: the config declared a rule, BAND 4 printed it as data, and
   the rollup read none of it. */
.rulelist { margin: var(--sp-3) 0 0; padding-left: var(--sp-6); font-size: var(--t-caption); color: var(--ledger-muted); }
.rulelist li { padding: 2px 0; }
details.rulewhy > summary { padding: var(--sp-2) 0; font-size: var(--t-caption); color: var(--ledger-muted); }

/* The dominant number. No percentage. No progress bar. No ring fill
   proportional to settled count (design 3.4, H5). */
.dominant {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-headline);
  line-height: 1.15;
  margin-top: var(--sp-6);
}
.dominant .sub { display: block; font-family: var(--font-sans); font-size: var(--t-body); color: var(--ledger-muted); margin-top: var(--sp-2); }

.ledger-block { margin-top: var(--sp-6); }
.ledger-block h2 { font-size: var(--t-caption); text-transform: uppercase; letter-spacing: 0.14em; color: var(--ledger-muted); font-weight: 600; }

/* The blocking list. One entry per row, wording byte-identical to the row's
   own owed label. Assertion 32 checks the two strings match. Contract 3.5. */
.blocklist { list-style: none; padding: 0; margin: var(--sp-3) 0 0; }
.blocklist li { padding: var(--sp-2) 0; border-top: 1px solid var(--ledger-line); display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: baseline; }
.blocklist .owed { min-width: 190px; font-weight: 600; }
.blocklist .what { color: var(--ledger-muted); flex: 1 1 240px; }
.blocklist .flag { font-family: var(--font-mono); font-size: var(--m-small); letter-spacing: 0.06em; color: var(--danger); }
.blocklist .flag[data-kind="copy"] { color: var(--warning); }

/* AMENDED P6. THE LIST IS THE CONTENT AND THE LEADING WAS THE COST.
   At 390px the 190px minimum on the owed label forced every entry onto three
   wrapped rows and MEASURED 101px EACH, so twelve blocking entries were 1,212
   pixels of header before anything else. Nothing is hidden here and no entry is
   dropped: the two halves stack instead of competing for a 343px content width,
   and each entry measures roughly 56px. Twelve entries, 672 pixels, every one
   still open, still linked and still byte-identical to its row's own label. */
@media (max-width: 720px) {
  .blocklist li, .deadlines li { display: block; padding: 6px 0; line-height: 1.35; }
  .blocklist .owed, .deadlines .owed { min-width: 0; display: block; font-size: 13px; }
  .blocklist .what, .deadlines .what { display: block; font-size: 13px; }
  .blocklist .flag { margin-right: var(--sp-2); }
}

.rollup-rule { margin-top: var(--sp-6); font-size: var(--t-caption); color: var(--ledger-muted); max-width: 76ch; }

/* -------------------------------------------------------------- STATUS CHIP
   Colour + shape + label triple. If no icon is supplied it renders a 7 by 7
   dot, so the triple ALWAYS exists and CANNOT be omitted by a caller
   (P1A C35). The single most important structural enforcement in the kit.

   NO MINIMUM TOUCH HEIGHT. It is an indicator, not a target, and the height
   it gives up is what stops row titles truncating (P1A C38, X10). No pointer
   cursor, no hover, no underline, no href: GOV.UK's clicked-status research
   finding, honoured structurally rather than lexically. */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: var(--radius-chip);
  font-size: var(--t-caption); font-weight: 600; line-height: 1.2;
  border: 1px solid transparent; white-space: nowrap;
  color: var(--text);                            /* label is NEUTRAL high-contrast text */
}
.chip .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: currentColor; }
.chip[data-tone="warning"] { background: color-mix(in srgb, var(--warning) 14%, transparent); border-color: color-mix(in srgb, var(--warning) 45%, transparent); }
.chip[data-tone="warning"] .dot { background: var(--warning); }
.chip[data-tone="danger"]  { background: color-mix(in srgb, var(--danger) 14%, transparent); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.chip[data-tone="danger"] .dot { background: var(--danger); }
.chip[data-tone="success"] { background: color-mix(in srgb, var(--success) 14%, transparent); border-color: color-mix(in srgb, var(--success) 45%, transparent); }
.chip[data-tone="success"] .dot { background: var(--success); }
/* NEUTRAL is TRANSPARENT with a hairline border, never a grey fill, so
   unknown recedes instead of competing. Contract 1.4. */
.chip[data-tone="neutral"] { background: transparent; border-color: var(--line-strong); }
.chip[data-tone="neutral"] .dot { background: var(--text-tertiary); }
.chip[data-tone="outline"] { background: transparent; border-color: var(--card-outline); border-style: dashed; }
.chip[data-tone="outline"] .dot { background: var(--text-tertiary); }
/* Quiet renders as plain ink text with NO fill and NO background
   (GOV.UK's Completed). Done is quiet. Design 3.4. */
.chip[data-tone="quiet"] { background: transparent; border-color: transparent; padding-left: 0; font-weight: 500; color: var(--text-muted); }
.chip[data-tone="quiet"] .dot { background: var(--text-tertiary); opacity: 0.7; }
.ledger .chip { color: var(--ledger-text); }

/* --------------------------------------------------------- AUTHORITY DISC
   Monochrome, 15px, mono 9px, title carrying the full honest sentence, with
   a legend on the same page decoding all five (P1A B9). A second axis that
   never steals the signal colour. Contract 2.3. */
.disc {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%;
  border: 1px solid var(--line-strong); color: var(--text-muted);
  font-family: var(--font-mono); font-size: 9px; font-weight: 700;
  flex: none; cursor: help;
}

/* The actor badge is a DIFFERENT thing (contract 2.4). Rendered only when the
   actor is not human. SILENCE MEANS A PERSON DID IT. */
.actor { font-style: italic; font-size: var(--t-caption); color: var(--text-tertiary); }
.actor[data-actor="machine"] { color: var(--ai); }

/* ------------------------------------------------------------------ LAYOUT */
main { max-width: 1240px; margin: 0 auto; padding: 0 var(--sp-4); }
.with-rail { display: block; }
@media (min-width: 1024px) {
  .with-rail { display: grid; grid-template-columns: 216px minmax(0, 1fr); gap: var(--sp-8); align-items: start; }
}

/* CONTENTS RAIL: sticky 216px at 1024px and above. Absent below.
   Below 1024px the BandSwitcher is mandatory (contract 3.23), because the
   accordion alone left the operator with no route to BAND 2 in under eight
   swipes except a control that collapses the gaps. */
.rail { display: none; }
@media (min-width: 1024px) {
  .rail {
    display: block; position: sticky; top: var(--sp-6); align-self: start;
    max-height: calc(100vh - 120px); overflow: auto; padding-right: var(--sp-2);
  }
}
.rail a {
  display: block; font-size: 13.5px; padding: 5px var(--sp-2);
  border-left: 2px solid var(--line); color: var(--text-muted); text-decoration: none;
}
.rail a:hover { border-left-color: var(--accent-dim); color: var(--text); }
.rail a[aria-current="true"] {
  color: var(--accent-ui); font-weight: 700;
  border-left-color: var(--accent-ui);
  background: color-mix(in srgb, var(--accent-data) 10%, transparent);
}
.rail .group { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-tertiary); margin: var(--sp-4) 0 var(--sp-1); padding-left: var(--sp-2); }

/* ------------------------------------------------------------- CONTROL BAR
   "Collapse all" is DELETED and replaced by "Collapse the settled". The old
   control was the fastest route to the lower bands and it worked by breaking
   D11, the law the design promotes two sections earlier. The replacement is
   implemented as a filter over the same isOpen predicate, so it is
   STRUCTURALLY INCAPABLE of closing a category holding a loud row. */
.controlbar { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; padding: var(--sp-4) 0; border-bottom: 1px solid var(--line); }
.btn {
  font: inherit; font-size: var(--t-caption); font-weight: 600;
  min-height: 34px; padding: var(--sp-2) var(--sp-3);
  background: transparent; color: var(--text); border: 1px solid var(--line-strong);
  border-radius: 8px; cursor: pointer;
}
.btn:hover { border-color: var(--accent-dim); }
.btn-primary { background: var(--accent-ui); color: var(--surface); border-color: transparent; }
.btn-primary:hover { opacity: 0.9; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.readstring { margin-left: auto; font-size: var(--t-caption); color: var(--text-muted); }

/* ------------------------------------------------------------- FILTER BAR
   Six standing saved views, shipped on day one. Every chip carries its result
   count and the "All N" chip is explicit and always present (P1A C40).
   The filter REACHES INTO COLLAPSED SECTIONS by re-running isOpen over the
   filtered set, never by hiding DOM: `hidden` is unreachable by find-in-page
   and is therefore banned for anything a reader might hunt for. */
.filterbar { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: var(--sp-3) 0; }
.fchip {
  font: inherit; font-size: var(--t-caption); font-weight: 600;
  min-height: 34px; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-chip); border: 1px solid var(--line-strong);
  background: transparent; color: var(--text); cursor: pointer;
}
.fchip[aria-pressed="true"] { background: var(--accent-ui); color: var(--surface); border-color: transparent; }
.fchip .n { font-family: var(--font-mono); opacity: 0.75; margin-left: 4px; }

/* A registry whose gap count is silently filtered is worse than no registry
   (P1A C41). The banner is sticky and does not scroll away. */
.filterbanner {
  position: sticky; top: 4px; z-index: 30;
  display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3); margin: var(--sp-2) 0;
  background: color-mix(in srgb, var(--warning) 16%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--warning) 45%, transparent);
  border-radius: 8px; font-size: var(--t-caption); font-weight: 600;
}

/* ------------------------------------------------------------------- BANDS */
.band { margin: var(--sp-8) 0; }
.band > h2 { font-size: var(--t-section); margin-bottom: var(--sp-2); }
details.band-details {
  border: 1px solid var(--card-outline); border-radius: var(--radius-card);
  background: var(--card); padding: 0; margin: var(--sp-4) 0;
}
details.band-details > summary { padding: var(--sp-4); }
details.band-details > .band-body { padding: 0 var(--sp-4) var(--sp-4); }

/* ------------------------------------------------------- CATEGORY SECTION
   Native <details>. ZERO JavaScript toggle (P1A D1). Find-in-page reveals
   text inside closed details in all three engines (WHATWG ancestor-revealing
   algorithm; Chromium long-standing, Safari 26.2 on 2025-12-12, Firefox 148
   on 2026-02-24). Deep links, reader mode and the no-JS fallback come free.
   NEVER name= grouped exclusive accordions (P1A D2): they close the section
   the reader just opened. */
details.cat {
  border: 1px solid var(--card-outline); border-radius: var(--radius-card);
  background: var(--card); margin: var(--sp-3) 0;
}
summary { cursor: pointer; list-style: none; padding: var(--sp-4); display: block; }
summary::-webkit-details-marker { display: none; }
.summary-grid { display: grid; grid-template-columns: minmax(0,1fr) auto auto; gap: var(--sp-3); align-items: start; }
.stitle { font-size: 17.5px; font-weight: 700; }
/* The .ssub states the FINDING, not the topic (P1A D9), capped at 62ch. */
.ssub { font-size: 14.5px; color: var(--text-muted); max-width: 62ch; margin-top: 2px; }
/* .smeta carries the GAP COUNT and STAYS VISIBLE WHEN OPEN. This is the
   deliberate deviation from GCD D8: reading minutes stop mattering when a
   section opens; a gap count does not (P1A residue 1, ruled). */
.smeta { font-family: var(--font-mono); font-size: var(--m-small); color: var(--text-muted); white-space: nowrap; align-self: center; }
.chev { width: 14px; height: 14px; align-self: center; transition: transform 0.18s; color: var(--text-tertiary); }
details[open] > summary .chev { transform: rotate(90deg); }
.cat-body { padding: 0 var(--sp-4) var(--sp-4); }
.subband { margin-top: var(--sp-4); }
.subband > h4 { font-size: var(--t-caption); text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-tertiary); margin: 0 0 var(--sp-2); }
/* A category with no barred rows renders a PROSE LINE, not an empty box
   (P1A E27's zero-count prose line). */
.zeroline { font-size: var(--t-caption); color: var(--text-tertiary); }
details.settled-strip { border: 1px dashed var(--line-strong); border-radius: 10px; margin-top: var(--sp-4); }
details.settled-strip > summary { padding: var(--sp-3); font-size: var(--t-caption); color: var(--text-muted); }
details.settled-strip > div { padding: 0 var(--sp-3) var(--sp-3); }
.notinuse { padding: var(--sp-4); }
.notinuse .reason { color: var(--text-muted); font-size: var(--t-caption); margin-top: var(--sp-1); }

/* ---------------------------------------------------------- REGISTRY ROW
   ONE row renderer, three densities (contract 3.3, M3). Built from the CARD
   component, not from a platform list tile (P1A C33). */
.row {
  border: 1px solid var(--card-outline); border-radius: var(--radius-card);
  background: var(--card); padding: var(--sp-4); margin: 0 0 var(--sp-3);
}
.row:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------ THE WEIGHTS
   AMENDED P6-M7. THE THREE TIER WEIGHT MODEL WAS COMPUTED AND THROWN AWAY.
   WEIGHT() returns loud, quiet or silent, every row carried the answer as an
   attribute, and this file styled exactly two things: loud and danger. There
   was no rule for quiet and none for silent anywhere in it. Measured on the
   shipped consoles, 35 of 50 comms rows and 50 of 63 funding rows carried NO
   VISUAL MARKER AT ALL. The header promised a triage that the body did not
   deliver: thirteen of sixty three called loud, and sixty three near identical
   cards underneath with a three pixel stripe on thirteen of them.

   FOUR TIERS NOW, and the gradient is deliberate. Danger and loud keep their
   full weight colour. Quiet gets a hairline in the neutral line colour, which
   says "this is a row and it is not shouting". Silent gets the same hairline
   at reduced opacity and a slightly recessed background, which says "settled
   or blocking nothing". NOTHING IS DISMISSED and nothing is hidden: a silent
   row still renders its complete anatomy, which is the half the first build
   got right and the half worth keeping. */
.row[data-weight="silent"] { border-left: 3px solid var(--line); background: color-mix(in srgb, var(--card) 92%, var(--surface)); }
.row[data-weight="quiet"]  { border-left: 3px solid var(--line-strong); }
.row[data-weight="loud"]   { border-left: 3px solid var(--warning); }
.row[data-danger="true"]   { border-left: 3px solid var(--danger); }
/* A silent row's title recedes by ONE STEP of weight, never by colour, so
   greyscale and a colour blind reader lose nothing (P1A B9). */
.row[data-weight="silent"] .rsum .rname .label { font-weight: 500; }
.row[data-weight="loud"] .rsum .rname .label,
.row[data-danger="true"] .rsum .rname .label { font-weight: 700; }

/* compact: 72px HARD on the SUMMARY, and the number is a MEASUREMENT not a
   preference. The first layout put the name, the status chip and the meta row
   on three grid rows and measured 89px at a 390px viewport, which breached the
   budget the contract states. Two rows fit: name plus disc on line one, owed
   label plus owner plus any incident marker on line two.

   AMENDED P6. THE COMPACT ROW IS A NATIVE <details> NOW. At the phone density
   the row body was not in the document at all: no reasoning, no value, no
   settling control and no provenance, on any of the fifty or the sixty three,
   and the tap that revealed them was a JavaScript innerHTML swap that was not
   deep linkable and did not survive a refresh. The 72px budget is unchanged
   because it now binds the summary; the body is in the document, closed, which
   is what find in page needs and what a JavaScript swap can never give. */
.row[data-density="compact"] { padding: 0; overflow: hidden; }
.row[data-density="compact"] > summary.rsum {
  height: var(--row-compact-h); padding: 8px var(--sp-4);
  display: grid; grid-template-rows: auto auto; gap: 4px;
  align-content: center; cursor: pointer; overflow: hidden;
}
.row[data-density="compact"] > .rbody { padding: 0 var(--sp-4) var(--sp-4); }
.row[data-density="compact"] .rname {
  font-weight: 600; display: flex; align-items: center; gap: var(--sp-2);
  min-width: 0; line-height: 1.2;
}
.row[data-density="compact"] .rsum .rname .label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row[data-density="compact"] .rmeta {
  display: flex; gap: var(--sp-2); align-items: center; flex-wrap: nowrap;
  overflow: hidden; min-width: 0;
}
.row[data-density="compact"] .rmeta .chip {
  padding: 2px 8px; font-size: 12.5px; flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; display: inline-flex;
}
.row[data-density="compact"] .rmeta .chip > span:last-child {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.incident[data-danger="true"] { color: var(--danger-ink); }

.row-head { display: flex; gap: var(--sp-3); align-items: flex-start; }
.row-head .rname { font-size: var(--t-body); font-weight: 600; flex: 1 1 auto; min-width: 0; }
/* A label gets TWO LINES before ellipsis, because a half-word label reads as
   a defect (P1A C9). */
.row-head .rname .label { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* why_it_matters states the FINDING, authored in the source, lifted out at
   render, and NEVER SAID TWICE in the body (P1A D9, D10). */
.why { font-size: var(--t-caption); color: var(--text-muted); margin-top: 2px; max-width: 72ch; }
.chiprow { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-3); }
.incident { font-family: var(--font-mono); font-size: var(--m-small); color: var(--warning-ink); letter-spacing: 0.06em; }

/* -------------------------------------------------------------- VALUE SLOT
   The most important component in the kit. The only place a value ever
   reaches the screen. THERE IS NO CODE PATH THAT EMITS AN EMPTY STRING.
   The value, its status chip and its provenance are ONE VISUAL UNIT and are
   never rendered apart (P1A verdict 5). */
.vslot { margin-top: var(--sp-3); padding: var(--sp-3); border-radius: 10px; background: var(--panel); }
.vslot .vlabel { font-size: var(--t-caption); color: var(--text-tertiary); }
/* Numbers render in the mono tabular face and are the LARGEST thing in their
   slot; labels are small and muted ABOVE them, never beside them (P1A B6).
   A value NEVER truncates. It scales to fit, because a clipped figure reads
   as broken evidence (P1A C9, H9). */
.vslot .vvalue {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--m-large); line-height: 1.2; margin-top: 2px;
  display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
  overflow-wrap: anywhere;
}
@container (max-width: 320px) { .vslot .vvalue { font-size: var(--m-body); } }
.vslot .vunit { font-family: var(--font-sans); font-size: var(--t-caption); color: var(--text-muted); }
.vslot .vnull { font-family: var(--font-sans); font-size: var(--t-body); color: var(--text-muted); font-style: normal; }
.vslot .vline { font-size: var(--t-caption); color: var(--text-muted); margin-top: var(--sp-2); }
.vslot .vprov { display: flex; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); flex-wrap: wrap; }
/* A withheld row renders as SET, with the value slot occupied by a BORDERED
   STATEMENT. Never an empty cell. Never a dash glyph (P1A X14). */
.withheld { border: 1px solid var(--card-outline); border-radius: 8px; padding: var(--sp-3); }
.withheld .t { font-weight: 600; }
.conflictline { border-left: 3px solid var(--danger); padding-left: var(--sp-3); color: var(--danger-ink); font-weight: 600; margin-top: var(--sp-2); }
.supersede { font-size: var(--t-caption); color: var(--warning-ink); margin-top: var(--sp-2); }
.claimsline { font-size: var(--t-caption); color: var(--text-muted); margin-top: var(--sp-2); }

/* --------------------------------------------------------- ABORT STATEMENT
   NEVER a chip. A full-width bordered statement in the danger tone, which is
   legitimate here because P1A C14 reserves danger for genuine work-stopping
   states and "do not submit" is literally work-stopping. Contract 3.21. */
.abort {
  border: 2px solid var(--danger); border-radius: 10px;
  padding: var(--sp-3); margin-bottom: var(--sp-3);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
}
.abort .predicate { font-family: var(--font-mono); font-size: var(--m-small); }
.abort .consequence { font-weight: 700; color: var(--danger-ink); }
.abort .authority, .abort .cost { font-size: var(--t-caption); color: var(--text-muted); }
.abort[data-state="not_evaluable"] { border-color: var(--line-strong); border-width: 1px; background: transparent; }
.abort[data-state="not_evaluable"] .consequence { color: var(--text-muted); font-weight: 600; }
.ledger .abort { background: transparent; }

/* --------------------------------------------------------- FILL CONTROLS */
.fill { margin-top: var(--sp-3); }
.fill label { display: block; font-size: var(--t-caption); font-weight: 600; margin-bottom: var(--sp-1); }
/* 16px MINIMUM on inputs, because it is what prevents iOS auto-zoom (X6). */
.fill input[type="text"], .fill textarea, .fill input[type="date"] {
  font: inherit; font-size: var(--t-body); width: 100%;
  padding: var(--sp-2) var(--sp-3); border: 1px solid var(--line-strong);
  border-radius: 8px; background: var(--surface); color: var(--text);
}
/* Error BELOW the field, not only at the top. Every error states cause PLUS
   how to fix (contract 3.8). Two independent feedback slots, both cleared at
   the start of every attempt (P1A F7). */
.fill .err { color: var(--danger-ink); font-size: var(--t-caption); margin-top: var(--sp-1); min-height: 1.2em; }
.fill .res { color: var(--success-ink); font-size: var(--t-caption); margin-top: var(--sp-1); min-height: 1.2em; }
.fill .actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); flex-wrap: wrap; }
.criteria { display: flex; gap: var(--sp-2); align-items: flex-start; font-size: var(--t-caption); margin: var(--sp-2) 0; }
/* The `hidden` attribute is BANNED across this kit, without an allow list,
   because `hidden` is unreachable by find-in-page and an allow list is how a
   ban stops being a ban. An idle progress bar hides through a data attribute
   instead, and it carries no text for anyone to hunt for anyway. */
.progress[data-idle="true"] { display: none; }
.progress { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; margin-top: var(--sp-2); }
.progress > i { display: block; height: 100%; background: var(--accent-data); }

/* A four-state line. The operator entering a value on a poor connection must
   know whether it left the device. A DRAFT renders nothing at all. */
.wsl { display: block; font-size: var(--t-caption); padding: var(--sp-1) var(--sp-2); border-radius: 6px; margin-top: var(--sp-2); }
.wsl[data-state="local"]  { background: color-mix(in srgb, var(--warning) 12%, transparent); color: var(--warning-ink); }
.wsl[data-state="queued"] { background: color-mix(in srgb, var(--warning) 12%, transparent); color: var(--warning-ink); }
.wsl[data-state="saved"]  { background: color-mix(in srgb, var(--success) 12%, transparent); color: var(--success-ink); }
.wsl[data-state="error"]  { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger-ink); }
.wsl[data-state="draft"]  { display: none; }

/* ------------------------------------------------------------ LINEAGE ---- */
details.lineage { margin-top: var(--sp-3); }
details.lineage > summary { padding: var(--sp-2) 0; font-size: var(--t-caption); color: var(--text-muted); }
details.lineage .note { white-space: pre-wrap; font-size: var(--t-caption); background: var(--panel); padding: var(--sp-3); border-radius: 8px; }

/* -------------------------------------------------------- DECISION BRIEF */
.brief { border: 1px solid var(--card-outline); border-radius: 12px; padding: var(--sp-4); margin-top: var(--sp-3); background: var(--surface-elevated); }
.brief h5 { font-size: var(--t-caption); text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-tertiary); margin: var(--sp-3) 0 var(--sp-1); }
.brief h5:first-of-type { margin-top: 0; }
.brief ol { margin: 0; padding-left: var(--sp-6); }

/* ----------------------------------------------------------- LOCKSTEP ---- */
.lockstep { border: 2px solid var(--accent-dim); border-radius: 12px; padding: var(--sp-4); margin: var(--sp-4) 0; }
.lockstep h4 { font-size: var(--t-body); margin: 0; }
.lockstep .reason { font-size: var(--t-caption); color: var(--text-muted); margin-top: 2px; }
/* "4 of 9 filled" is NOT a progress meter and does not breach assertion 13:
   it counts a hard cross-row invariant with a fixed denominator every member
   of which must be filled, not a proportion of work done. Assertion 13 is
   scoped by name. Contract 3.16. */
.lockstep .filled { font-family: var(--font-mono); font-size: var(--m-body); margin-top: var(--sp-3); }
.lockstep ol { margin: var(--sp-3) 0 0; padding-left: var(--sp-6); font-size: var(--t-caption); }
.lockstep .unfilled-names { font-size: var(--t-caption); color: var(--text-muted); margin-top: var(--sp-2); }

/* ------------------------------------------------------ VERSIONS / TABLES */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
thead th { background: var(--accent-text-light); color: white; text-align: left; padding: var(--sp-2) var(--sp-3); font-size: var(--t-caption); }
tbody td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--line); vertical-align: top; }
tbody tr:nth-child(even) { background: color-mix(in srgb, var(--panel) 60%, transparent); }
tr[data-loser="true"] td .val { text-decoration: line-through; }
.winner { font-family: var(--font-mono); font-weight: 700; color: var(--success-ink); }
.pinbasis { font-size: var(--t-caption); color: var(--text-muted); margin-top: var(--sp-2); }

/* The data-label restack: the only pattern in the estate that survives both
   a phone and a printer. Every <td> carries data-label at render time. */
@media (max-width: 640px) {
  table.restack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.restack tr { display: block; border: 1px solid var(--card-outline); border-radius: 10px; margin-bottom: var(--sp-3); background: var(--card); }
  table.restack td { display: flex; gap: var(--sp-3); border-bottom: 1px solid var(--line); }
  table.restack td::before { content: attr(data-label); width: 40%; flex: none; color: var(--accent-ui); font-weight: 600; font-size: var(--t-caption); }
  table.restack tr td:last-child { border-bottom: 0; }
}
.tablewrap { overflow-x: auto; }

/* ------------------------------------------------------------- ARTIFACTS */
.artifact { border: 1px solid var(--card-outline); border-radius: var(--radius-card); padding: var(--sp-4); margin-bottom: var(--sp-3); background: var(--card); }
.artifact .meta { font-size: var(--t-caption); color: var(--text-muted); margin-top: var(--sp-1); }
/* E19 location honesty. The three cases are exhaustive and NOT ONE IS A DEAD
   LINK: no location renders a sentence saying it cannot honestly be reviewed;
   a web address renders "Open the artifact"; a disk path renders as
   SELECTABLE TEXT plus "This opens on the laptop, not on this phone". */
.location { font-family: var(--font-mono); font-size: var(--m-small); word-break: break-all; user-select: all; background: var(--panel); padding: var(--sp-2); border-radius: 6px; margin-top: var(--sp-2); }
.location-note { font-size: var(--t-caption); color: var(--text-tertiary); margin-top: var(--sp-1); }
.revindex { margin-top: var(--sp-3); }
.revindex h5 { font-size: var(--t-caption); margin: var(--sp-3) 0 var(--sp-1); }
.revindex ul { margin: 0; padding-left: var(--sp-6); font-size: var(--t-caption); }

/* WHAT IS INSIDE IT. AMENDED P6. Twenty nine of thirty seven funding cards
   were a filename, a size and a sentence saying nobody had read the file, and
   every card on both consoles ended with "This opens on the laptop, not on
   this phone" and no way to open it. The walk reads each document now and this
   renders the document's own headings and its opening prose. It opens by
   default where there is a table of contents to show, because a contents list
   behind a chevron is the thing the reader came for behind a click. */
details.contents { margin-top: var(--sp-3); border: 1px dashed var(--line-strong); border-radius: 10px; }
details.contents > summary { padding: var(--sp-2) var(--sp-3); font-size: var(--t-caption); color: var(--text-muted); }
.contents-body { padding: 0 var(--sp-3) var(--sp-3); }
.contents-body .toc { margin: 0 0 var(--sp-2); padding-left: var(--sp-6); font-size: var(--t-caption); }
.contents-body .toc li { padding: 1px 0; }
.contents-body blockquote.note { margin: 0; white-space: normal; }

/* The operator's reverse index write. AMENDED P6-M9: twenty two rendered
   buttons had no handler anywhere and every one of them was on BAND 3. */
.linkpicker { border: 1px solid var(--accent-dim); border-radius: 10px; padding: var(--sp-3); margin-top: var(--sp-3); }
.linkpicker label { display: block; font-size: var(--t-caption); font-weight: 600; margin: var(--sp-2) 0 var(--sp-1); }
.linkpicker select {
  font: inherit; font-size: var(--t-body); width: 100%; min-height: 44px;
  padding: var(--sp-2) var(--sp-3); border: 1px solid var(--line-strong);
  border-radius: 8px; background: var(--surface); color: var(--text);
}
.linkpicker .err { color: var(--danger-ink); font-size: var(--t-caption); margin-top: var(--sp-1); min-height: 1.2em; }
.linkpicker .res { color: var(--success-ink); font-size: var(--t-caption); margin-top: var(--sp-1); min-height: 1.2em; }
.linkpicker .actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); flex-wrap: wrap; }
.artifact .err { color: var(--danger-ink); font-size: var(--t-caption); min-height: 0; }
.artifact .res { color: var(--success-ink); font-size: var(--t-caption); min-height: 0; }

/* The root route's own "do this next", so the index answers the question
   without opening a system. */
.sysnext { font-size: var(--t-caption); font-weight: 600; margin-top: var(--sp-2); }

/* ---------------------------------------------------------- EMPTY STATES
   FOUR named factories, never three and never one (P1A C43, B7). */
.empty { border: 1px dashed var(--line-strong); border-radius: 12px; padding: var(--sp-6); text-align: left; }
.empty h4 { font-size: var(--t-section); margin: 0 0 var(--sp-2); }
.empty p { margin: 0 0 var(--sp-2); color: var(--text-muted); }
.empty[data-tone="positive"] { border-color: color-mix(in srgb, var(--success) 50%, transparent); }
.empty[data-tone="calm"] { border-color: color-mix(in srgb, var(--accent-data) 50%, transparent); }
.empty[data-tone="danger"] { border-color: var(--danger); border-style: solid; border-width: 2px; }
.empty[data-tone="danger"] h4 { color: var(--danger-ink); }
/* A FILTERED list that comes back empty uses a compact inline state, not the
   illustrated one. They are different messages (P1A C42). */
.empty-inline { font-size: var(--t-caption); color: var(--text-muted); padding: var(--sp-3); }
.discrepancy { border: 2px solid var(--danger); border-radius: 10px; padding: var(--sp-3); color: var(--danger-ink); font-weight: 600; margin: var(--sp-3) 0; }

/* ------------------------------------------------------------------ RING
   Draws its arc ONLY when evaluable > 0 (P1A C4, H4). No filled arc for no
   score. `unknown` draws a BROKEN OUTLINE in the danger tone: the old
   function returned grey on an empty array, which is exactly what a broker
   outage produces, so an outage rendered as "nothing here to judge". */
.ring { width: 44px; height: 44px; flex: none; }
.ring circle.track { fill: none; stroke: var(--line-strong); stroke-width: 4; }
.ring circle.arc { fill: none; stroke-width: 4; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 50% 50%; }
.ring[data-tone="green"] circle.arc { stroke: var(--success); }
.ring[data-tone="amber"] circle.arc { stroke: var(--warning); }
.ring[data-tone="unknown"] circle.track { stroke: var(--danger); stroke-dasharray: 6 5; }

/* ------------------------------------------------------------------- DOCK
   Fixed, full width, near-opaque ink, top hairline. Below 620px it SHRINKS
   rather than dropping content, because the phone is the device this arrives
   on (P1A D19). Hidden while gated and at print. */
.dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  background: var(--ledger-bg); color: var(--ledger-text);
  border-top: 1px solid var(--ledger-line);
}
.dock-main { display: flex; gap: var(--sp-3); align-items: center; justify-content: center; padding: var(--sp-3) var(--sp-4); flex-wrap: nowrap; }
.dock .fact { font-size: var(--t-caption); color: var(--ledger-muted); }
.dock .btn { border-color: var(--ledger-line); color: var(--ledger-text); }
.dock .btn-primary { background: var(--accent); color: var(--ledger-bg); border-color: transparent; }
@media (max-width: 620px) {
  .dock .fact { font-size: 11.5px; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .dock-main { padding: var(--sp-2) var(--sp-3); }
  .dock .btn { padding: 6px var(--sp-2); }
  /* The narrow dock is shorter, so the inset is too. One number covering every
     breakpoint was the m15 defect: it covered none of them. */
  body { padding-bottom: 100px; }
}
@media (min-width: 1024px) {
  /* Above 1024px the band switcher does not render, so the dock is one row. */
  body { padding-bottom: 72px; }
}

/* BAND SWITCHER: renders ONLY below 1024px, four 44px targets each carrying
   its count. Activating one scrolls to the band and OPENS it if collapsed,
   which is an `open` attribute write, not a JS show, so every band stays
   find-in-page reachable and deep-linkable. Contract 3.23. */
.bandswitch { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--ledger-line); }
@media (min-width: 1024px) { .bandswitch { display: none; } }
.bandswitch button {
  font: inherit; font-size: 11.5px; font-weight: 600; min-height: 44px;
  background: transparent; color: var(--ledger-muted); border: 0; cursor: pointer;
  border-right: 1px solid var(--ledger-line); padding: 4px;
}
.bandswitch button:last-child { border-right: 0; }
.bandswitch button[aria-current="true"] { color: var(--accent); }
.bandswitch .n { display: block; font-family: var(--font-mono); font-size: var(--m-small); }

/* ------------------------------------------------------------ GATE OVERLAY
   Fixed inset 0, z-index 999, ink background, centred 420px box, LEFT-ALIGNED
   text. The error paragraph has min-height RESERVED so the box does not jump.
   Contract 3.13. */
.gate { position: fixed; inset: 0; z-index: 999; background: var(--ledger-bg); color: var(--ledger-text); display: flex; align-items: center; justify-content: center; padding: var(--sp-4); }
.gate-box { width: 100%; max-width: 420px; text-align: left; }
.gate-box h1 { font-size: var(--t-section); margin-bottom: var(--sp-2); }
.gate-box p { color: var(--ledger-muted); font-size: var(--t-caption); }
.gate-box input {
  font: inherit; font-size: var(--t-body); width: 100%; margin-top: var(--sp-4);
  padding: var(--sp-3); border-radius: 8px; border: 1px solid var(--ledger-line);
  background: transparent; color: var(--ledger-text);
}
.gate-box button { width: 100%; margin-top: var(--sp-3); min-height: 44px; }
.gate-err { min-height: 2.6em; color: var(--danger); font-size: var(--t-caption); margin-top: var(--sp-2); }
/* THE LABELS ARE VISIBLE, because two boxes that look alike need naming and a
   placeholder disappears the moment either one is typed into. The label sits
   tight under the field above it, so the pair reads as one field. */
.gate-label { display: block; margin-top: var(--sp-3); font-size: var(--t-caption); color: var(--ledger-muted); }
.gate-label + input { margin-top: var(--sp-1); }
/* THE SECOND ROUTE IN, RULED OFF AND QUIETER THAN THE FIRST. Subordinate on
   the screen because it is subordinate in fact: the password is the login and
   the code is the alternative for somebody who has no password. */
.gate-alt { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--ledger-line); }
.gate-alt .btn { font-size: var(--t-caption); min-height: 40px; margin-top: 0; }
.gate-alt p { margin-top: var(--sp-2); }
/* A PLAIN BUTTON ON THE GATE IS A PLAIN BUTTON ON INK, and .btn is written for
   the light app surface. Its text takes --text and its border takes
   --line-strong, and both of those vanish against the overlay: measured on the
   live deploy, the code button rendered as dark grey on near black and read as
   a disabled control. The sign out button on the no access card had the same
   fault and had shipped with it. The gate restates the plain button in its own
   ink palette and leaves the primary button alone. */
.gate-box .btn:not(.btn-primary) { color: var(--ledger-text); border-color: var(--ledger-line); }
.gate-box .btn:not(.btn-primary):hover { border-color: var(--ledger-accent); }
/* AND THE ERROR IS RESTATED AT A SPECIFICITY THAT WINS. .gate-err is one class
   and .gate-box p is a class plus an element, so the muted paragraph colour
   beat the danger colour and every refusal this gate has ever shown rendered in
   the same grey as the help text under it. Measured on the live deploy: the
   computed colour was the muted token, not the danger one. */
.gate-box .gate-err { color: var(--danger); }
body.locked { overflow: hidden; }
body.locked .dock { display: none; }

/* --------------------------------------------------------- SYSTEM INDEX */
.sysrow { display: grid; grid-template-columns: 44px minmax(0,1fr); gap: var(--sp-3); align-items: center; border: 1px solid var(--card-outline); border-radius: var(--radius-card); padding: var(--sp-4); margin-bottom: var(--sp-3); background: var(--card); text-decoration: none; color: inherit; }
.sysrow .cols { display: flex; gap: var(--sp-4); flex-wrap: wrap; font-size: var(--t-caption); color: var(--text-muted); margin-top: var(--sp-2); }
.sysrow .cols b { font-family: var(--font-mono); color: var(--text); }

/* ------------------------------------------------------------- UNFILED --- */
.unfiled { border: 1px solid var(--card-outline); border-radius: var(--radius-card); background: var(--card); margin: var(--sp-6) 0; }
.unfiled > summary { padding: var(--sp-4); }
.canon-proposal { border-left: 3px solid var(--warning); padding-left: var(--sp-3); font-size: var(--t-caption); margin-top: var(--sp-3); }

/* ------------------------------------------------------------- DIAGRAM --- */
.diagram { border: 1px solid var(--line-strong); border-radius: 12px; padding: var(--sp-3); margin: var(--sp-3) 0; }
.diagram .zoomrow { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.diagram .zoomrow button { min-width: 44px; min-height: 44px; }
.diagram .canvas { overflow: auto; background: var(--panel); border-radius: 8px; padding: var(--sp-3); }
.diagram pre { margin: 0; font-family: var(--font-mono); font-size: var(--m-small); white-space: pre; }
.warnline { border-left: 3px solid var(--warning); padding-left: var(--sp-3); font-size: var(--t-caption); color: var(--warning-ink); margin: var(--sp-2) 0; }
.qcard { border: 1px solid var(--card-outline); border-radius: 12px; padding: var(--sp-3); margin-bottom: var(--sp-3); background: var(--card); }
.qcard .q { font-weight: 600; }
.qcard .meta { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; margin-top: var(--sp-2); font-size: var(--t-caption); color: var(--text-muted); }

/* ------------------------------------------------------------- LEGEND ---- */
.legend { display: grid; gap: var(--sp-2); }
.legend .item { display: flex; gap: var(--sp-3); align-items: center; font-size: var(--t-caption); }
.legend .item .what { color: var(--text-muted); }

/* ---------------------------------------------------------------- PRINT
   details::details-content content-visibility, plus beforeprint and
   afterprint handlers as belt and braces. THE LEGACY RULE
   `details:not([open]) > *:not(summary){display:block}` WAS MEASURED BROKEN
   IN CHROME 150 AND MUST NOT BE USED (P1A D3).
   While the gate is locked, print emits nothing. */
@media print {
  .dock, .rail, .filterbar, .filterbanner, .controlbar, .syncbar, .chev { display: none !important; }
  body { padding-bottom: 0; background: white; color: black; }
  details { break-inside: avoid; }
  details::details-content { content-visibility: visible !important; block-size: auto !important; }
  table.restack thead { position: static; width: auto; height: auto; clip: auto; }
  table.restack tr { display: table-row; border: 0; }
  table.restack td { display: table-cell; }
  table.restack td::before { content: none; }
  .ledger { background: white; color: black; border-bottom: 2px solid black; }
  .ledger .scopeline, .ledger .dominant .sub, .rollup-rule { color: black; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 10px; }
  body.locked > *:not(.gate) { display: none !important; }
  body.locked .gate { display: none !important; }
}
