:root {
  --bg: #f4f6f9;
  --surface: #ffffff;
  --surface-2: #fbfcfe;
  --border: #dfe4ec;
  --border-strong: #c6cedb;
  --text: #182231;
  --text-soft: #5a6779;
  /* ⚠ WAS #8b96a7 -- 2.99:1 on white, a FAIL, and it carries EVERY small
     label on the board ("per shift", "fans/shift", the rank sub-line). AA
     leaves no room for two distinct greys under 4.5:1, so the faint level and
     the N/A level are now the same value. The ladder is --text (16.0),
     --text-soft (5.75), faint (5.01). */
  --text-faint: #646D7B;
  --accent: #1f5fd0;
  --accent-soft: #e8f0ff;
  --good: #0f7a52;
  --good-soft: #e2f5ec;
  --warn: #9a5b00;
  --warn-soft: #fdf0dc;
  --na: #98a2b3;
  --na-soft: #f1f3f7;
  --danger: #b3261e;
  --danger-soft: #fdecea;
  /* TRUE ZERO. Must stay legible on --surface, on the striped unranked row,
     and on the blue --accent-soft selected cell. */
  /* ================= 026: ONE COLOUR, ONE MEANING =================
     Every colour on this board means exactly one thing everywhere it appears.
     If a reader has to ask "is this amber because it is a Suicide page, or
     because something is wrong?", the colour is worse than none.
     ⛔ TWO COLLISIONS AVOIDED DELIBERATELY:
       * UNPROVEN AT THIS LOAD is NOT amber. Amber is the SUICIDE account type
         (Johnson's instruction), and a caution sharing a colour with an account
         type is exactly the ambiguity above.
       * INTENT is NOT --accent blue. That blue is the DECIDING NUMBER -- the
         REV/SHIFT column and its label in the formula block. An account type
         must never wear the colour of the figure that decides the allocation.
     ⚠ The SUICIDE and INTENT values are the ones already on the board and
     already contrast-measured; 026 moves them into tokens, it does not
     re-pick them. A colour that exists in one place changes in one place. */
  --game-sui: #6E4A00;          /* SUICIDE -- gold. NOT --warn (#9a5b00 is a
                                   muddy brown, and --warn means caution) */
  --game-sui-soft: #FFF1CC;
  --game-int: #0A5560;          /* INTENT -- teal, far from --accent blue */
  --game-int-soft: #D8F3F8;
  --best: var(--good);          /* BEST HANDLER, and ONLY that. Green reads as
                                   "this is good", and top handler on an account
                                   genuinely is. Intent pages are not "good" --
                                   they are a different game, which is why green
                                   was wrong there and is right here. */
  --best-soft: var(--good-soft);
  --caution: #A3243D;           /* UNPROVEN AT THIS LOAD / LIGHTEST LOAD HERE.
                                   A caution about READING a number, never an
                                   account type. ⚠ NOT applied to HEAVIER LOAD:
                                   that one is favourable. */
  --caution-soft: #FDEAEE;
  /* ⛔ --na IS NOT LEGIBLE AS TEXT ON A LIGHT BACKGROUND. Measured #98a2b3:
     2.58:1 on white, 2.38:1 on the page -- both well under WCAG AA's 4.5:1.
     It was carrying N/A, UNTESTED and the $ PER FAN label, all of which are
     meant to be QUIET, not unreadable. --na keeps its job on fills and
     borders; text uses this. Measured 5.23:1 on white, 4.83:1 on the page and
     4.57:1 on the BLUE REV/SHIFT column -- that last case is the binding one,
     and it is exactly what an eyeball would have missed. */
  --na-text: #646D7B;
  /* ---- 028: SHIFT COLOURS. Johnson's: morning yellow, evening orange,
     midnight blue. These are SOLID FILLS -- see the shiftTag() comment in
     app.js for why the fill, not the hue, is what keeps them apart from the
     amber/teal ACCOUNT TYPE tags.
     ⚠ MIDNIGHT IS DELIBERATELY A VERY DARK NAVY, not a mid blue: --accent
     (#1f5fd0) is the deciding number and a mid blue pill would sit right on
     top of it. Measured separation from --accent: rgb-distance 129, contrast
     2.44 -- see the report; this is the widest gap available while still
     being recognisably "midnight blue". */
  --shift-morning-bg: #FFD84D;  --shift-morning-fg: #3A2D00;
  --shift-evening-bg: #FF9640;  --shift-evening-fg: #3A1B00;
  --shift-midnight-bg: #15275C; --shift-midnight-fg: #EAF1FF;
  --zero: #c62828;
  --zero-soft-text: #a8443c;
  --zero-bg: #fbe3e0;
  --shadow: 0 1px 2px rgba(24,34,49,.06), 0 4px 14px rgba(24,34,49,.06);
  --radius: 10px;
  /* ⚠ --num is the SANS face with lining figures. --mono survives for
     exactly two things: the identity key and the sha256 in the drawer's
     technical block, where character-by-character comparison is the
     whole point. Everything else that was monospace is now --num. */
  --num: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
  /* 028 shift colours, dark. ⚠ Midnight moves LIGHTER here, not darker: on a
     dark page a navy pill would disappear into the navy REV/SHIFT column
     (--accent-soft #1c2b45). Measured rgb-distance from that column 132, from
     --accent 107 -- the most balanced of the candidates tested. */
  --shift-morning-bg: #E8C34A;  --shift-morning-fg: #241B00;
  --shift-evening-bg: #E8883A;  --shift-evening-fg: #2A1200;
  --shift-midnight-bg: #3E63B8; --shift-midnight-fg: #EAF1FF;
  /* 026 tokens, dark. Same meanings, lifted for contrast. */
  --game-sui: #FFD24A;
  --game-sui-soft: #3A2E08;
  --game-int: #5FDCEC;
  --game-int-soft: #07323A;
  --best: var(--good);
  --best-soft: var(--good-soft);
  --caution: #F2879E;
  --caution-soft: #3D1A24;
  /* ⛔ MEASURED, NOT ASSUMED: --na #6b7688 as text on --surface is 3.68:1, a
     FAIL. I first wrote var(--na) here on the assumption that dark greys are
     safe. They are not. #8a95a4 measures 5.57:1 on the panel and 4.67:1 on the
     blue REV/SHIFT column -- the blue is the binding case here too -- and it
     still sits below --text-soft (7.53), so the ladder holds. */
  --na-text: #8a95a4;
    --bg: #11151b;
    --surface: #181d25;
    --surface-2: #1e242e;
    --border: #2a323e;
    --border-strong: #3a4453;
    --text: #e8edf4;
    --text-soft: #a3aebd;
    /* ⚠ WAS #7a8695. That measures 4.57:1 on the panel and passes -- but only
       3.83:1 on the BLUE REV/SHIFT column and 4.21:1 on the table headers,
       both FAILS. The binding background is never the plain panel. */
    --text-faint: #8a95a4;
    --accent: #6ea3ff;
    --accent-soft: #1c2b45;
    --good: #4bd39a;
    --good-soft: #123528;
    --warn: #e0a44a;
    --warn-soft: #33270f;
    --na: #6b7688;
    --na-soft: #202631;
    --danger: #ff8a80;
    --danger-soft: #3a1c1a;
    --zero: #ff6b60;
    --zero-soft-text: #d98078;
    --zero-bg: #3d1f1c;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 4px 14px rgba(0,0,0,.3);
  }
}

* { box-sizing: border-box; }

/* Any explicit display rule below would otherwise defeat the hidden attribute. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
}

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

/* ---------- top bar ---------- */
.topbar {
  display: flex; align-items: center; gap: 16px;
  padding: 12px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 30;
}
.brand { display: flex; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; }
.brand-mark {
  width: 36px; height: 36px; flex: 0 0 36px; border-radius: 9px;
  /* --bg, not #fff: white on the LIGHT dark-mode accent measures 2.52:1. The
     page background is dark where the accent is light and light where it is
     dark, so it is legible in both without a theme override. */
  background: var(--accent); color: var(--bg);
  display: grid; place-items: center; font-weight: 700; font-size: 15px;
}
.brand-text h1 { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: -.01em; }
.brand-text p { margin: 0; font-size: 12px; color: var(--text-soft); }
.runtime {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--text-soft);
  font-family: var(--num); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); flex: 0 0 7px; }
.rail-toggle {
  display: none;
  padding: 7px 14px; border-radius: 8px; border: 1px solid var(--border-strong);
  background: var(--surface-2); color: var(--text); font: inherit; font-size: 13px;
  cursor: pointer;
}

/* ---------- certification banner ---------- */
.cert-banner {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  border-left: 4px solid var(--good);
  padding: 10px 20px 11px;
}
.cert-line {
  margin: 0; font-size: 12.5px; font-weight: 700; letter-spacing: .02em;
  display: flex; align-items: baseline; gap: 7px;
}
.cert-verified { color: var(--good); }
.cert-caution { color: var(--warn); margin-top: 3px; }
.cert-sub {
  margin: 5px 0 0; font-weight: 400; letter-spacing: 0;
  font-size: 11.5px; line-height: 1.5; color: var(--text-soft); max-width: 108ch;
}

/* ---------- layout ---------- */
.workspace {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: 18px;
  padding: 18px 20px 40px;
  align-items: start;
}

/* ---------- model rail ---------- */
.model-rail {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  position: sticky; top: 78px;
  max-height: calc(100vh - 96px);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.rail-heading { padding: 14px 14px 8px; }
.rail-heading h2 { margin: 0; font-size: 14px; font-weight: 650; }
.rail-heading p { margin: 2px 0 0; font-size: 11.5px; color: var(--text-soft); font-family: var(--num); font-variant-numeric: tabular-nums; }
.rail-search { display: block; padding: 0 14px 10px; }
.rail-search input {
  width: 100%; padding: 7px 10px; font: inherit; font-size: 13px;
  border: 1px solid var(--border-strong); border-radius: 7px;
  background: var(--surface-2); color: var(--text);
}
.rail-search input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.model-list { overflow-y: auto; padding: 0 8px 10px; }
.model-button {
  width: 100%; text-align: left; display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; margin-bottom: 2px;
  border: 1px solid transparent; border-radius: 7px;
  background: transparent; color: var(--text); font: inherit; cursor: pointer;
}
.model-button:hover { background: var(--surface-2); }
.model-button[data-active="true"] {
  background: var(--accent-soft); border-color: var(--accent);
}
.model-button .m-name { font-weight: 600; font-size: 13.5px; flex: 1 1 auto; }
.model-button .m-id { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 10.5px; color: var(--text-faint); }
.m-tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: .06em;
  padding: 2px 6px; border-radius: 4px; flex: 0 0 auto;
}
.rail-empty { padding: 14px; font-size: 12.5px; color: var(--text-soft); }

/* ---------- model head ---------- */
.dashboard-main { min-width: 0; display: flex; flex-direction: column; gap: 16px; }
/* Flex children default to min-width:auto and would refuse to shrink below the
   940px table, pushing the whole page sideways. The table scrolls in its own box. */
.dashboard-main > * { min-width: 0; }
.model-head {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 16px 18px;
  display: flex; flex-wrap: wrap; gap: 16px; justify-content: space-between; align-items: flex-start;
}
.eyebrow {
  margin: 0 0 2px; font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11px;
  color: var(--text-faint); letter-spacing: .04em;
}
.model-head h2 { margin: 0; font-size: 24px; font-weight: 680; letter-spacing: -.02em; }
.subtle { margin: 3px 0 0; font-size: 13px; color: var(--text-soft); }
.alias-note {
  margin: 6px 0 0; font-size: 11.5px; color: var(--text-soft);
  background: var(--na-soft); border: 1px solid var(--border);
  padding: 4px 8px; border-radius: 6px; display: inline-block;
}
.model-head-cutoff { text-align: right; }
.cutoff-label { display: block; font-size: 11px; color: var(--text-faint); letter-spacing: .04em; text-transform: uppercase; }
.model-head-cutoff strong { display: block; font-size: 15px; font-family: var(--num); font-variant-numeric: tabular-nums; margin-top: 2px; }
.cutoff-note { display: block; font-size: 11px; color: var(--text-soft); margin-top: 2px; }

/* ---------- summary cards ---------- */
/* three cards since 028 removed EVIDENCE COVERAGE -- auto-fit so they fill the
   row instead of leaving a fourth-column gap */
.summary-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px;
}
.summary-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 13px 15px; min-width: 0;
}
.summary-label {
  display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-faint); font-weight: 650;
}
.summary-value {
  display: block; margin-top: 5px; font-size: 18px; font-weight: 650;
  letter-spacing: -.01em; overflow-wrap: anywhere;
}
.summary-context { margin: 3px 0 0; font-size: 12px; color: var(--text-soft); overflow-wrap: anywhere; }
.summary-value.muted { color: var(--na-text); font-weight: 550; font-size: 15px; }

/* ---------- ranking panel ---------- */
.ranking-panel {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden;
}
.panel-toolbar {
  display: flex; flex-wrap: wrap; gap: 14px; justify-content: space-between; align-items: flex-end;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.panel-title h3 { margin: 0; font-size: 15px; font-weight: 650; }
.panel-title p { margin: 2px 0 0; font-size: 12px; color: var(--text-soft); }
.filters { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.field {
  display: flex; flex-direction: column; gap: 3px;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-faint); font-weight: 650;
}
.field select {
  font: inherit; font-size: 13px; text-transform: none; letter-spacing: 0; font-weight: 400;
  padding: 6px 9px; border: 1px solid var(--border-strong); border-radius: 7px;
  background: var(--surface-2); color: var(--text); min-width: 116px;
}
.checkbox-field {
  flex-direction: row; align-items: center; gap: 7px;
  text-transform: none; letter-spacing: 0; font-size: 12.5px; font-weight: 400; color: var(--text-soft);
  padding-bottom: 6px;
}
.checkbox-field input { width: 15px; height: 15px; accent-color: var(--accent); }

.table-scroll { overflow-x: auto; }
.ranking-table { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 940px; }
.ranking-table thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface-2); text-align: left;
  padding: 9px 10px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-faint); font-weight: 700; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.ranking-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.ranking-table tbody tr { cursor: pointer; }
.ranking-table tbody tr:hover { background: var(--surface-2); }
/* ⚠ 35%, NOT 55%. The stripe sits BEHIND the text, so every point of tint it
   adds is taken off the contrast of the labels on that row -- measured 4.37:1
   at 55%, a FAIL, on rows that are already the hardest to read. The row is
   still visibly set apart; it just no longer eats its own legibility. */
.ranking-table tbody tr.is-unranked { background: color-mix(in srgb, var(--na-soft) 35%, transparent); }
.ranking-table tbody tr.is-unranked:hover { background: var(--na-soft); }

.col-rank { width: 54px; }
.rank-number { font-family: var(--num); font-variant-numeric: tabular-nums; font-weight: 650; color: var(--text-soft); }
.rank-number.leader { color: var(--accent); }
.rank-number.none { color: var(--na-text); }   /* 2.48:1 as raw --na */

.chatter-cell strong { display: block; font-weight: 620; font-size: 13.5px; }
.chatter-cell span { display: block; font-size: 11px; color: var(--text-faint); }
/* ⚠ `.chatter-cell .id-flag`, not bare `.id-flag`. `.chatter-cell span` sets
   --text-faint and OUT-SPECIFIES a single class, so the badge rendered grey
   text on its own red background. That was true of the old RESOLVED badge too
   -- it just never mattered while the badge was meaningless. */
.chatter-cell .id-flag, .id-flag {
  display: inline-block; margin-left: 5px; font-size: 9.5px; font-weight: 700;
  /* ⛔ --danger, NOT --warn. An unresolved id is a BROKEN ROW, not a caution
     about how to read a number, and --warn is amber -- the Suicide family.
     --danger already means "something is wrong here" (.error-panel) and is used
     for nothing else. --zero red stays separate: that marks a real zero VALUE. */
  padding: 1px 5px; border-radius: 4px;
  background: var(--danger-soft); color: var(--danger);
  border: 1px solid var(--danger);
  letter-spacing: .04em; vertical-align: middle;
}
/* .shift-chip retired in 028 -- the exact shift is now a .shift-tag pill */
.shift-cell span.sub { display: block; font-size: 10.5px; color: var(--text-faint); margin-top: 2px; }

.rate-cell { white-space: nowrap; font-variant-numeric: tabular-nums; }
.rate-cell strong { display: block; font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 650; }
.rate-cell small { display: block; font-size: 10.5px; color: var(--text-faint); font-family: var(--num); font-variant-numeric: tabular-nums; }
.rate-cell.complete strong { color: var(--text); }
.rate-cell.na strong { color: var(--na-text); font-weight: 550; }
.rate-cell.na small { color: var(--na-text); }
.rate-cell.active { background: var(--accent-soft); }
.rate-cell.active.na { background: var(--na-soft); }

/* ---------- TRUE ZERO ----------
   A complete window whose exact rate is zero. Red because it is a real result,
   not because anything is missing. The colour must survive the selected-cell
   background, so `.active` only ever sets a background, never a text colour. */
.rate-cell.true-zero strong,
.rate-cell.true-zero.active strong { color: var(--zero); font-weight: 700; }
.rate-cell.true-zero small { color: var(--zero-soft-text); }
.tz-tag {
  display: inline-block; margin-right: 5px;
  font-size: 8.5px; font-weight: 800; letter-spacing: .07em;
  padding: 1px 4px; border-radius: 3px;
  background: var(--zero-bg); color: var(--zero); vertical-align: 1px;
}

.depth-cell { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 12px; color: var(--text-soft); white-space: nowrap; }

.empty-row td { padding: 26px 14px; text-align: center; color: var(--text-soft); font-size: 13px; }

.panel-footer {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: space-between;
  padding: 10px 16px; border-top: 1px solid var(--border);
  font-size: 11.5px; color: var(--text-soft); font-family: var(--num); font-variant-numeric: tabular-nums;
}

/* .legend and .colour-legend rules deleted in 033 with the blocks they styled */


/* ---------- drawer ---------- */
.drawer {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(12,17,24,.42);
  display: flex; justify-content: flex-end;
}
.drawer[hidden] { display: none; }
.drawer-panel {
  width: min(560px, 100%); height: 100%;
  background: var(--surface); border-left: 1px solid var(--border);
  display: flex; flex-direction: column; overflow: hidden;
}
.drawer-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 15px 18px; border-bottom: 1px solid var(--border);
}
.drawer-head h3 { margin: 0; font-size: 17px; font-weight: 650; }
.drawer-close {
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text);
  width: 30px; height: 30px; border-radius: 7px; font-size: 19px; line-height: 1;
  cursor: pointer; flex: 0 0 auto;
}
.drawer-body { overflow-y: auto; padding: 16px 18px 40px; }

.d-section { margin-bottom: 18px; }
.d-section > h4 {
  margin: 0 0 8px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-faint); font-weight: 700;
}
.d-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 8px; }
.d-item {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 7px; padding: 8px 10px; min-width: 0;
}
.d-item .k { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); font-weight: 650; }
/* ⭐ THE ONE PLACE MONOSPACE STAYS: an identity key and a sha256 are read
   character by character, and a proportional face makes that harder. */
.d-item .v { display: block; font-family: var(--mono); font-size: 12.5px; margin-top: 2px; overflow-wrap: anywhere; }
.d-item .v.na { color: var(--na-text); }
.d-item.wide { grid-column: 1 / -1; }

.w-block { border: 1px solid var(--border); border-radius: 8px; margin-bottom: 9px; overflow: hidden; }
.w-head {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; justify-content: space-between;
  padding: 8px 11px; background: var(--surface-2); border-bottom: 1px solid var(--border);
}
.w-head .w-name { font-family: var(--num); font-variant-numeric: tabular-nums; font-weight: 700; font-size: 13px; }
.w-head .w-rate { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 650; }
.w-head .w-rate.na { color: var(--na-text); font-weight: 550; }
.w-status {
  font-size: 9.5px; font-weight: 700; letter-spacing: .05em;
  padding: 2px 6px; border-radius: 4px;
}
.w-status.complete { background: var(--good-soft); color: var(--good); }
.w-status.insufficient { background: var(--na-soft); color: var(--text-soft); }
.w-body { padding: 9px 11px; font-size: 12px; }
.w-row { display: flex; gap: 8px; padding: 2px 0; }
.w-row .k { color: var(--text-faint); min-width: 122px; flex: 0 0 122px; font-size: 11px; }
.w-row .v { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11.5px; overflow-wrap: anywhere; }
.w-row .v.na { color: var(--na-text); }
.w-head .w-rate.true-zero { color: var(--zero); font-weight: 700; }
.tz-note {
  margin-top: 8px; padding: 8px 10px; border-radius: 6px;
  background: var(--zero-bg); border: 1px solid color-mix(in srgb, var(--zero) 30%, transparent);
  font-size: 11.5px; line-height: 1.55; color: var(--text-soft);
}
.tz-note-title {
  display: block; font-weight: 800; letter-spacing: .06em;
  font-size: 10px; color: var(--zero); margin-bottom: 3px;
}
/* ⚠ --text-soft, not --text-faint. This line sits on the red-tinted TRUE ZERO
   note, and the faint grey measured 4.28:1 against that background -- a FAIL,
   on the one note in the drawer that explains why a number is zero. */
.tz-caution { display: block; margin-top: 5px; color: var(--text-soft); }
.tz-mismatch { color: var(--zero); }



.partial-note {
  margin-top: 7px; padding: 7px 9px; border-radius: 6px;
  background: var(--warn-soft); border: 1px solid color-mix(in srgb, var(--warn) 25%, transparent);
  font-size: 11px; color: var(--warn);
}
.partial-note .pn-title { font-weight: 700; letter-spacing: .04em; display: block; margin-bottom: 3px; }
.partial-note .pn-val { font-family: var(--num); font-variant-numeric: tabular-nums; color: var(--text-soft); }
.dates-list {
  font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11px; line-height: 1.7;
  color: var(--text-soft); overflow-wrap: anywhere;
}
.span-warn { color: var(--warn); font-size: 11px; margin-top: 4px; display: block; }

/* ---------- error ---------- */
.error-panel {
  position: fixed; left: 20px; right: 20px; bottom: 20px; z-index: 70;
  background: var(--danger-soft); color: var(--danger);
  border: 1px solid var(--danger); border-radius: var(--radius);
  padding: 13px 16px; font-size: 13px; box-shadow: var(--shadow);
}
.error-panel[hidden] { display: none; }

/* ---------- responsive ---------- */
@media (max-width: 1180px) {
  .summary-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

@media (max-width: 900px) {
  .workspace { grid-template-columns: minmax(0, 1fr); padding: 14px 14px 36px; }
  .rail-toggle { display: block; }
  .runtime { display: none; }
  .model-rail {
    position: fixed; inset: 0 auto 0 0; z-index: 50;
    width: min(300px, 86vw); max-height: none; height: 100%;
    border-radius: 0; border-left: 0; transform: translateX(-102%);
    transition: transform .18s ease;
  }
  .model-rail.open { transform: translateX(0); box-shadow: 0 0 0 100vmax rgba(12,17,24,.42); }
  .model-head-cutoff { text-align: left; }
  .drawer-panel { width: 100%; }
}

@media (max-width: 620px) {
  body { font-size: 14px; }
  .topbar { padding: 10px 14px; gap: 10px; }
  .brand-text p { display: none; }
  .cert-banner { padding: 8px 14px; font-size: 11.5px; }
  .cert-sub { font-size: 11px; }
  .summary-grid { grid-template-columns: minmax(0,1fr); gap: 10px; }
  .model-head h2 { font-size: 20px; }
  .panel-toolbar { flex-direction: column; align-items: stretch; }
  .filters { justify-content: space-between; }
  .field select { min-width: 0; width: 100%; }
  .field { flex: 1 1 130px; }
  .checkbox-field { flex: 1 1 100%; padding-bottom: 0; }
  .d-grid { grid-template-columns: minmax(0,1fr); }
  .w-row { flex-direction: column; gap: 0; }
  .w-row .k { flex-basis: auto; }
}

/* ---- MODE SWITCH: model view vs chatter view -------------------------- */
/* ⛔ THIS BLOCK WAS DARK-ONLY AND HAD NEVER BEEN THEMED. Measured on the light
   page: the unselected button read 1.11:1 and the selected one 3.09:1 -- the
   mode switch was very nearly invisible, and `var(--muted, ...)` names a token
   that does not exist anywhere, so it always fell through to its literal.
   ⚠ AND THE SELECTED STATE WAS ACCENT BLUE, which 026 reserves for the DECIDING
   NUMBER. A toggle is chrome; it must not wear the colour of the figure that
   decides an allocation. It is neutral now, and still obviously selected. */
.mode-switch{display:flex;gap:4px;margin:0 0 10px;padding:3px;border-radius:8px;
  background:var(--surface-2);border:1px solid var(--border)}
.mode-btn{flex:1;padding:6px 8px;border:0;border-radius:6px;cursor:pointer;
  background:transparent;color:var(--text-soft);font:inherit;font-size:12px;
  letter-spacing:.02em;transition:background .12s,color .12s}
.mode-btn:hover{color:var(--text)}
.mode-btn.is-on{background:var(--surface);color:var(--text);font-weight:700;
  box-shadow:inset 0 0 0 1px var(--border-strong)}

/* ---- DRAWER: rival comparison boxes ----------------------------------- */
.cmp{margin-top:14px;border:1px solid var(--border);border-radius:9px;overflow:hidden}
.cmp h5{margin:0;padding:8px 11px;font-size:11px;letter-spacing:.08em;
  background:var(--surface-2);color:var(--text-soft);text-transform:uppercase}
.cmp-note{padding:6px 11px;font-size:11px;color:var(--text-soft);line-height:1.5}
.cmp table{width:100%;border-collapse:collapse;font-size:12px}
.cmp td{padding:6px 11px;border-top:1px solid var(--border)}
.cmp td.n{text-align:right;font-variant-numeric:tabular-nums}
.cmp tr.me td{background:var(--accent-soft);color:var(--text);font-weight:700}
.cmp tr.beats td.n{color:var(--caution);font-weight:700}
.cmp .who{color:var(--text)}
.cmp .sh{color:var(--na-text);font-size:11px}
/* 2.2:1 on the light page before this -- the SUICIDE / INTENT section headers,
   which are the thing stopping the two units being read as one ranking. */
.ranking-table tr.group-head td{padding:9px 12px;font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--text-soft);background:var(--surface-2);
  border-top:1px solid var(--border);font-weight:700}

/* ---------- DENOMINATOR_BELOW_MATERIAL ----------
   Shaped like the TRUE ZERO badge but in the neutral N/A colour. A true zero is
   a RESULT; this is a REFUSAL to answer. They must never read the same. */
.dbm-tag {
  display: inline-block; margin-right: 5px;
  font-size: 8.5px; font-weight: 800; letter-spacing: .07em;
  padding: 1px 4px; border-radius: 3px;
  background: color-mix(in srgb, var(--na) 10%, transparent);
  color: var(--na-text); vertical-align: 1px; white-space: nowrap;
}
.dbm-note {
  margin-top: 8px; padding: 8px 10px; border-radius: 6px;
  background: color-mix(in srgb, var(--na) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--na) 30%, transparent);
  font-size: 11.5px; line-height: 1.55; color: var(--text-soft);
}
.dbm-note-title {
  display: block; font-weight: 800; letter-spacing: .06em;
  font-size: 10px; color: var(--na-text); margin-bottom: 3px;
}
.state-legend {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin-top: 6px; font-size: 11px; color: var(--text-faint);
}
.state-legend .sl-item { white-space: nowrap; }
.state-legend b { color: var(--text-soft); font-weight: 700; }

/* ---------- TASK 019 main view ---------- */
.load-flag { display: inline-block; margin: 3px 0 1px; }
/* THE BADGE COLOURS ARE TOKENS BECAUSE THE KEY BELOW MUST MATCH THEM EXACTLY.
   A reader who sees PROMISING one colour in the key and another in the table is
   worse off than with no key at all -- they would trust a mapping that is not
   real. Two copies of a colour drift the first time one is edited; one token
   cannot.
   Defined as var(--text) etc., NOT as literal hex, so dark mode keeps working:
   custom properties resolve where they are USED, so these follow the theme. */
:root {
  /* ⛔ NOT GREEN FOR EVIDENCE. Green is spoken for by BEST HANDLER, and
     "15 shifts of history" is not a value judgement -- a well-evidenced bad
     number is still bad. These are weights of certainty, not of quality. */
  --ev-strong: var(--text);      /* 16.01:1 on white */
  /* ⚠ ITS OWN VALUE, NOT --text-soft. Once --na-text had to darken to 5.23:1
     to stay legible on the blue column, --text-soft (5.75:1) sat almost on top
     of it and PROMISING and UNTESTED stopped looking like different bands.
     7.65:1 restores a real ladder: 16.0 / 7.7 / 5.2. */
  --ev-mid: #4A5464;
  --ev-weak: var(--na-text);     /* 5.23:1 */
}
@media (prefers-color-scheme: dark) {
  :root { --ev-mid: var(--text-soft); }   /* 7.53:1 -- the dark ladder is
                                             already 14.4 / 7.5 / 5.1 */
}
.depth-cell.ev-strong strong { color: var(--ev-strong); font-weight: 800; }
.depth-cell.ev-mid strong { color: var(--ev-mid); font-weight: 750; }
.depth-cell.ev-weak strong { color: var(--ev-weak); font-weight: 700; }
.depth-cell strong { display: block; font-size: 11px; letter-spacing: .05em; }
/* the Shifts column now carries a quiet dead-night count beneath the number */
.depth-cell.col-shifts strong { font-size: 13px; font-weight: 650; letter-spacing: 0; }
.depth-cell.col-shifts small { white-space: nowrap; }
.depth-cell small { display: block; font-size: 10px; color: var(--text-faint); }

/* ---------- TASK 024: the method strip and the traffic-sorted rail ---------- */

.method-strip {
  margin: 0 0 10px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.method-strip .steps {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin: 0; padding: 0; list-style: none;
}
.method-strip .steps li {
  flex: 1 1 260px; min-width: 200px;
  font-size: 11.5px; line-height: 1.45; color: var(--text-soft);
}
.method-strip .steps b {
  display: block; color: var(--text); font-size: 11px;
  letter-spacing: .05em; text-transform: uppercase;
}
.method-rules { margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--border); }
.method-toggle {
  margin-top: 8px; padding: 2px 8px; font-size: 10.5px; cursor: pointer;
  background: transparent; color: var(--text-faint);
  border: 1px solid var(--border); border-radius: 5px;
}
.method-toggle:hover { color: var(--text-soft); border-color: var(--border-strong); }
/* Steps 1-2 always visible; 3-6 and the rules fold, so the ranking table is
   never pushed below the fold. */
body.method-collapsed .method-strip .fold { display: none; }

.model-button .m-traffic {
  font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11px; color: var(--text-soft);
  flex: 0 0 auto; white-space: nowrap;
}

/* ⛔ YELLOW = SUICIDE (Johnson's instruction). CYAN = INTENT (chosen as the
   visual opposite of yellow so the two separate at a glance).
   ⛔ NOT green and NOT red, deliberately: green reads as "good" and would imply
   intent pages beat suicide pages; red reads as a warning. Neither is true —
   they are different games, not better and worse.
   Measured contrast, all >= 4.5:1 (WCAG AA):
     dark  yellow #FFD24A on #3A2E08  9.26:1   on panel #181d25  11.74:1
     dark  cyan   #5FDCEC on #07323A  8.47:1   on panel         10.42:1
     light amber  #6E4A00 on #FFF1CC  7.08:1   on white          7.95:1
     light teal   #0A5560 on #D8F3F8  7.29:1   on white          8.46:1 */
/* ⛔ TOKENS, NOT HEX. These were four literals in two theme blocks; the same
   colours now live in :root once each and the dark override comes free. */
/* ⛔ TEXT ONLY, NO FILL. Solid fill now means "this is a SHIFT". An account
   type is a property of a MODEL and must never look like one. Do not put the
   background back -- amber-filled would be indistinguishable from the yellow
   MORNING pill at a glance. */
.m-tag.sui { background: none; color: var(--game-sui); }
.m-tag.int { background: none; color: var(--game-int); }

/* ---------- 024c: Johnson's steps ---------- */
.method-strip .steps { counter-reset: none; }
.method-strip .steps li {
  flex: 1 1 210px; min-width: 190px;
  font-size: 12px; line-height: 1.45; color: var(--text);
}
/* (the 024c tips styling is superseded by the 024e block below) */

/* ---------- 024e: the method, written properly ---------- */
.method-strip .steps {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 10px 20px;
}
.method-strip .steps li { display: block; min-width: 0; }
.method-strip .steps li b {
  display: block; margin-bottom: 2px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .02em;
  color: var(--text); text-transform: none;
}
.method-strip .steps li .desc {
  display: block; font-size: 11.5px; line-height: 1.45; color: var(--text-soft);
}
/* the toggle hides the EXPLANATION, never the instruction */
body.method-collapsed .method-strip .steps li .desc { display: none; }

/* ⭐ THE TIPS ARE PROMINENT, NOT BURIED. They were small, grey and folded away;
   Johnson called that unprofessional and he was right -- these are the two
   judgement calls he makes most often. Own block, accent rail, full-size text,
   and they NEVER collapse. */
.method-tips {
  margin-top: 11px; padding: 9px 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  background: var(--surface-2);
  overflow: visible;
}
.method-tips p {
  margin: 0 0 5px; font-size: 12px; line-height: 1.5; color: var(--text);
}
.method-tips p:last-child { margin-bottom: 0; }
/* ⛔ NOT --accent. 026 reserves that blue for the DECIDING NUMBER, and "Tip 1"
   in the same blue as REV/SHIFT invites the reader to think a tip carries the
   weight of the metric. Full-strength text keeps the prominence Johnson asked
   for without borrowing a meaning.
   ⚠ The 3px left rail stays accent: it is structural emphasis on a block, not
   a colour applied to a value, and nothing about it reads as a number. */
.method-tips b {
  color: var(--text); font-weight: 800; letter-spacing: .02em;
  margin-right: 4px;
}
.method-tips span { color: var(--text-soft); }

/* ================= 024f: MOBILE =================
   Johnson allocates from his phone, minutes before a shift opens. Mobile is a
   primary target here, not a fallback. */

@media (max-width: 620px) {

  /* ---- the whole method block folds away, tips included ----
     ⛔ On a phone `method-collapsed` hides the STEPS AND THE TIPS TOGETHER --
     they are reference, and the table is the job. On desktop the same class
     hides only the descriptions. The tips are never CLIPPED either way: they
     are either fully shown or fully put away. */
  body.method-collapsed .method-strip .steps,
  body.method-collapsed .method-strip .method-tips,
  body.method-collapsed .method-strip .method-rules { display: none; }
  body.method-collapsed .method-strip { padding: 6px 10px; }
  .method-strip .steps { grid-template-columns: minmax(0, 1fr); gap: 12px; }

  /* ---- 44px touch targets ---- */
  .method-toggle, .rail-toggle, .mode-btn, #mode-model, #mode-chatter {
    min-height: 44px; padding: 10px 14px; font-size: 13px;
  }
  .field select { min-height: 44px; }
  .checkbox-field { min-height: 44px; display: flex; align-items: center; gap: 8px; }
  .checkbox-field input { width: 20px; height: 20px; }
  .model-button { min-height: 48px; }

  /* ---- ⭐ A CARD PER CHATTER, NOT A SCROLLING TABLE ----
     Eight columns cannot fit in 375px. A pinned first column would keep the
     name but leave REV/SHIFT and FANS/SHIFT a horizontal drag apart, and
     reading a revenue figure without the traffic beside it is the exact
     mistake this board exists to prevent -- it is how Andy read $18 a fan.
     As cards they sit side by side, ZERO swipes apart, and nothing scrolls. */
  .table-scroll { overflow: visible; }
  /* ⛔ min-width: 940px is what makes the DESKTOP table scroll sideways. As
     cards there are no columns to keep apart, so it must be released or every
     card renders 940px wide inside a 375px screen -- which is exactly what it
     did before this line existed. */
  .ranking-table { min-width: 0; width: 100%; }
  .ranking-table thead { display: none; }
  .ranking-table, .ranking-table tbody, .ranking-table tr, .ranking-table td {
    display: block; width: auto;
  }
  .ranking-table tr[data-key] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px 10px;
    margin: 0 0 10px; padding: 10px 12px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 10px;
  }
  /* name across the top, then revenue and traffic SIDE BY SIDE */
  .ranking-table td.rank-number { grid-column: 1 / -1; padding: 0; font-size: 11px; }
  .ranking-table td.chatter-cell { grid-column: 1 / -1; padding: 0 0 6px; }
  .ranking-table td.col-rev   { grid-column: 1; }
  .ranking-table td.col-fans  { grid-column: 2; }
  .ranking-table td.col-rev strong, .ranking-table td.col-fans strong {
    font-size: 19px; line-height: 1.15;
  }
  /* the rest, smaller, beneath */
  .ranking-table td.shift-cell, .ranking-table td.col-shifts,
  .ranking-table td.col-perfan, .ranking-table td.col-evidence {
    grid-column: auto; padding: 6px 0 0; border-top: 1px solid var(--border);
    margin-top: 6px; font-size: 12px;
  }
  .ranking-table td[data-label]::before {
    content: attr(data-label);
    display: block; font-size: 9.5px; letter-spacing: .06em;
    text-transform: uppercase; color: var(--text-faint); margin-bottom: 1px;
  }
  .ranking-table td.col-rev::before, .ranking-table td.col-fans::before {
    font-size: 10px; color: var(--text-soft);
  }
  /* ⛔ THE UNPROVEN BADGE SURVIVES. It is the guard against exactly the error
     above, so it must never be the thing dropped for space. */
  /* ⛔ THE BADGE IS WHY THE CARD OVERFLOWED. `.dbm-tag` carries
     white-space: nowrap, so its min-content width forced the 1fr column wider
     than the screen and dragged the full-width cells to 434px in a 375px
     viewport. Grid tracks do not shrink below min-content unless you say so --
     hence min-width: 0 on every cell, and the badge is allowed to wrap here. */
  .ranking-table tr[data-key] > td { min-width: 0; overflow-wrap: anywhere; }
  .ranking-table td.col-fans .dbm-tag { white-space: normal; }
  .ranking-table td.col-fans .load-flag { display: inline-block; margin-top: 4px; }
  .ranking-table td.col-fans .sub { display: block; font-size: 10.5px; }
  .ranking-table .empty-row td { grid-column: 1 / -1; }
}

/* ================= 024g: THE FORMULA, WRITTEN OUT =================
   Johnson: "Make the explanation clear like this, color if need." The previous
   version was one compressed line of shorthand; this is a heading, then one
   labelled line per measure with its meaning beneath it.

   THE COLOUR IS THE KEY, NOT DECORATION. Every colour here is the same token
   the table uses, so the eye can carry a colour from this block straight to a
   cell. Weight follows importance on purpose: REVENUE/SHIFT is the loudest
   because it decides, $ PER FAN is the quietest because it does not. */

/* THE TOGGLE IS PINNED TOP-RIGHT AND THE BLOCK RESERVES ITS WIDTH.
   It was floated first. A float only avoids what happens to flow beside it, and
   at 1440px it landed on top of the Evidence heading -- measured overlap=true.
   Reserved space cannot collide: the grid simply never extends under it. */
.method-rules { position: relative; }
.formula-toggle {
  position: absolute; top: 8px; right: 0; z-index: 1;
  margin: 0; padding: 3px 9px; font-size: 10.5px; cursor: pointer;
  background: transparent; color: var(--text-faint);
  border: 1px solid var(--border); border-radius: 5px;
}
body.formula-collapsed .formula-body { display: none; }

.formula-body {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 8px 22px;
  padding-right: 96px;      /* the strip the pinned toggle occupies */
}
.formula-block h4 {
  margin: 0 0 5px; font-size: 10px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-faint);
}
.formula-block .fm { margin: 0 0 5px; font-size: 11.5px; line-height: 1.45; }
.formula-block .fm:last-child { margin-bottom: 0; }
.formula-block .fm b { font-weight: 800; letter-spacing: .02em; }
.formula-block .fm em { font-style: normal; color: var(--text); }
.formula-block .fm span {
  display: block; color: var(--text-soft); font-size: 11px; line-height: 1.4;
}

/* ---- the three measures ---- */
/* the decider: the same accent the highlighted REV/SHIFT column carries */
.fm-rev b {
  color: var(--accent); background: var(--accent-soft);
  padding: 1px 6px; border-radius: 4px;
}
.fm-rev em { font-weight: 700; }
/* the fairness check: neutral, but full-strength. NOT a footnote. */
.fm-fans b { color: var(--text); }
/* THE REFERENCE READ IS DELIBERATELY QUIETER. Its lower visual weight IS the
   message. Johnson: "$ per fan only as a reference of efficiency reader, but not
   the main decider." Andy read $18.3750 a fan on 2 landed fans. */
/* ⛔ THE ASSIGNMENT SAYS --na FOR THIS LABEL, so it uses that token and not a
   look-alike grey. Its low weight IS the message: reference, not decider. */
.fm-perfan b { color: var(--na-text); font-weight: 700; }
.fm-perfan em, .fm-perfan span { color: var(--na-text); }

/* ---- the three bands, in their own badge colours ---- */
.fm-ev b { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11px; }
.fm-ev.ev-weak b { color: var(--ev-weak); }
.fm-ev.ev-mid b { color: var(--ev-mid); }
.fm-ev.ev-strong b { color: var(--ev-strong); }
.fm-ev em { color: var(--text-soft); }

/* ---- WIDE SCREENS: THE THREE MEASURES SIT ACROSS, NOT DOWN ----
   Stacked, this block ran 135px tall and pushed the first ranking row off a
   900px laptop screen -- measured 866px, viewport 900. The brief is explicit
   that it must not do that. Across, it is 3 lines instead of 9 and the table
   clears the fold. Each measure still gets its own labelled line with the
   explanation beneath it, which is the structure Johnson asked for. */
@media (min-width: 1100px) {
  .formula-block { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px 18px; }
  .formula-block h4 { grid-column: 1 / -1; }
  .formula-block .fm { margin-bottom: 0; }
}

/* ---- tight screens: the whole block folds, AFTER the tips, never a step ----
   THE TOGGLE IS AVAILABLE AT EVERY WIDTH. It is the escape hatch the brief
   asks for, and a control that only appears on some screens is one Johnson
   cannot rely on finding. */
.formula-toggle { display: inline-block; }
@media (max-width: 620px) {
  /* No reserved strip on a phone: there is no spare 96px on a 375px screen, and
     sharing the line with the toggle rendered the formula 241px wide -- a third
     of the display lost to a button. The toggle goes back into the flow above
     the block instead, full width, which also gives it a 44px touch target. */
  .formula-body { grid-template-columns: minmax(0, 1fr); gap: 10px; padding-right: 0; }
  .formula-toggle {
    position: static; display: block; width: 100%; margin: 0 0 8px;
    min-height: 44px; padding: 10px 14px; font-size: 13px;
  }
}

/* ================= 026: THE ASSIGNMENTS, APPLIED =================
   ⭐ NOTHING RELIES ON COLOUR ALONE. Every coloured state also carries its own
   words -- SUICIDE, INTENT, BEST HANDLER, UNPROVEN AT THIS LOAD -- so a
   colour-blind reader, or a printed page, loses nothing at all. */

/* ---- BEST HANDLER (task 025). Green, and green is used for nothing else. ---- */
.best-handler {
  display: inline-block; margin-top: 4px;
  padding: 1px 6px; border-radius: 4px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .05em;
  color: var(--best); background: var(--best-soft);
  border: 1px solid var(--best);
}

/* ---- the two load CAUTIONS ----
   ⛔ AN OUTLINE, NOT A FILL, AND NEVER AMBER. These caution about how to READ a
   number; they are not a property of the account. HEAVIER LOAD deliberately
   keeps the neutral --na chip: it is favourable, not a warning. */
.dbm-tag.is-caution {
  color: var(--caution); background: var(--caution-soft);
  border: 1px solid var(--caution);
}

/* ---- the rank-on-this-model cell (task 025) ---- */
.rank-number.rank-on-model {
  width: auto; min-width: 106px; text-align: left; white-space: normal;
  font-family: var(--sans); font-size: 12px; font-variant-numeric: normal;
}
.rank-number.rank-on-model strong { display: block; font-weight: 750; color: var(--text); }
.rank-number.rank-on-model.leader strong { color: var(--best); font-weight: 800; }
.rank-number.rank-on-model.solo strong { color: var(--text-soft); font-weight: 650; }
.rank-number.rank-on-model.none strong { color: var(--na-text); font-weight: 550; }
.rank-number.rank-on-model .sub {
  display: block; font-size: 10px; color: var(--text-faint); margin-top: 1px;
}
body.by-chatter .col-rank { min-width: 106px; }

@media (max-width: 620px) {
  .ranking-table td.rank-number.rank-on-model {
    grid-column: 1 / -1; padding: 0 0 4px; min-width: 0;
  }
  .ranking-table td.rank-number.rank-on-model strong { font-size: 13px; }
}

/* ================= 028: THE SHIFT TAG =================
   A SOLID FILLED PILL, always carrying its own word, so nothing depends on the
   colour alone. It marks a PERSON's shift; account-type tags mark a MODEL and
   are text-only. Those two never look alike and never share a slot. */
.shift-tag {
  display: inline-block; vertical-align: 2px;
  padding: 2px 7px; border-radius: 999px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; white-space: nowrap;
}
.shift-tag.sh-morning  { background: var(--shift-morning-bg);  color: var(--shift-morning-fg); }
.shift-tag.sh-evening  { background: var(--shift-evening-bg);  color: var(--shift-evening-fg); }
.shift-tag.sh-midnight { background: var(--shift-midnight-bg); color: var(--shift-midnight-fg); }
/* beside the big chatter name in the header */
.shift-tag.big { font-size: 11px; padding: 3px 10px; vertical-align: 5px; }

.model-head-id h2 .shift-tag { letter-spacing: .08em; }
.summary-value .shift-tag { vertical-align: 3px; }


/* ================= 031: THE DRAWER =================
   The drawer is about a PAIRING, so the header names both halves at the same
   weight. "on" is the only quiet word in it. */
#drawer-title .pair-on {
  font-weight: 500; color: var(--text-soft); font-size: .72em;
  padding: 0 2px; letter-spacing: .04em;
}
.d-grid.three { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

/* the audit trail, one click away at the bottom */
.tech-block { border-top: 1px solid var(--border); padding-top: 10px; }
.tech-toggle {
  min-height: 32px; padding: 5px 11px; font-size: 11px; cursor: pointer;
  background: transparent; color: var(--text-faint);
  border: 1px solid var(--border); border-radius: 5px;
}
.tech-toggle:hover { color: var(--text); }
.tech-body { margin-top: 9px; }

/* ---- the candidate lines ----
   ⭐ SAME VISUAL HIERARCHY AS THE FORMULA BLOCK, same tokens: revenue per shift
   decides and is loudest, fans per shift is the fairness check, $ per fan is a
   reference read and is deliberately the quietest thing on the line. */
.cmp td.n { text-align: right; }
.cmp .cmp-rev {
  display: block; font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 750;
  color: var(--text);
}
.cmp tr.me .cmp-rev { color: var(--accent); }
.cmp .cmp-fans {
  display: block; font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11px; color: var(--text-soft);
}
.cmp .cmp-perfan {
  display: block; font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 10px; color: var(--na-text);
}
.cmp .who .ev-strong { color: var(--ev-strong); font-weight: 700; }
.cmp .who .ev-mid    { color: var(--ev-mid); font-weight: 700; }
.cmp .who .ev-weak   { color: var(--ev-weak); font-weight: 700; }
.cmp .who .load-flag { margin-top: 4px; }
.cmp .who .sub { display: block; font-size: 10px; color: var(--text-faint); }

@media (max-width: 620px) {
  .cmp td.n { white-space: normal; }
}

/* ================= 033: ONE FOOTER KEY =================
   Replaces a colour-legend block, an N/A paragraph and the old inline legend.
   ⭐ The swatches carry the SAME tokens as the cells they explain (026), so the
   key looks like the thing it is describing and cannot drift from it. */
/* ⛔ ONE STATE PER LINE. A wrapped run-on line was the whole complaint. */
.state-legend .key-body { display: block; }
.state-legend .sl-item {
  display: flex; align-items: baseline; gap: 10px; padding: 2px 0;
}
/* fixed-width symbol column so the descriptions line up down the page */
.state-legend .sl-sym {
  flex: 0 0 132px; display: flex; align-items: baseline; gap: 5px;
}
.state-legend .sl-desc { flex: 1 1 auto; color: var(--text-soft); }
.state-legend .k-num  { font-family: var(--num); font-variant-numeric: tabular-nums; color: var(--text); font-weight: 700; }
.state-legend .k-zero { font-family: var(--num); font-variant-numeric: tabular-nums; color: var(--zero); font-weight: 700; }
.state-legend .k-na   { font-family: var(--num); font-variant-numeric: tabular-nums; color: var(--na-text); font-weight: 600; }
.state-legend .key-note {
  flex: 1 1 100%; margin: 5px 0 0; font-size: 11px; line-height: 1.5;
  color: var(--text-soft);
}
/* desktop: always open, no toggle */
.state-legend .key-toggle { display: none; }

@media (max-width: 620px) {
  /* per 024f: on a phone this folds away behind its own button */
  .state-legend .key-toggle {
    display: block; width: 100%; min-height: 44px; margin-bottom: 8px;
    padding: 10px 14px; font-size: 13px; cursor: pointer;
    background: transparent; color: var(--text-faint);
    border: 1px solid var(--border); border-radius: 5px;
  }
  .state-legend .key-body { display: none; }
  .state-legend.key-open .key-body { display: flex; flex-direction: column; gap: 7px; }
}

/* ================= 034: THE WINDOW CARD =================
   Dates lead, because that is what a reader checks first. */
.w-block .w-perfan {
  font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 11px; color: var(--na-text);
  margin-left: 8px;
}
.w-block .w-perfan.true-zero { color: var(--zero); }
.w-row.dates-row { align-items: baseline; }
.w-row.dates-row .dates-big {
  display: block; font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700;
  color: var(--text); line-height: 1.45;
}
.w-row .v .sub { color: var(--text-faint); font-size: 10.5px; margin-left: 5px; }
.w-row .v .na { color: var(--na-text); }

/* ---- 033a: the data-age line is a health indicator, not a footnote ---- */
#loaded-time.stale {
  color: var(--danger); font-weight: 700;
}
@media (max-width: 620px) {
  /* the symbol column collapses; the description sits beneath its symbol */
  .state-legend .sl-item { flex-direction: column; gap: 1px; }
  .state-legend .sl-sym { flex: 0 0 auto; }
}

/* ---- 034a: the ratio sits quietly beside its raw count ----
   The count is the fact; the ratio is the read. Neither stands alone. */
.w-row .v .ratio { color: var(--text-soft); font-size: 11px; }

/* ---- 033b: the key names the column, not a sample value ---- */
.state-legend .k-col {
  font-family: var(--sans); font-size: 10.5px; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-faint);
}
.state-legend .sl-more { display: block; color: var(--text-faint); font-size: 11px; }

/* ================= 041: THE HOUSE STYLE =================
   Matching the admin app SCAR is now embedded in. Three changes carry almost
   all of it: sans-serif type, softer and better-padded cards, and whitespace.

   ⚠ WRITTEN FROM A DESCRIPTION, NOT FROM THE SCREENSHOTS -- I could not see
   them. The radius, padding and label/value pattern below follow what was
   described; the exact hues are the palette this board already had, because
   026 assigns each of those a MEANING and guessing at new ones would break
   that. If a house colour collides with an assigned meaning, that is a
   decision to take deliberately, not to infer. */

:root { --radius: 12px; }

/* ---- generous internal padding, the single biggest visual difference ---- */
.summary-card { padding: 18px 20px; border-radius: var(--radius); }
.ranking-panel, .model-rail, .drawer-panel, .method-strip, .cmp, .howto {
  border-radius: var(--radius);
}
.summary-grid { gap: 16px; margin-bottom: 20px; }
.panel-toolbar { padding: 16px 20px; }
.panel-footer { padding: 16px 20px; }

/* ---- the table breathes ---- */
.ranking-table th { padding: 12px 14px; }
.ranking-table td { padding: 14px; }
.ranking-table thead th { font-size: 10px; letter-spacing: .07em; }

/* ---- ⭐ THEIR NUMBER PATTERN: a small muted uppercase label above a large
   value that carries the colour. The summary figures used to read like table
   text; they are the headline of the page and should look like it. ---- */
.summary-label {
  display: block; font-size: 10px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-faint); margin-bottom: 8px;
}
.summary-value {
  display: block; font-size: 30px; line-height: 1.1; font-weight: 750;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
  color: var(--text);
}
.summary-value.muted { font-size: 22px; }
.summary-context { margin-top: 9px; font-size: 12px; line-height: 1.5; }

/* ---- the header chip now carries data freshness, not a false address ---- */
.runtime.stale { color: var(--danger); font-weight: 700; }
.runtime.stale .dot { background: var(--danger); }

/* ================= 041: HOW TO ALLOCATE =================
   One control, closed by default, at the very end of the page. It is no longer
   competing for space, so everything inside it gets room. */
.howto {
  margin-top: 22px; background: var(--surface);
  border: 1px solid var(--border); box-shadow: var(--shadow);
}
.howto > summary {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 20px; cursor: pointer; list-style: none;
  font-size: 13px; font-weight: 700; letter-spacing: .01em; color: var(--text);
}
.howto > summary::-webkit-details-marker { display: none; }
.howto > summary::after {
  content: ""; margin-left: auto;
  width: 8px; height: 8px; border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint); transform: rotate(45deg);
  transition: transform .15s ease;
}
.howto[open] > summary::after { transform: rotate(-135deg); }
.howto > summary:hover { background: var(--surface-2); }
.howto > summary svg { width: 16px; height: 16px; flex: 0 0 16px; color: var(--accent); }
.howto-body { padding: 4px 20px 22px; border-top: 1px solid var(--border); }

/* inside, it is a document rather than a strip -- give it the room */
.howto .method-strip {
  background: none; border: 0; box-shadow: none; padding: 18px 0 0; margin: 0;
}
.howto .steps { gap: 16px 26px; }
.howto .method-tips { margin-top: 18px; padding: 14px 16px; }
.howto .method-rules { margin-top: 18px; padding-top: 16px; }
.howto .formula-body { padding-right: 0; }

@media (max-width: 620px) {
  .summary-card { padding: 15px 16px; }
  .summary-value { font-size: 25px; }
  .howto > summary { min-height: 44px; }
  .howto-body { padding: 4px 15px 18px; }
}
