/* ── Barlow, self-hosted ──────────────────────────────────────────────────
   These names were in the palette from the start and nothing ever loaded
   them: no @font-face, no link, and no `font-src` in the CSP, so every
   surface rendered in `system-ui`. Investigation I-08.

   Latin subset only, at the two weights the rules below actually use. Text
   outside the range falls back to `system-ui`, which is the right answer
   rather than a gap -- this is an English-language application and the
   latin-ext and vietnamese subsets would be bytes nobody loads.

   Provenance, checksums and the licence check are in
   `static/fonts/PROVENANCE.md`; `static/fonts/OFL.txt` is the licence itself
   and sits beside the files because SIL OFL condition 2 requires each copy to
   carry it. Do not move it to a licences directory away from them.
   ──────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  /* `swap`: text is readable in the fallback immediately and reflows when the
     face arrives. `block` would hide it for up to three seconds, which on a
     page whose whole job is telling somebody what their evidence will cost is
     three seconds of blank. */
  font-display: swap;
  src: url("/static/fonts/barlow-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 600;
  /* `swap`: text is readable in the fallback immediately and reflows when the
     face arrives. `block` would hide it for up to three seconds, which on a
     page whose whole job is telling somebody what their evidence will cost is
     three seconds of blank. */
  font-display: swap;
  src: url("/static/fonts/barlow-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow Condensed";
  font-style: normal;
  font-weight: 400;
  /* `swap`: text is readable in the fallback immediately and reflows when the
     face arrives. `block` would hide it for up to three seconds, which on a
     page whose whole job is telling somebody what their evidence will cost is
     three seconds of blank. */
  font-display: swap;
  src: url("/static/fonts/barlow-condensed-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow Condensed";
  font-style: normal;
  font-weight: 600;
  /* `swap`: text is readable in the fallback immediately and reflows when the
     face arrives. `block` would hide it for up to three seconds, which on a
     page whose whole job is telling somebody what their evidence will cost is
     three seconds of blank. */
  font-display: swap;
  src: url("/static/fonts/barlow-condensed-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Credenza design system.
 *
 * Ported from the Claude Design deck, which is the visual authority. Tokens are
 * the deck's own values, not approximations -- if a colour here disagrees with
 * the deck, the deck wins and this file is wrong.
 *
 * The palette is deliberately almost monochrome: type, steel, and ONE warm
 * ochre. The ochre means "you have to finish this before you move on" and
 * appears nowhere else, which is what lets it be quiet and still be seen. There
 * is no red, no green, and no severity palette -- a colour system that shouts on
 * every screen cannot mark the one thing that is actually owed. Loud only where
 * unresolved (AGENTS.md invariant 5).
 */

:root {
  --color-bg: #f2f2f3;
  /* `--color-surface: #e9e9ea` was here and NOTHING referenced it -- `.card`
     is #fff. Removed rather than kept: an unused token is a second surface
     language waiting for somebody to reach for it. A design that needs a second
     surface should declare one on purpose. */
  --color-text: #1d1f20;
  --color-accent: #5980a6;
  --color-accent-2: #728fab;
  --color-divider: color-mix(in srgb, #1d1f20 16%, transparent);

  --color-neutral-100: #f5f5f8;
  --color-neutral-200: #e7e7ea;
  --color-neutral-300: #d4d4d7;
  --color-neutral-400: #b7b7ba;
  --color-neutral-500: #98989b;
  --color-neutral-600: #7a7a7d;
  --color-neutral-700: #5d5d60;
  --color-neutral-800: #424244;
  --color-neutral-900: #2b2b2d;

  --color-accent-100: #eef6ff;
  --color-accent-200: #d6ebff;
  --color-accent-400: #94bce3;
  --color-accent-600: #597ea3;
  --color-accent-700: #416180;
  --color-accent-800: #2c455d;
  --color-accent-900: #1d2d3d;

  /* The one warm colour. Reserved for open obligations. */
  --color-owed: #66490d;
  --color-owed-bg: #f5e3b9;

  --font-heading: "Barlow Condensed", system-ui, sans-serif;
  --font-heading-weight: 600;
  --font-body: "Barlow", system-ui, sans-serif;

  --space-1: 3.4px;  --space-2: 6.8px;  --space-3: 10.2px;
  --space-4: 13.6px; --space-6: 20.4px; --space-8: 27.2px;

  --radius-md: 6px;
  --radius-lg: 8px;

  --shadow-sm: 0 1px 2px color-mix(in srgb, #2b2b2d 14%, transparent);
  --shadow-md: 0 3px 10px color-mix(in srgb, #2b2b2d 16%, transparent);

  --rail-w: 232px;
  --rail-spine-w: 56px;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, .kicker {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  margin: 0;
}

.kicker {
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}

a { color: var(--color-accent-700); }

/* ── App frame: rail | working surface | source spine ───────────────────── */

.app {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "head head head"
    "rail main source"
    "rail drawer source";
  height: 100vh;
}
.app[data-rail="spine"] { grid-template-columns: var(--rail-spine-w) minmax(0, 1fr) auto; }

.head   { grid-area: head; }
.rail   { grid-area: rail; }
.main   { grid-area: main; overflow-y: auto; padding: var(--space-6) var(--space-8);
          scrollbar-gutter: stable;
          /* The cut edge is shaded ONLY while something is below it: the two
             `local` gradients ride the content and cover the shadows when the
             ends are reached. No script, and it cannot report a cut that is not
             there. */
          background:
            linear-gradient(var(--color-bg) 30%, transparent) local top / 100% 20px no-repeat,
            linear-gradient(transparent, var(--color-bg) 70%) local bottom / 100% 20px no-repeat,
            radial-gradient(farthest-side at 50% 0,
              color-mix(in srgb, #1d1f20 22%, transparent), transparent)
              scroll top / 100% 10px no-repeat,
            radial-gradient(farthest-side at 50% 100%,
              color-mix(in srgb, #1d1f20 22%, transparent), transparent)
              scroll bottom / 100% 10px no-repeat; }

/* An overlay scrollbar that appears only once you already know to scroll is an
   affordance for people who do not need it. Styling the scrollbar at all makes
   Chromium and WebKit render a permanent one. */
.main::-webkit-scrollbar { width: 11px; }
.main::-webkit-scrollbar-track { background: transparent; }
.main::-webkit-scrollbar-thumb {
  background: var(--color-neutral-400); border-radius: 6px;
  border: 3px solid var(--color-bg);
}
.main::-webkit-scrollbar-thumb:hover { background: var(--color-neutral-500); }
.drawer { grid-area: drawer; }
.source { grid-area: source; }

/* ── Header ─────────────────────────────────────────────────────────────── */

/* ── one header, two shells ───────────────────────────────────────────────
   `.head` and `.public-head` were built from the same tokens and agreed on
   nothing: 6.8px padding against 13.6px, a 16px wordmark against 19px, one
   with a mobile reflow and one without. Crossing `/start` was a visible jolt.
   They share geometry now and differ only in what sits in the spacer -- nav on
   the public side, instruments on the workbench.

   **Dark, deliberately.** Every header in the deck is ink-on-white and this is
   the one place the code wins: the dark bar gives the landing page a firmer
   edge and is applied consistently. Recorded in the deck rather than left as a
   silent divergence -- see `Assurify v1.dc.html`.
   ───────────────────────────────────────────────────────────────────────── */
.head, .public-head {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-6);
  min-height: 52px;
  background: var(--color-neutral-900); color: var(--color-bg);
  font-size: 12px;
}
.head .brand, .public-head .brand {
  display: inline-flex; align-items: center; gap: var(--space-3);
  color: var(--color-bg); text-decoration: none;
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px; letter-spacing: 0.01em;
}
.head .brand:hover, .public-head .brand:hover { color: #fff; }

/* The deck's 26x26 bordered mark, left of the wordmark in all eleven of its
   headers and previously in none of ours. It is what earns the footer's
   "Built on the open UofA framework". */
.monogram {
  display: grid; place-items: center; width: 26px; height: 26px;
  border: 1px solid currentColor; border-radius: 2px;
  font-size: 12px; line-height: 1; letter-spacing: 0.02em;
}
.brand-divider {
  width: 1px; height: 18px;
  background: color-mix(in srgb, #f2f2f3 30%, transparent);
}
/* Which tool this is, after the divider. The deck's planner header reads
   `Assurify | Evidence & Capital Planner`. */
.product-name {
  font-family: var(--font-heading); font-size: 14px; letter-spacing: 0.02em;
  color: var(--color-accent-200);
}

/* **Unscoped from `.head`.** These were `.head .spacer` and `.head .chip`, so
   the three the public header renders got no styling at all -- a live layout
   bug on every public page that nothing was looking at. */
.spacer { margin-left: auto; }
.head .chip, .public-head .chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: var(--radius-md);
  background: color-mix(in srgb, #f2f2f3 14%, transparent);
}
/* The backend chip must read truthfully before a choice is made (spec §2). */
.head .chip[data-state="unset"],
.public-head .chip[data-state="unset"] { color: var(--color-owed-bg); }

/* **Contrast.** `.btn-ghost` is `--color-accent-700` (#416180), designed for
   ink-on-white. On the dark bar that is roughly 2:1 and fails WCAG AA for text
   -- a defect the headers only acquired by going dark. The nav links beside
   them already use `--color-accent-200` on this background, so the buttons use
   it too. */
.head .btn-ghost, .public-head .btn-ghost {
  color: var(--color-accent-200);
  border-color: color-mix(in srgb, #f2f2f3 30%, transparent);
}
.head .btn-ghost:hover, .public-head .btn-ghost:hover {
  color: #fff; border-color: color-mix(in srgb, #f2f2f3 55%, transparent);
}

/* ── Rail ───────────────────────────────────────────────────────────────── */

.rail {
  background: var(--color-accent-900); color: var(--color-bg);
  padding: var(--space-4) 0; overflow-y: auto;
}
.rail .kicker { color: color-mix(in srgb, #f2f2f3 55%, transparent); padding: 0 var(--space-4) var(--space-2); }

.stage {
  display: block; text-decoration: none; color: inherit;
  padding: var(--space-2) var(--space-4);
  border-left: 2px solid transparent;
}
.stage:hover { background: color-mix(in srgb, #f2f2f3 7%, transparent); }
.stage[aria-current="step"] { border-left-color: var(--color-accent-400); background: color-mix(in srgb, #f2f2f3 10%, transparent); }
.stage-line { display: flex; align-items: baseline; gap: var(--space-2); }
.stage-num { font-variant-numeric: tabular-nums; opacity: 0.55; font-size: 11px; }
.stage-name { font-family: var(--font-heading); font-size: 15px; }

/* Work owed, not progress made (deck 1l, option A). */
.owed {
  margin-left: auto; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-owed-bg);
}
.stage-done { margin-left: auto; opacity: 0.5; }

/* One-line gate subtitle, current and next stage only (deck 1l, option C). */
.stage-gate {
  font-size: 11px; line-height: 1.35; margin-top: 2px;
  color: color-mix(in srgb, #f2f2f3 62%, transparent);
}

/* ── Surfaces ───────────────────────────────────────────────────────────── */

.card {
  background: #fff; border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm); padding: var(--space-6);
  margin-bottom: var(--space-4);
}
.card h3 { font-size: 19px; margin-bottom: var(--space-2); }

/* A quiet statement with a change affordance -- not a card, not a decision. */
.statement {
  display: flex; align-items: baseline; gap: var(--space-2);
  padding: var(--space-2) 0; border-bottom: 1px solid var(--color-divider);
}
.statement:last-child { border-bottom: 0; }
.statement .label { color: var(--color-neutral-600); min-width: 8.5em; }
.statement .value { font-weight: 600; }
.statement .change { margin-left: auto; }

.note { color: var(--color-neutral-600); font-size: 12.5px; }

/* The only loud thing in the app. */
.strip-owed {
  background: var(--color-owed-bg); color: var(--color-owed);
  border-radius: var(--radius-md); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4); font-weight: 600;
}
.strip-owed .detail { font-weight: 400; opacity: 0.85; }

/* A confirmation, not a refusal. Quiet where `strip-owed` is loud: something
   went RIGHT, and invariant 5's rule that unresolved work announces itself
   would be inverted by styling an ordinary success the same way.

   **It fades on its own**, because the thing it confirms is over. A notice that
   sat there would go on announcing an act the reader had moved past, and the
   report this answers -- "you are never told you are signed out" -- is about a
   moment, not a state. `forwards` holds the faded frame so it does not flash
   back at the end.

   CSS rather than a timer: the content policy allows no inline script, and a
   fade is presentation. */
.strip-notice {
  background: var(--color-neutral-100);
  color: var(--color-neutral-800);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  animation: notice-fade 8s ease-in forwards;
}

@keyframes notice-fade {
  0%, 70%  { opacity: 1; }
  100%     { opacity: 0; visibility: hidden; }
}

/* Someone who has asked for less motion still needs to READ it. The message is
   the point; the fade is decoration, so the decoration is what goes. */
@media (prefers-reduced-motion: reduce) {
  .strip-notice { animation: none; }
}

/* The ambient state chip. Loud only where unresolved, per invariant 5: an
   owed package announces itself, a signable one is quiet. */
.chip-status { text-decoration: none; font-weight: 600; letter-spacing: 0.01em; }
.chip-status[data-state="owed"] {
  background: var(--color-owed-bg); color: var(--color-owed);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-owed) 35%, transparent);
}
.chip-status[data-state="clear"] {
  background: var(--color-accent-100); color: var(--color-accent-800);
}

/* The review queue stays on screen while the list under it scrolls away.

   Measured, pane open with a row selected: 4 of 13 factors visible at 1512x982,
   3 at 1440x900, 2 at 1280x800. The rows are reachable -- the column scrolls --
   but on macOS the overlay scrollbar is invisible until something moves, so
   nothing on the screen says the other eleven exist. Invariant 5 was resting on
   the rail's count, several hundred pixels away and never adjacent to the work.
   Three changes, none of them a redesign: the count sticks, the scrollbar is
   made permanent, and the cut edge is shaded while there is more below. */
.strip-queue {
  position: sticky; top: 0; z-index: 3;
  box-shadow: 0 6px 12px -8px color-mix(in srgb, #1d1f20 45%, transparent);
}

.strip-clear {
  background: var(--color-accent-100); color: var(--color-accent-800);
  border-radius: var(--radius-md); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
}

/* ── Controls ───────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 14px; line-height: 1.2; color: var(--color-text);
  background: transparent; border: 1px solid var(--color-divider);
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-4);
  cursor: pointer; text-decoration: none;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-bg); }
.btn-primary:hover:not(:disabled) { background: var(--color-accent-600); }
.btn-ghost { border-color: transparent; color: var(--color-accent-700); padding-inline: var(--space-1); }
/* A one-button form in a row of chips, so signing out sits beside the name
   it applies to rather than breaking the header onto a second line. */
form.inline { display: inline; }

.input {
  font-family: var(--font-body); font-size: 14px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
  background: #fff; width: 100%;
}

.tag {
  display: inline-block; font-family: var(--font-heading);
  font-size: 10px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; padding: 3px 6px; border-radius: var(--radius-md);
  border: 1px solid var(--color-divider);
}
.tag-accent { background: var(--color-accent-100); border-color: var(--color-accent-400); color: var(--color-accent-800); }

/* ── Drawer ─────────────────────────────────────────────────────────────── */

.drawer {
  border-top: 1px solid var(--color-divider);
  background: var(--color-neutral-100);
  padding: var(--space-2) var(--space-4);
  font-size: 12px;
}
.drawer .tabs { display: flex; gap: var(--space-4); align-items: baseline; }
.drawer .tab { color: var(--color-neutral-700); text-decoration: none; }
.drawer .tab[aria-current="true"] { color: var(--color-text); font-weight: 600; }
.drawer .built { margin-left: auto; color: var(--color-neutral-500); }

/* ── Source spine ───────────────────────────────────────────────────────── */

/* Open: a real pane, remembered per project. Dismissed: a spine you can get
   back from. Never an overlay -- you must be able to scan the sheet and read
   the page at the same time (deck 1j, option C rejected). */
.source {
  grid-area: source; overflow-y: auto;
  border-left: 1px solid var(--color-divider);
  background: var(--color-neutral-100);
  padding: var(--space-4);
  /* The remembered width is a preference, not a licence to take the screen.
     Half-width is the most the deck offers (1j option B) and the grid must stay
     scannable at the same time -- the whole reason the overlay option was
     rejected is that you cannot read the page and scan the sheet at once. */
  max-width: min(46vw, 620px);
}
.source-head { margin-bottom: var(--space-3); }
.source-body { display: flex; flex-direction: column; gap: var(--space-2); }

.passage { padding: var(--space-3); border: 1px solid transparent; border-radius: var(--radius-md); }
.passage-label {
  font-family: var(--font-heading); font-size: 10.5px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--color-neutral-600); margin-bottom: 2px;
}
.passage-text { font-size: 13px; }
.passage.is-anchor { background: color-mix(in srgb, #5980a6 14%, transparent); border-color: var(--color-accent); }
/* An excluded passage stays visible and stays refusable. Hiding it would make
   the boundary invisible; greying it out without saying why would make it look
   broken. */
.passage.excluded { opacity: 0.55; border-style: dashed; border-color: var(--color-neutral-400); }
.passage form { margin-top: var(--space-2); }

.source-spine {
  grid-area: source; width: 44px; border-left: 1px solid var(--color-divider);
  background: var(--color-neutral-200);
}
.source-spine button {
  width: 100%; height: 100%; border: 0; background: transparent; cursor: pointer;
  writing-mode: vertical-rl; text-orientation: mixed;
  font-family: var(--font-heading); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--color-neutral-700);
}

/* ── Rail collapsed to a spine ──────────────────────────────────────────── */

.rail-spine {
  grid-area: rail; background: var(--color-accent-900);
  display: flex; flex-direction: column; align-items: center;
  gap: var(--space-3); padding: var(--space-4) 0;
}
.rail-spine > button, .rail-collapse {
  background: transparent; border: 0; cursor: pointer;
  color: color-mix(in srgb, #f2f2f3 70%, transparent); font-size: 14px;
}
.spine-stage { position: relative; color: var(--color-bg); text-decoration: none; opacity: 0.7; }
.spine-stage:hover { opacity: 1; }
/* The count does not fit on a spine, so the obligation becomes a mark -- work
   owed is still visible, just not enumerated (deck 1l, option B's trade). */
.spine-dot {
  position: absolute; top: -2px; right: -7px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--color-owed-bg);
}

/* ── Drawer, dismissed to one line ──────────────────────────────────────── */

.drawer-closed { padding: 0; }
.drawer-closed button {
  width: 100%; text-align: left; background: transparent; border: 0;
  padding: var(--space-2) var(--space-4); cursor: pointer;
  font-family: var(--font-body); font-size: 12px; color: var(--color-neutral-700);
}
.drawer-closed .kicker { display: inline; margin-right: var(--space-2); }

/* ── Utility ────────────────────────────────────────────────────────────── */

.stack > * + * { margin-top: var(--space-3); }
.row { display: flex; align-items: center; gap: var(--space-3); }
.muted { color: var(--color-neutral-600); }

/* ── Extract: the protocol walk and the run log ─────────────────────────── */

.walk { list-style: none; margin: 0; padding: 0; }
.walk-step {
  display: grid; grid-template-columns: 20px 15em 1fr;
  gap: var(--space-2); align-items: baseline;
  padding: var(--space-2) 0; border-bottom: 1px solid var(--color-divider);
}
.walk-step:last-child { border-bottom: 0; }
.walk-step[data-state="queued"] { opacity: 0.5; }
.walk-step[data-state="active"] .walk-name { font-weight: 600; }
.walk-mark { color: var(--color-accent); }
.walk-step[data-state="open"] .walk-mark { color: var(--color-owed); }

.runlog { border-collapse: collapse; width: 100%; font-size: 13px; }
.runlog td { padding: var(--space-1) 0; vertical-align: baseline; }
.runlog td:first-child { width: 13em; }
/* A field the run log still owes reads as owed, not as blank. */
.runlog tr[data-owed="true"] td:nth-child(2) { color: var(--color-owed); }
/* The writer column: set back, right-aligned, and italic, so the table reads as
   a record with a provenance margin rather than as label/field pairs. Two
   models read the old two-column layout as a form and typed into it. */
.runlog td.written-by {
  text-align: right; font-style: italic; font-size: 12px;
  white-space: nowrap; padding-left: var(--space-2);
}

/* ── Review: grid as the surface, card as the row expansion ─────────────── */

.tabs-sheet { display: flex; gap: var(--space-4); margin-bottom: var(--space-3); }
.sheet-tab {
  font-family: var(--font-heading); font-size: 13px; text-decoration: none;
  color: var(--color-neutral-600); padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}
.sheet-tab[aria-current="true"] { color: var(--color-text); border-bottom-color: var(--color-accent); }

.grid { width: 100%; border-collapse: collapse; background: #fff;
        border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); overflow: hidden; }
.grid th {
  text-align: left; font-family: var(--font-heading); font-size: 10.5px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-neutral-600);
  padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-divider);
}
.grid td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid color-mix(in srgb, #1d1f20 8%, transparent); }

/* With the pane open the column is narrow and vertical space is the scarce
   thing, so the rows give back what they can. Worth a few factors, not the
   whole cut -- the sticky count above is what carries the rest. */
.app:has(.source[data-open]) .grid td,
.app:has(.source[data-open]) .grid th { padding-block: var(--space-1); }

/* And the status wraps rather than being cut mid-word. `nowrap` in a column
   this narrow put "cross-standard -- decline or map to NASA-STD-7009B" on the
   screen as "cross-standard -- decline or m", clipped by the table's own
   rounded overflow, with no ellipsis to say it had been. An instruction a
   reviewer cannot finish reading is an instruction that was not given.

   Tighter than the unwrapped version, and measured rather than eyeballed:
   wrapping alone made every row two lines in the scaffolded state and cost a
   13in laptop two of the nine factors it could see. At 1.15/10.5px -- the size
   the column headers already use -- the status is fully readable AND the row
   count is restored. Readability was not worth buying with density. */
.app:has(.source[data-open]) .grid .status {
  white-space: normal; line-height: 1.15; font-size: 10.5px;
}
.grid .num { text-align: center; font-variant-numeric: tabular-nums; width: 4.5em; }
.grid-link { color: inherit; text-decoration: none; }
.grid-row[data-selected="true"] { background: color-mix(in srgb, #5980a6 10%, transparent); }
.grid-row[data-selected="true"] td:first-child { box-shadow: inset 2px 0 0 var(--color-accent); }

/* Per-cell provenance: an edge mark, so it lives where the value is and costs
   no column. The word rides in the row expansion, where there is room for it. */
.grid td[data-prov] { position: relative; }
.grid td[data-prov]::before {
  content: ""; position: absolute; left: 0; top: 15%; bottom: 15%; width: 2px;
}
.grid td[data-prov="defaulted"]::before { background: var(--color-owed); }
.grid td[data-prov="extracted"]::before { background: var(--color-neutral-400); }
.grid td[data-prov="confirmed"]::before { background: var(--color-accent); }
.grid td[data-prov="corrected"]::before,
.grid td[data-prov="author-added"]::before,
.grid td[data-prov="author-recovered"]::before { background: var(--color-accent-700); }
.grid td[data-prov="source-absent"]::before { background: var(--color-neutral-300); }
.grid td[data-prov="declined-mapping"]::before { background: var(--color-neutral-500); }

/* A shortfall is shown by weight, not by an alarm colour. */
.grid .shortfall { font-weight: 700; color: var(--color-accent-800); }

.grid .status { font-size: 11.5px; white-space: nowrap; color: var(--color-neutral-500); }
.grid .status[data-state="owed"] { color: var(--color-owed); font-weight: 600; }

.expansion td { background: var(--color-neutral-100); }
.prov-chips { display: flex; gap: var(--space-2); align-items: baseline; margin-bottom: var(--space-2); }
.chip-word {
  font-family: var(--font-heading); font-size: 10px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 3px 6px; border: 1px solid var(--color-divider); border-radius: var(--radius-md);
}
.teaching { font-size: 12.5px; color: var(--color-owed); margin: var(--space-2) 0; max-width: 62ch; }
.actions { flex-wrap: wrap; margin-top: var(--space-3); }
.actions form { margin: 0; }
.sc { font-size: 10px; opacity: 0.6; border: 1px solid currentColor; border-radius: 3px; padding: 0 3px; }

/* ── Dispositions ───────────────────────────────────────────────────────── */

.grid .dstate { width: 7em; }
.grid .finding { font-size: 13px; }
.grid .verdict-cell { width: 16em; }
.tag-judgment { background: var(--color-owed-bg); border-color: var(--color-owed); color: var(--color-owed); }
.tag-silent { color: var(--color-neutral-600); }

/* Settled rows: quiet gray attribution, never live controls. */
.attribution { font-size: 12px; color: var(--color-neutral-600); }

.judgment-note {
  color: var(--color-owed); font-weight: 600; max-width: 62ch;
  margin: 0 0 var(--space-2);
}

/* The machine's proposal renders as an inert ghost until a human adopts it.
   Dashed and unselected: it must not look like a state the row is already in,
   because the single click that adopts it is the act the firewall protects. */
.ghost-draft {
  border-style: dashed; color: var(--color-neutral-600);
  background: transparent;
}
.draft-tag {
  font-size: 9.5px; letter-spacing: 0.06em; text-transform: uppercase;
  opacity: 0.75;
}
.input.defer { width: 18em; display: inline-block; }

/* ── Preview and Finalize ───────────────────────────────────────────────── */

.watermark-bar {
  background: repeating-linear-gradient(45deg,
    var(--color-neutral-200), var(--color-neutral-200) 10px,
    var(--color-neutral-100) 10px, var(--color-neutral-100) 20px);
  color: var(--color-neutral-700);
  font-family: var(--font-heading); font-size: 11px; font-weight: 600;
  letter-spacing: 0.12em; text-align: center;
  padding: var(--space-2); margin-bottom: var(--space-4);
  border-radius: var(--radius-md);
}

.card.gap h4 { font-family: var(--font-heading); font-size: 16px; margin-bottom: var(--space-2); }
.card.gap .row { margin-top: var(--space-3); }

.news { margin: var(--space-3) 0 var(--space-6); padding-left: var(--space-3);
        border-left: 2px solid var(--color-neutral-300); }

.figures { display: flex; gap: var(--space-8); margin: var(--space-4) 0; flex-wrap: wrap; }
.figure-num { font-family: var(--font-heading); font-size: 26px; line-height: 1.1; }
/* The label is not optional chrome. A bare percentage is read as a grade, and
   there is deliberately no total anywhere for a reader to land on. */
.figure-label { font-size: 11px; color: var(--color-neutral-600); max-width: 16ch; }

.missing { margin: var(--space-2) 0 0; padding-left: 1.1em; font-size: 13px; }
.missing li { margin-bottom: var(--space-2); }
.queued { font-size: 11px; margin-left: var(--space-2); }

.passing { margin: var(--space-4) 0; font-size: 13px; }
.passing summary { cursor: pointer; color: var(--color-neutral-700); }
.passing ul { margin: var(--space-2) 0 0; padding-left: 1.2em; color: var(--color-neutral-600); }

.will-not-say { background: var(--color-neutral-100); box-shadow: none;
                border: 1px solid var(--color-divider); }
.will-not-say p { max-width: 74ch; margin: 0; }

/* ── Drawer panels ──────────────────────────────────────────────────────── */

.grid.ledger .mono { font-family: ui-monospace, monospace; font-size: 11.5px;
                     color: var(--color-neutral-600); white-space: nowrap; }
.prior { display: inline-block; margin-left: var(--space-2); font-size: 11px;
         color: var(--color-neutral-600); }
.owed-inline { color: var(--color-owed); font-weight: 600; font-size: 12px; }
.panel-empty { color: var(--color-neutral-600); }

.edit-row { padding: var(--space-3) 0; border-bottom: 1px solid var(--color-divider); }
.edit-row .input { max-width: 30em; }

/* An unmeasured figure must not read like a measured zero. */
.figure-num.unmeasured { color: var(--color-owed); font-size: 19px; }

/* The CLI's own words, not a paraphrase of them. */
.cli-out {
  font-family: ui-monospace, monospace; font-size: 11.5px; line-height: 1.5;
  background: var(--color-neutral-100); border-radius: var(--radius-md);
  padding: var(--space-3); overflow-x: auto; white-space: pre-wrap;
  margin: var(--space-2) 0 0;
}

/* ── Narrow windows ─────────────────────────────────────────────────────── */
/*
 * The layout is designed for desktop (build spec §2), but "designed for desktop"
 * is not a licence to become unusable below it. Three things compete for width:
 * the rail, the sheet, and the source. The sheet is the one that must never lose
 * -- it is the surface the work happens on -- so the rail gives up its labels
 * first and the source gives up its width second.
 */
@media (max-width: 1200px) {
  .app { grid-template-columns: var(--rail-spine-w) minmax(0, 1fr) auto; }
  .rail { padding: var(--space-4) 0; }
  .rail .stage-name, .rail .stage-gate, .rail .kicker { display: none; }
  .rail .stage { text-align: center; padding: var(--space-2) 0; }
  .rail .owed { margin: 0; font-size: 9px; }
  .source { max-width: 40vw; }
}

@media (max-width: 900px) {
  /* Below this the pane and the sheet cannot both be read, and the deck already
     ruled out the overlay that would pretend otherwise. The source drops to its
     spine and the reader opens it deliberately. */
  .source { max-width: 34vw; font-size: 12px; }
  .source .passage-text { font-size: 12px; }
}

/* ── Drop zone ──────────────────────────────────────────────────────────── */

.dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-1); min-height: 88px; cursor: pointer;
  border: 1.5px dashed var(--color-neutral-400); border-radius: var(--radius-md);
  padding: var(--space-4); margin-bottom: var(--space-3);
  color: var(--color-neutral-700);
}
.dropzone strong { font-family: var(--font-heading); font-size: 15px; }
.dropzone[data-over] { border-color: var(--color-accent); background: var(--color-accent-100); }

.admitted-list { list-style: none; margin: 0 0 var(--space-3); padding: 0; font-size: 13px; }
.admitted-list li { padding: 2px 0; }
.admitted-list .mono { font-family: ui-monospace, monospace; font-size: 12px; }
.card.archive .figures { gap: var(--space-6); margin: var(--space-3) 0; }

/* A fact read out of a sealed member is not a page, and should not look like one. */
.passage.fact { border-left: 2px solid var(--color-accent-400); background: #fff; }
.passage.fact .mono { font-family: ui-monospace, monospace; font-size: 10.5px; }

/* ── Guided overlay ─────────────────────────────────────────────────────── */

.card.guided { background: var(--color-accent-100); box-shadow: none;
               border: 1px solid var(--color-accent-400); }
.guided-item + .guided-item { margin-top: var(--space-3);
                              padding-top: var(--space-3);
                              border-top: 1px solid var(--color-accent-400); }
.card.guided p { margin: 0; max-width: 76ch; font-size: 13px; }

/* ── The public shell: landing page and planner ──────────────────────────────
   A founder arriving with no working set. Same tokens, same cards, same ochre
   for what is unresolved -- a wider column and no rail, because there are no
   six stages to show somebody who has not started one. */
.public { display: flex; flex-direction: column; min-height: 100vh;
          background: var(--color-bg); }
/* Geometry now lives in the shared `.head, .public-head` rule above. What is
   left here is the nav, which only this shell has. */
.public-nav { display: flex; gap: var(--space-6); flex-wrap: wrap; }
.public-nav a { color: var(--color-accent-200); text-decoration: none;
                font-size: 14px; }
.public-nav a:hover { color: #fff; text-decoration: underline; }
.public-main { flex: 1; width: 100%; max-width: 880px; margin: 0 auto;
               padding: var(--space-8) var(--space-6); }
.public-foot { border-top: 1px solid var(--color-divider);
               padding: var(--space-6) var(--space-8); }
.public-foot .note { max-width: 880px; margin: 0 auto var(--space-3); }

/* The hero. One claim, one action, and the limits beside them rather than in
   a footnote nobody reaches. */
.hero { margin-bottom: var(--space-8); }
.hero h1 { font-size: 30px; line-height: 1.2; margin: 0 0 var(--space-4); }
.hero .lede { font-size: 17px; max-width: 62ch; }
.hero-terms { display: flex; flex-wrap: wrap; gap: var(--space-4);
              margin-top: var(--space-4); font-size: 13px;
              color: var(--color-neutral-700); }

/* Cards that carry a figure, used by the preview and the worked example. */
.figure-card { display: flex; flex-wrap: wrap; gap: var(--space-8); }
.figure-card > div { flex: 1 1 200px; }
.figure-head { font-family: var(--font-heading); font-size: 26px;
               line-height: 1.15; }
.figure-partial { color: var(--color-owed); font-size: 13px;
                  margin-top: var(--space-2); }

@media (max-width: 700px) {
  /* Both headers now, not just the public one. `.head` had no mobile rule at
     all, so the workbench header did not reflow under 700px. */
  .head, .public-head { flex-wrap: wrap; gap: var(--space-3);
                 padding: var(--space-3) var(--space-4); }
  .public-main { padding: var(--space-6) var(--space-4); }
  .hero h1 { font-size: 24px; }
  .figure-card { gap: var(--space-4); }
}

/* The critical chain. Numbered, because it IS an order -- and one column, so
   nothing suggests the parallel work that is not on it. */
.chain { margin: var(--space-3) 0; padding-left: var(--space-6); }
.chain li { margin-bottom: var(--space-2); }

/* Facts as a description list: label over value when there is no room for them
   side by side, rather than a fixed label column squeezing the value to one
   word per line. */
.facts { display: grid; grid-template-columns: 15rem 1fr; gap: 0;
         margin: var(--space-3) 0 0; }
.facts dt { padding: var(--space-3) 0; color: var(--color-neutral-700);
            border-top: 1px solid var(--color-divider); }
.facts dd { padding: var(--space-3) 0; margin: 0;
            border-top: 1px solid var(--color-divider); }

/* A wide table gets its own scroll region. The page itself never scrolls
   sideways -- a reader who has to pan the whole document to read one column
   loses the rest of the screen to do it. */
.table-scroll { overflow-x: auto; scrollbar-gutter: stable; }
.table-scroll .grid { min-width: 34rem; }

@media (max-width: 700px) {
  .facts { grid-template-columns: 1fr; }
  .facts dt { padding-bottom: 0; border-top: 1px solid var(--color-divider); }
  .facts dd { padding-top: var(--space-1); border-top: 0; }
}

/* The disclaimer at the foot of a workbench stage. Not a grid row: `.app` is
   100vh and a row would take height from the review pane, so it rides the
   bottom of the scrolled column instead -- directly under the unsigned-package
   link, which is where somebody is about to walk away with an artifact. */
.app-foot {
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-divider);
  max-width: 880px;
}

/* The width sentence, between the figure and the explanation of what a band
   is. Heavier than `.note` because it is the line that should stop a reader:
   it says how much of this plan is still open, and where. */
.figure-width {
  margin: var(--space-3) 0 var(--space-2);
  font-size: 13.5px; line-height: 1.5;
  color: var(--color-text);
}
