/* The Path — client portal.
 *
 * Self-contained: no CDN, no webfonts, no build step. Dense and data-first for
 * an institutional audience. Tier and signal colours are always paired with a
 * text label, so nothing depends on colour alone.
 */

:root {
  --ink: #14181f;
  --ink-2: #4a5464;
  --ink-3: #6d7786;
  --line: #e2e6ec;
  --line-2: #eef1f5;
  --bg: #f6f7f9;
  --card: #ffffff;
  --navy: #10233c;
  --navy-2: #1c3557;
  --accent: #1f5fbf;

  /* State colours, tuned to one perceived weight so that "Active" and
     "1 to resolve" sit at the same level in the eye and neither outshouts the
     row it describes. Text is dark enough to read on its own tint; the tint is
     light enough to stay behind the content. */
  --pos: #16704a;
  --pos-bg: #e8f3ed;
  --pos-line: #c6e2d2;
  --neg: #a52d24;
  --neg-bg: #fbeceb;
  --neg-line: #f0cdca;
  --warn: #825312;
  --warn-bg: #fbf1de;
  --warn-line: #eddcb8;
  /* The same caution, filled rather than written. --warn is tuned to be read
     as dark text on --warn-bg; painted into a solid shape it loses the tint
     behind it and reads as brown. Anything that carries the state as colour
     alone -- a bar, a dot -- uses this instead, and it holds up on the navy
     tab as well as on white. */
  --warn-mark: #c98a12;
  --flat: #5a6675;
  --flat-bg: #eff1f5;
  --flat-line: #dee3ea;

  --field: #cfd6e0;          /* control border, one shade darker than --line */
  --field-focus: #1f5fbf;
  --radius: 8px;
  --pad: 20px;
  /* The horizontal inset inside a table card. The caption and the
     cells both use it, which is the only way their left edges agree. */
  --cell-x: 16px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.5 var(--sans);
  color: var(--ink);
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
}

.wrap { width: 100%; max-width: 1280px; margin: 0 auto; padding: 0 20px; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Visible only to assistive tech / keyboard users. */
.sr, .skip {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip:focus {
  position: fixed; top: 8px; left: 8px; z-index: 20;
  width: auto; height: auto; clip: auto; margin: 0;
  padding: 10px 14px; background: var(--navy); color: #fff; border-radius: 6px;
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- top bar ------------------------------------------------------------ */
.topbar { background: var(--navy); color: #fff; }
.topbar-inner {
  display: flex; align-items: center; gap: 28px;
  min-height: 60px; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 10px; color: #fff; }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 10px; height: 22px; border-radius: 2px;
  background: linear-gradient(180deg, #4d9bff, #0f7a4e);
}
.brand-text { font-weight: 650; letter-spacing: .2px; line-height: 1.1; }
.brand-sub {
  display: block; font-size: 10.5px; font-weight: 500;
  letter-spacing: .09em; text-transform: uppercase; color: #8ea3bd;
}

.nav { display: flex; gap: 4px; margin-right: auto; flex-wrap: wrap; }
.nav a {
  color: #c8d5e6; padding: 7px 12px; border-radius: 6px;
  font-size: 14px; font-weight: 500;
}
.nav a:hover { background: var(--navy-2); color: #fff; text-decoration: none; }
.nav a[aria-current="page"] { background: var(--navy-2); color: #fff; }

.signout { display: flex; align-items: center; gap: 12px; }
.who { font-size: 13px; color: #8ea3bd; }
.signout button {
  background: transparent; color: #c8d5e6; cursor: pointer;
  border: 1px solid #2d4468;
  padding: 6px 12px; border-radius: 6px; font: inherit; font-size: 13px;
}
.signout button:hover { background: var(--navy-2); color: #fff; }

/* --- page furniture ---------------------------------------------------- */
main { padding-bottom: 48px; }

.pagehead {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; margin: 28px 0 18px;
}
h1 { font-size: 23px; margin: 0 0 4px; letter-spacing: -.2px; }
h1 .co { font-weight: 400; color: var(--ink-2); font-size: 19px; }
h2 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); margin: 0 0 12px;
}
h2 .muted { text-transform: none; letter-spacing: 0; }
h3 { font-size: 14px; margin: 18px 0 6px; }
.muted { color: var(--ink-3); }
.crumbs { margin: 20px 0 0; font-size: 13px; }

.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: var(--pad); margin-bottom: 18px;
}
.tablecard { padding: 0; }
.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 900px) { .cols { grid-template-columns: 1fr; } }

/* --- stat tiles -------------------------------------------------------- */
.tiles {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 12px; margin-bottom: 18px;
}
@media (max-width: 800px) { .tiles { grid-template-columns: repeat(2, 1fr); } }
.tile {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px;
  display: flex; flex-direction: column; gap: 6px;
}
.tile-k {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3);
}
.tile-k em { font-style: normal; text-transform: none; letter-spacing: 0; }
.tile-v { font-size: 26px; font-weight: 600; letter-spacing: -.5px; }
.tile-v.small { font-size: 15px; font-weight: 550; letter-spacing: 0; }

/* --- tables ------------------------------------------------------------ */
.scroll { overflow-x: auto; }
table.grid { width: 100%; border-collapse: collapse; font-size: 14px; }
.grid th, .grid td {
  text-align: left; padding: 9px var(--cell-x);
  border-bottom: 1px solid var(--line-2);
}
.grid thead th {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); font-weight: 600; white-space: nowrap;
  border-bottom: 1px solid var(--line);
}
.tablecard .grid thead th { background: #fbfcfd; position: sticky; top: 0; z-index: 1; }
.grid tbody tr:hover { background: #fafbfc; }
.grid tbody tr:last-child td { border-bottom: 0; }
.grid .r, .grid th.r { text-align: right; }
.num { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 13px; }
.strong { font-weight: 650; }
.pos { color: var(--pos); }
.neg { color: var(--neg); }
.nowrap { white-space: nowrap; }
.trunc { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tick { font-family: var(--mono); font-weight: 600; font-size: 13px; }
.empty { padding: 32px; text-align: center; color: var(--ink-3); }
.rank tbody td { padding-top: 8px; padding-bottom: 8px; }

.grid.kv th[scope="row"] { color: var(--ink-2); font-weight: 500; width: 40%; }
.comp tfoot th, .comp tfoot td {
  border-top: 1px solid var(--line); border-bottom: 0;
  font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3);
}
.comp tfoot td { font-size: 14px; color: var(--ink); }

th.sortable a {
  color: inherit; display: inline-flex; align-items: center; gap: 4px;
}
th.sortable a:hover { color: var(--accent); text-decoration: none; }
.caret { font-size: 8px; color: var(--accent); }

/* --- pills / signals --------------------------------------------------- */
.pill, .sig {
  display: inline-block; padding: 2px 9px; border-radius: 100px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  /* Neutral by default. Without this a pill carrying no state variant fell
     back to body text at weight 600 — so "Awaiting spec", the least
     interesting thing on a row, was set in bold near-black and read as the
     most. A label with no state still has to look like a label. */
  background: var(--flat-bg); color: var(--flat);
  border: 1px solid var(--flat-line);
}
/* The ADS tier scale, where "negative" is amber and "strongly negative" is red:
   an Elevated Risk name is a caution and a Disruption Target is a refusal. */
.t-strong-pos { background: var(--pos-bg); color: #0d5c3b; border-color: var(--pos-line); }
.t-pos        { background: var(--pos-bg); color: var(--pos); border-color: var(--pos-line); }
.t-neutral    { background: var(--flat-bg); color: var(--flat); border-color: var(--flat-line); }
.t-neg        { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-line); }
.t-strong-neg { background: var(--neg-bg); color: var(--neg); border-color: var(--neg-line); }
.pill.t-warn  { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-line); }

.sig { font-weight: 550; }
.s-aligned   { background: var(--pos-bg); color: var(--pos); border-color: #d3ecdd; }
.s-divergent { background: var(--warn-bg); color: var(--warn); border-color: #f0dcb4; }
.s-neutral   { background: var(--flat-bg); color: var(--flat); border-color: #dfe4ea; }

/* --- bars -------------------------------------------------------------- */
.barcell { width: 190px; }
.bar {
  display: inline-block; height: 7px; border-radius: 4px;
  background: var(--flat); vertical-align: middle; min-width: 2px;
}
.bar.t-strong-pos, .bar.t-pos { background: var(--pos); }
.bar.t-neg { background: var(--warn-mark); }
.bar.t-strong-neg { background: var(--neg); }
.barnum { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); margin-left: 8px; }

.mini {
  display: inline-block; width: 46px; height: 5px; margin-left: 8px;
  background: var(--line); border-radius: 3px; vertical-align: middle;
  overflow: hidden;
}
.mini-fill { display: block; height: 100%; background: var(--accent); }

/* --- filters ----------------------------------------------------------- */
.filters {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr auto;
  gap: 12px; align-items: end;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px; margin-bottom: 18px;
}
@media (max-width: 1000px) { .filters { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .filters { grid-template-columns: 1fr; } }
.f-actions { flex-direction: row; gap: 8px; }

/* --- buttons ----------------------------------------------------------- */
.btn, button.primary, .f-actions button {
  display: inline-block; padding: 8px 15px; border-radius: 6px;
  font: inherit; font-size: 14px; font-weight: 550; cursor: pointer;
  border: 1px solid var(--navy); background: var(--navy); color: #fff;
  white-space: nowrap;
}
.btn:hover, button.primary:hover { background: var(--navy-2); text-decoration: none; }
.btn.ghost {
  background: #fff; color: var(--ink-2); border-color: var(--field);
}
.btn.ghost:hover { background: #f4f6f9; color: var(--ink); }
.btn.disabled { opacity: .45; pointer-events: none; }

/* --- pager ------------------------------------------------------------- */
.pager { display: flex; align-items: center; gap: 14px; justify-content: center; }
.pageof { font-size: 13px; color: var(--ink-3); }

/* --- detail ------------------------------------------------------------ */
.headline { display: flex; align-items: center; gap: 12px; }
.headline-k {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3);
}
.headline-v { font-size: 30px; font-weight: 650; letter-spacing: -.6px; }
.formula { font-size: 15px; margin: 0 0 10px; }
.formula strong { font-family: var(--mono); font-size: 14px; }
.note { font-size: 13px; color: var(--ink-3); margin: 8px 0 0; }
/* Text somebody typed into a field: their paragraph breaks are theirs, so
   pre-line keeps them. Copy written in a template is NOT this — pre-line
   renders the template's own line breaks and the blank lines around its tags,
   which is how a paragraph ends up wrapping mid-sentence under a heading it
   has been pushed three lines away from. Template copy uses .explain. */
.prose { margin: 0; color: var(--ink-2); max-width: 78ch; white-space: pre-line; }
.explain { margin: 0 0 10px; color: var(--ink-2); max-width: 78ch; }
.explain:last-child { margin-bottom: 0; }

/* --- auth -------------------------------------------------------------- */
.auth {
  max-width: 380px; margin: 64px auto; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 28px;
}
.auth h1 { margin-bottom: 2px; }
.auth button { width: 100%; margin-top: 20px; padding: 10px; }
.alert {
  background: var(--neg-bg); color: var(--neg); border: 1px solid #f3cdca;
  border-radius: 6px; padding: 10px 12px; font-size: 13.5px; margin: 16px 0 0;
}

/* --- footer ------------------------------------------------------------ */
.foot {
  border-top: 1px solid var(--line); padding-top: 16px; padding-bottom: 28px;
  font-size: 12px; color: var(--ink-3);
}
.foot p { margin: 0; }
.conf { font-weight: 600; color: var(--ink-2); }

/* --- print: interim stand-in for the PDF export ------------------------ */
@media print {
  .topbar, .filters, .pager, .btn, .crumbs, .skip { display: none !important; }
  body { background: #fff; font-size: 11pt; }
  .card, .tile { border-color: #ccc; break-inside: avoid; }
  .wrap { max-width: none; padding: 0; }
  a { color: #000; }
  .tablecard .grid thead th { position: static; }
}

/* --- universes: picker cards ------------------------------------------- */
.ucards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 14px;
}
.ucard {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px; display: flex; flex-direction: column; gap: 7px;
  color: var(--ink); min-height: 128px;
}
.ucard:hover { text-decoration: none; border-color: var(--accent); }
.ucard-kind {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3);
}
.ucard-name { font-size: 17px; font-weight: 650; letter-spacing: -.2px; line-height: 1.25; }
.ucard-meta { font-size: 13px; color: var(--ink-3); margin-top: auto; }
.ucard .pill { align-self: flex-start; }
.ucard-new { border-style: dashed; }
.ucard-new summary {
  cursor: pointer; font-weight: 600; color: var(--ink-2); list-style: none;
  display: flex; align-items: center; gap: 8px;
}
.ucard-new summary::-webkit-details-marker { display: none; }
.ucard-new[open] { min-height: 0; }
.plus {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 6px; background: var(--flat-bg);
  font-size: 15px; line-height: 1;
}
.ucard-new button { width: 100%; margin-top: 14px; }

.regime-expansion   { background: var(--pos-bg); color: var(--pos); border-color: #d3ecdd; }
.regime-slowdown    { background: var(--warn-bg); color: var(--warn); border-color: #f0dcb4; }
.regime-contraction { background: var(--neg-bg); color: var(--neg); border-color: #f3cdca; }
.regime-recovery    { background: #e8f0fd; color: #1b4b96; border-color: #cfe0f8; }

/* --- regime bar -------------------------------------------------------- */
.regimebar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 16px; margin-bottom: 14px;
}
.rb-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-weight: 600;
}
.regimebar select {
  font: inherit; font-size: 14px; padding: 6px 10px;
  border: 1px solid var(--field); border-radius: 6px; background: #fff;
}
.rb-source { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
.rb-weights { margin-left: auto; font-size: 12.5px; }
.headactions { display: flex; gap: 8px; }

/* --- stage tabs -------------------------------------------------------- */
.tabs {
  display: flex; flex-wrap: wrap; gap: 2px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 4px; margin-bottom: 14px;
}
.tabs a, .tabs label {
  padding: 8px 18px; border-radius: 6px; font-size: 14px; font-weight: 550;
  color: var(--ink-2);
}
.tabs a:hover, .tabs label:hover { background: #f4f6f9; text-decoration: none; }
.tabs a.on { background: var(--navy); color: #fff; }
/* Labels rather than links where the tabs switch panels of one form. A link
   would be a new request, and a new request discards whatever has been typed
   into the panel being left. */
.tabs label {
  display: inline-flex; align-items: center; gap: 2px;
  cursor: pointer; -webkit-user-select: none; user-select: none;
}

.stagebox {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px 20px;
}
.stagenote {
  border-left: 3px solid var(--warn); background: var(--warn-bg);
  padding: 12px 15px; border-radius: 0 6px 6px 0; margin-bottom: 18px;
  font-size: 13.5px; color: #6b4700;
}
.stagenote strong { display: block; margin-bottom: 4px; color: #4d3300; }
.stagenote p { margin: 0; }
.stagemeta {
  display: flex; gap: 20px; flex-wrap: wrap; font-size: 13px;
  color: var(--ink-3); margin-bottom: 12px;
}
/* Caveats about the numbers, not a headline. Constrained measure, quieter than
   the table, but with a rule so it cannot be mistaken for decoration. */
.stagecaveat {
  max-width: 92ch; margin: 0 0 14px; padding: 9px 0 9px 12px;
  border-left: 3px solid var(--warn); background: transparent;
  font-size: 13px; line-height: 1.5; color: var(--ink-2);
}
.stagecaveat strong { color: var(--ink); }
/* A caption block above a table. .tablecard has no padding of its own — the
   table runs edge to edge — so the caption has to supply its own, and it has
   to be the cells' inset or the card shows two different left edges. */
.tablecap { padding: 0 0 10px; }
/* Only inside a table card does the caption supply the inset: a plain .card
   already pads, and a caption padding itself again inside one indents twice. */
.tablecard .tablecap { padding: 14px var(--cell-x) 10px; }
.tablecap h2, .tablecap h3 { margin: 0; }
.tablecap .fieldhint, .tablecap p { margin: 4px 0 0; }

/* The scrolling container that used to share the caption's class and its
   max-height, which is why the caption could never be given padding. */
.tablescroll { max-height: 620px; overflow: auto; }

/* Table wrapper for the paginated stage tables. No max-height: pagination
   already bounds the row count, and a fixed-height box inside a scrolling page
   gives the reader two scrollbars and a header that slides under the text above
   it. Horizontal overflow only, for the wide numeric tables on a narrow screen. */
.tablewrap { overflow-x: auto; margin: 0 -2px; }
/* Uniform row height. Letting a two-word sector wrap made every second row
   double height, which reads as ragged rather than dense, and pushed the
   numbers into a narrow strip on the right. Nowrap plus horizontal overflow on
   the wrapper keeps one row one line and lets a wide table scroll sideways
   instead of reflowing. */
.tablewrap .grid td, .tablewrap .grid th { white-space: nowrap; }
.tablewrap .grid td.trunc { max-width: 300px; }
.tablewrap .grid th.wrap { white-space: normal; }
.tablewrap .grid tbody td { padding-top: 7px; padding-bottom: 7px; }
.tablewrap .grid thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--card);
  box-shadow: inset 0 -1px 0 var(--line);
}
.grid th.vert { font-size: 9.5px; letter-spacing: 0; }

/* Wrapping headers. Column names were truncated to fit, which made
   "Task Automation Exposure" read as "TASK AUTOMATA…" — unusable as a label.
   Wrapping costs a little height once, at the top of the table. */
.grid th.wrap {
  white-space: normal; overflow: visible; text-overflow: clip;
  /* Wide enough for two or three words a line. At 108px a descriptor called
     "Momentum 12-1, Volatility-Adjusted" broke into six lines of two
     syllables, which reads worse than the truncation it replaced. */
  min-width: 96px; max-width: 156px;
  line-height: 1.3; vertical-align: bottom; padding-bottom: 7px;
  /* Sentence case, not uppercase. These are proper names of descriptors, and
     capitals cost roughly a fifth of the width while removing the word shapes
     the reader scans by. Slightly darker than the other headers to carry the
     smaller size. */
  text-transform: none; letter-spacing: 0;
  font-size: 11px; font-weight: 600; color: var(--ink-2);
  hyphens: auto;
}
/* The weight beneath the name: subordinate, and on its own line so the name
   above it keeps the full column width. */
.grid th.wrap .thw {
  display: block; margin-top: 3px;
  font-family: var(--mono); font-weight: 400; font-size: 10px;
  letter-spacing: 0; color: var(--ink-3); text-transform: none;
}

/* Cell-view control. A segmented pair rather than a dropdown: two options, both
   worth naming in full, and the consequence for the arithmetic stated beside
   them. */
.cellview {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 10px;
  margin: 0 0 12px; font-size: 13px;
}
.cellview-label { color: var(--ink-3); }
.cellview .seg {
  padding: 5px 10px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--card); color: var(--ink-2); text-decoration: none;
}
.cellview .seg:hover { background: #f4f6f9; }
.cellview .seg.on {
  background: var(--navy); border-color: var(--navy); color: #fff; font-weight: 500;
}
.cellview .seg.on .muted { color: #a9bad3; }
.cellview .seg .muted { font-size: 11.5px; }
.cellview-note { color: var(--ink-3); }

/* --- pagination ---------------------------------------------------------- */
.pager {
  display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: baseline;
  justify-content: space-between; padding: 10px 0; font-size: 13px;
}
.pager-count { color: var(--ink-2); }
.pager-links { display: flex; gap: 4px; align-items: baseline; }
.pager-links a, .pager-links .disabled {
  padding: 5px 9px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--card); text-decoration: none;
}
.pager-links a:hover { background: #f4f6f9; }
.pager-links .disabled { color: var(--ink-3); opacity: .5; }
.pager-export {
  font-size: 12px; font-weight: 550; color: var(--accent);
  text-decoration: none; padding: 4px 10px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--card);
  margin-left: auto; margin-right: 8px;
}
.pager-export:hover { border-color: var(--accent); }
.pager-at { padding: 5px 9px; color: var(--ink-3); }

.subs { margin-top: 18px; }
/* Same disclosure marker as .fold: two triangles of different shapes on one
   page read as two different kinds of control. */
.subs > summary {
  cursor: pointer; list-style: none; font-size: 13px; color: var(--accent);
  display: flex; align-items: center; gap: 6px;
}
.subs > summary::-webkit-details-marker { display: none; }
.subs > summary::before {
  content: ""; flex: none; width: 0; height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .12s;
}
.subs[open] > summary::before { transform: rotate(90deg); }
.subgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px; margin-top: 14px;
}
.subgrid h3 { font-size: 13px; margin: 0 0 6px; }
.submetrics { list-style: none; margin: 0; padding: 0; font-size: 12.5px; }
.submetrics li {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 3px 0; border-bottom: 1px solid var(--line-2);
}
.submetrics code { font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); }

/* --- weights editor ---------------------------------------------------- */
.wcols { display: grid; grid-template-columns: 210px 1fr; gap: 18px; align-items: start; }
@media (max-width: 800px) { .wcols { grid-template-columns: 1fr; } }
.wrail {
  display: flex; flex-direction: column; gap: 2px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 6px;
  position: sticky; top: 14px;
}
.wrail a {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px;
  border-radius: 6px; color: var(--ink-2); font-size: 14px; font-weight: 550;
}
.wrail a:hover { background: #f4f6f9; text-decoration: none; }
.wrail a.on { background: var(--navy); color: #fff; }
.wrail .pill { font-size: 10px; padding: 1px 7px; }
.dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  margin-left: auto;
}
.wgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
}
.wactions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.flash {
  border-left: 3px solid var(--accent); background: #eef4fd;
  padding: 11px 15px; font-size: 13.5px; margin-bottom: 14px;
}

/* --- regime hero -------------------------------------------------------- */
.regimehero {
  display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: center;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px 24px; margin-bottom: 18px;
}
@media (max-width: 760px) { .regimehero { grid-template-columns: 1fr; } }
.rh-main { display: flex; flex-direction: column; gap: 8px; }
.rh-k {
  font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-weight: 600;
}
.rh-v {
  display: inline-block; align-self: flex-start;
  font-size: 30px; font-weight: 700; letter-spacing: -.6px;
  padding: 4px 16px; border-radius: 8px; border: 1px solid transparent;
}
.rh-tags { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.rh-meta {
  display: grid; grid-template-columns: auto auto; gap: 4px 14px;
  margin: 0; font-size: 13px; align-content: start;
}
.rh-meta dt {
  color: var(--ink-3); text-transform: uppercase; font-size: 10.5px;
  letter-spacing: .06em; font-weight: 600; align-self: center;
}
.rh-meta dd { margin: 0; color: var(--ink-2); }
.mono { font-family: var(--mono); font-size: 13px; }

/* Prompt editor: the template needs room and a monospace face. */
.card textarea[name="template"] {
  width: 100%; font-family: var(--mono); font-size: 12.5px; line-height: 1.55;
  padding: 12px 14px; border: 1px solid var(--field); border-radius: 6px;
  background: #fbfcfd; resize: vertical;
}
.card textarea[name="notes"] {
  width: 100%; font: inherit; font-size: 14px; padding: 9px 11px;
  border: 1px solid var(--field); border-radius: 6px;
}

/* Checkbox pairing for the invite access-level control. */
.check { display: flex; align-items: center; gap: 8px; cursor: pointer;
         padding: 8px 0; text-transform: none; letter-spacing: 0;
         font-size: 14px; font-weight: 500; color: var(--ink); }
.check input { width: 16px; height: 16px; margin: 0; accent-color: var(--navy); }

/* --- create-universe card + form page ----------------------------------- */
.ucard-new {
  border-style: dashed;
  align-items: center; justify-content: center; text-align: center;
  gap: 6px; color: var(--ink-2);
}
.ucard-new:hover { border-color: var(--accent); border-style: solid; }
.ucard-new:hover .plus { background: var(--accent); color: #fff; }
.ucard-new .plus {
  width: 34px; height: 34px; border-radius: 9px; font-size: 20px;
  background: var(--flat-bg); color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s, color .12s;
}
.ucard-new-label { font-size: 15px; font-weight: 650; color: var(--ink); }
.ucard-new-hint { font-size: 12px; color: var(--ink-3); }

/* Centred form page, matching the sign-in card's proportions. */
.formcard {
  max-width: 520px; margin: 28px auto 48px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 28px 30px;
}
.formcard h1 { margin-bottom: 6px; }
.formcard > .muted { margin: 0 0 22px; font-size: 14px; }
.fieldhint { font-size: 12.5px; color: var(--ink-3); margin: 6px 0 0; }
.formactions {
  display: flex; align-items: center; gap: 10px;
  margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line-2);
}
.formactions button { flex: 1; }

/* --- collapsible section ------------------------------------------------- */
.fold { border: 1px solid var(--line); border-radius: var(--radius); }
.fold > summary {
  cursor: pointer; list-style: none; padding: 13px 16px;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before {
  content: ""; flex: none; margin-right: 6px; align-self: center;
  width: 0; height: 0;
  border-left: 5px solid var(--ink-3);
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .12s;
}
.fold[open] > summary::before { transform: rotate(90deg); }
.fold[open] > summary { border-bottom: 1px solid var(--line-2); }
.fold > summary:hover { background: #fafbfc; }
.fold-title {
  font-size: 12px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-2); font-weight: 650;
}
.fold-meta { font-size: 12.5px; color: var(--ink-3); }
.fold .scroll { padding: 0 4px 4px; }

/* --- error pages (404/403/400) --------------------------------------------
   Narrow measure and a lot of air: the reader is stuck, so the page has one
   job and should not look like a dashboard that failed to load. */
.errpage { max-width: 640px; margin: 56px auto; }
.errpage h1 { font-size: 26px; letter-spacing: -.02em; margin: 16px 0 10px; }
.errpage h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); margin: 0 0 10px; }
.err-code {
  display: inline-block; font: 600 13px/1 var(--mono); letter-spacing: .08em;
  color: var(--warn); background: var(--warn-bg); border: 1px solid #f0dcb4;
  border-radius: 999px; padding: 6px 11px;
}
.err-path {
  margin: 0 0 14px; padding: 9px 12px; overflow-x: auto; white-space: nowrap;
  background: var(--flat-bg); border: 1px solid var(--line);
  border-radius: 6px; color: var(--ink-2);
}
.err-suggest {
  margin-top: 26px; padding: 18px 20px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.err-list { list-style: none; margin: 0; padding: 0; }
.err-list li { padding: 6px 0; border-bottom: 1px solid var(--line-2);
  display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.err-list li:last-child { border-bottom: 0; }
.err-links { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 26px; }

/* Category header inside a factor definition table: a label for the rows under
   it, not a data row, so it is tinted and its weight is the emphasis. */
.grid tr.grouprow th, .grid tr.grouprow td {
  background: var(--line-2); font-size: 12px; letter-spacing: .02em;
  text-transform: uppercase; color: var(--ink-2);
}

/* Formula and weight inputs in the strategy editor. Monospace for formulas,
   because a misplaced bracket has to be visible. */
input.fx {
  width: 100%; min-width: 260px; padding: 5px 7px; font-size: 12.5px;
  border: 1px solid var(--line); border-radius: 5px; background: var(--card);
  color: var(--ink);
}
input.wt {
  width: 68px; padding: 5px 6px; text-align: right; font-family: var(--mono);
  font-size: 12.5px; border: 1px solid var(--line); border-radius: 5px;
}
input.fx:focus, input.wt:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

/* A destructive action that should not look like a primary button. */
.linkbtn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--neg); font-size: 12.5px; text-decoration: none;
}
.linkbtn:hover { text-decoration: underline; }
.linkbtn:hover { color: #8c1d17; }
/* 8a and 8b are one numbered stage in two parts, not two stages. The number
   is said once on the group and each part wears only its letter. */
.stagegroup {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px var(--cell-x) var(--cell-x); margin-bottom: 14px;
  background: var(--flat-bg);
}
.stagegroup-n {
  margin: 0 0 10px; font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3);
}
.stagegroup .substage { margin-bottom: 10px; }
.stagegroup .substage:last-child { margin-bottom: 0; }

/* Navigation is not destruction. `linkbtn` is red because it removes things;
   a "see all" link wearing it reads as a warning about the page it opens. */
.morelink {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--ink-3); text-decoration: none;
}
.morelink:hover { color: var(--accent); text-decoration: underline; }
fieldset.f { border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; }
fieldset.f legend { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); padding: 0 6px; }
label.radio { display: flex; gap: 9px; align-items: flex-start; margin: 8px 0; font-size: 13px; line-height: 1.45; }
label.radio input { margin-top: 3px; }

/* A stacked form: label above, control full width. Used where a field is a
   paragraph rather than a value, so it gets the room to be read. */
/* A checkbox's own label is a sentence, not a field name. The uppercase rule
   above was shouting a two-line explanation at the reader. */
.stackform .f > label.radio {
  text-transform: none; letter-spacing: 0; font-size: 13px; color: var(--ink-2);
  display: flex; gap: 9px; align-items: flex-start; margin-bottom: 0;
}
.stackform .f-actions { margin-bottom: 0; }

/* Formula reference. Sits inside the editor because a guide on another page is
   a guide nobody reads while typing. */
.refbody { padding: 4px 16px 16px; }
.refbody h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); margin: 18px 0 8px;
}
.refbody h3:first-child { margin-top: 6px; }
.refbody .grid td { padding: 6px 10px; vertical-align: top; }
.refbody .mono { font-family: var(--mono); font-size: 12.5px; }
.reflist { margin: 0; padding-left: 20px; font-size: 13px; color: var(--ink-2); line-height: 1.55; }
.reflist li { margin-bottom: 5px; }
.nowrap { white-space: nowrap; }

.refpre {
  background: var(--flat-bg); border: 1px solid var(--line); border-radius: 6px;
  padding: 11px 13px; font-size: 12.5px; overflow-x: auto; margin: 8px 0 0;
}

/* File input. The native control renders as a grey "Choose File" button next to
   "No file chosen", which looks like a different application from everything
   around it. The input is hidden and its label is the control; the filename is
   written back on change so the state is still visible. */
.filepick { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.filepick input[type="file"] {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.filepick .pick {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 9px 15px; border-radius: 6px; background: var(--card);
  border: 1px solid var(--line); color: var(--ink); font-size: 14px;
  font-weight: 500; transition: background .12s, border-color .12s;
}
.filepick .pick:hover { background: #f4f6f9; border-color: var(--ink-3); }
.filepick input[type="file"]:focus-visible + .pick {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.filepick .pick::before {
  content: ""; width: 0; height: 0; flex: none;
  border-left: 5px solid var(--ink-3);
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
}
.filepick .chosen { font-size: 13px; color: var(--ink-3); }
.filepick .chosen.has-file { color: var(--ink); font-family: var(--mono); font-size: 12.5px; }


/* --- dashboard ---------------------------------------------------------- */
/* A card heading with an escape hatch to the full list on the right. The
   dashboard shows every strategy and universe today, but it is the page that
   will overflow first, so the link is there before it is needed. */
.dashhead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
.dashhead h2 { margin: 0; }
/* Factor labels wrap as a set of pills rather than a comma list: a strategy
   with nine factors would otherwise force the column wide enough to squeeze
   every other column on the row. */
.factorcell { display: flex; flex-wrap: wrap; gap: 4px; max-width: 420px; }
.factorcell .pill { font-size: 11px; }


/* --- form controls, everywhere ------------------------------------------
   Every control on the site used to be styled by whichever container it sat
   in — .f, .formcard, .stackform, .auth, .wrow each restyled inputs from
   scratch. A control outside all of them (the universe picker on the apply
   page) fell back to the browser default: a grey system select with a heavy
   focus ring, next to buttons we had designed.

   This is the base layer. It is written with :where() so it carries zero
   specificity: every scoped rule above still wins on the properties it sets,
   and this only fills in what nothing else claims. Add a container style for
   layout (width, font size); never again for the look of the control.        */

:where(input, select, textarea, button) { font-family: inherit; }

:where(
  input[type="text"], input[type="search"], input[type="number"],
  input[type="email"], input[type="password"], input[type="date"],
  input[type="url"], input:not([type]), select, textarea
) {
  font-size: 14px; line-height: 1.4; color: var(--ink);
  padding: 8px 11px;
  background: var(--card);
  border: 1px solid var(--field);
  border-radius: 6px;
  /* The control should look like it belongs to the page, not to the OS. */
  appearance: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}

:where(textarea) { line-height: 1.55; resize: vertical; min-height: 80px; }

/* A select needs its own chevron once appearance is cleared, or it becomes an
   indistinguishable text box. Inline SVG so it costs no request and inherits
   nothing from the theme it cannot see. */
:where(select) {
  padding-right: 32px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%236d7786' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  cursor: pointer;
}
/* Options are drawn by the OS; only the colours are ours to set, and only so
   the dropdown does not flash white-on-white in a dark system theme. */
:where(select) option { color: var(--ink); background: var(--card); }

/* One focus treatment for the whole site. :focus-visible rather than :focus so
   a click does not leave a ring behind, but keyboard navigation always shows
   where it is. */
:where(input, select, textarea):focus-visible {
  outline: none;
  border-color: var(--field-focus);
  box-shadow: 0 0 0 3px rgba(31, 95, 191, .16);
}

:where(input, textarea)::placeholder { color: var(--ink-3); opacity: 1; }

:where(input, select, textarea):disabled {
  background: var(--flat-bg); color: var(--ink-3); cursor: not-allowed;
  border-color: var(--line);
}

/* Invalid only after the browser has something to judge — :invalid alone paints
   a required empty field red before the reader has typed anything. */
:where(input, select, textarea):user-invalid {
  border-color: var(--neg);
  box-shadow: 0 0 0 3px rgba(179, 38, 30, .13);
}

/* Checkboxes and radios keep their native control (accessible, familiar) and
   take only the brand colour and a size that matches 14px text. */
:where(input[type="checkbox"], input[type="radio"]) {
  width: 16px; height: 16px; margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
:where(input[type="checkbox"], input[type="radio"]):focus-visible {
  outline: 2px solid var(--field-focus); outline-offset: 2px;
}

/* The file input's own button is the ugliest default on the site; it gets the
   ghost-button treatment so an upload row reads as one designed control. */
:where(input[type="file"]) {
  font-size: 13.5px; color: var(--ink-2); max-width: 100%;
}
:where(input[type="file"])::file-selector-button {
  font: inherit; font-size: 13.5px; font-weight: 550;
  margin-right: 10px; padding: 7px 13px;
  color: var(--navy); background: #fff;
  border: 1px solid var(--field); border-radius: 6px;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}
:where(input[type="file"])::file-selector-button:hover {
  background: var(--flat-bg); border-color: var(--ink-3);
}

/* A number field's spinners are noise next to a weight the reader types; the
   arrows stay reachable by keyboard either way. */
:where(input[type="number"]) { -moz-appearance: textfield; }
:where(input[type="number"])::-webkit-inner-spin-button,
:where(input[type="number"])::-webkit-outer-spin-button {
  -webkit-appearance: none; margin: 0;
}

/* --- inline control row -------------------------------------------------
   A label and its control on one line, as the universe picker on the apply
   page. Sized so the select does not collapse to the width of the longest
   option, which made the control jump as the reader changed selection.      */
.cellview select, .pickrow select { min-width: 260px; }

/* A secondary action inside a table cell, beside the row's main link. Was an
   inline style on the strategies list. */
.rowlink {
  margin-left: 8px; font-size: 12px; color: var(--ink-3);
  text-decoration: none; border-bottom: 1px solid var(--line);
}
.rowlink:hover { color: var(--accent); border-bottom-color: currentColor; }

/* --- waiting on a job --------------------------------------------------- */
.waiting-state {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--ink-2); margin: 14px 0 0;
}
.spinner {
  width: 14px; height: 14px; flex: none;
  border: 2px solid var(--line); border-top-color: var(--accent);
  border-radius: 50%; animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Respect a reader who has asked for less motion: the text still updates on
   each refresh, so the spinner is decoration rather than the only signal. */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border-top-color: var(--line); }
}


/* --- radio choices inside a form card ----------------------------------- */
/* `.formcard label` sets the uppercase, letter-spaced style that suits a field
   name above an input. A radio's label is a sentence, and that rule was
   shouting three lines of explanation at the reader in small caps. These
   options are the whole reason the page exists, so they get sentence case, a
   left edge shared with the control, and room to breathe. */
.formcard fieldset.f {
  margin: 22px 0 0;
  padding: 16px 18px 18px;
  display: block;
}
.formcard fieldset.f legend {
  /* Matches the field labels above it, since it names this group. */
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; color: var(--ink-3);
  margin: 0; padding: 0 6px;
}
.formcard label.radio {
  display: grid;
  grid-template-columns: 18px 1fr;
  align-items: start;
  gap: 0 11px;
  margin: 0;
  padding: 10px 2px;
  text-transform: none;
  letter-spacing: 0;
  font-size: 13.5px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink-2);
  text-align: left;
  cursor: pointer;
}
.formcard label.radio + label.radio { border-top: 1px solid var(--line-2); }
.formcard label.radio input[type="radio"] { margin-top: 3px; }
/* The option's own name, which the sentence continues from. */
.formcard label.radio strong { color: var(--ink); font-weight: 600; }

/* The select belongs to the radio above it: aligned to that option's text
   column so it reads as part of the choice rather than as a fourth option. */
.formcard .subfield {
  margin: 0 2px 10px 29px;
  padding-bottom: 4px;
}
.formcard .subfield select { width: 100%; max-width: 420px; }

/* Actions sit clear of the fieldset above them. */
.formcard fieldset.f + .f-actions { margin-top: 22px; }
.f-actions { display: flex; gap: 10px; align-items: center; }

/* --- the strategy funnel ------------------------------------------------ */
/* The bar is the share of the starting universe, so a reader sees the shape of
   the funnel — a wide universe narrowing to sixty names — without arithmetic. */
.grid td.barcell { min-width: 140px; }
.grid td.barcell .bar {
  display: inline-block; height: 8px; border-radius: 2px;
  background: var(--accent); opacity: .55; vertical-align: middle;
  min-width: 2px; max-width: calc(100% - 42px);
}
.grid td.barcell .barnum {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  margin-left: 6px; font-variant-numeric: tabular-nums;
}


/* --- the stage flow ----------------------------------------------------- */
/* A sequence read top to bottom, with a rail connecting the steps. Vertical
   because a strategy runs to sixteen stages, and sixteen boxes across a page
   either become unreadable or scroll sideways.

   No grid: the first version reserved a column for the marker and then placed
   the marker absolutely on the rail as well, leaving 2.4rem of dead space in
   front of every label. The marker sits on the rail; the text starts where the
   padding puts it. */
.flow { list-style: none; margin: 0; padding: 0 0 0 1.1rem; }

.flow-step {
  position: relative;
  border-left: 2px solid var(--line);
  padding: 0 0 14px 1.5rem;
  min-height: 1.9rem;
}
.flow-step:last-child { border-left-color: transparent; padding-bottom: 0; }

.flow-num {
  position: absolute; left: -0.97rem; top: -2px;
  width: 1.9rem; height: 1.9rem;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 11.5px; font-weight: 500;
  color: var(--ink-2); background: var(--card);
  border: 2px solid var(--line); border-radius: 50%;
  font-variant-numeric: tabular-nums;
}
.flow-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.flow-label {
  font-size: 14px; font-weight: 550; color: var(--ink); line-height: 1.5;
}
.flow-label a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line); }
.flow-label a:hover { color: var(--accent); border-bottom-color: currentColor; }
.flow-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.flow-count {
  font-family: var(--mono); font-size: 11.5px; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.flow-drop { font-family: var(--mono); font-size: 11.5px; color: var(--neg); }
.flow-note {
  font-size: 12.5px; color: var(--ink-3); line-height: 1.45; max-width: 78ch;
}

/* State on the marker, not the whole row: a coloured block per step would make
   a sixteen-stage strategy look like an alarm panel. */
.flow-step.is-done .flow-num { border-color: var(--pos); color: var(--pos); }
.flow-step.is-skipped .flow-num { border-style: dashed; color: var(--ink-3); }
.flow-step.is-blocked .flow-num { border-color: var(--warn); color: var(--warn); }
.flow-step.is-failed .flow-num { border-color: var(--neg); color: var(--neg); }
.flow-step.is-running .flow-num { border-color: var(--accent); color: var(--accent); }
.flow-step.is-skipped .flow-label { color: var(--ink-3); font-weight: 400; }

/* The phase boundary. The one between selection and optimisation carries the
   approval gate, and it is the most consequential line in the process: nothing
   past it may consume weights a person has not signed. The rail continues
   through it, so the sequence does not visually break in two. */
.flow-phase {
  position: relative;
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  border-left: 2px solid var(--line);
  padding: 4px 0 12px 1.5rem;
}
.flow-phase-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.flow-gate {
  font-size: 10.5px; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--warn); background: var(--warn-bg);
  padding: 3px 8px; border-radius: 3px;
}
.inlineform { display: inline-block; margin: 0; }

/* Per-stage re-run. Deliberately quiet — it appears on every step of a
   sixteen-stage run, and sixteen buttons competing with the labels would make
   the diagram unreadable. Visible on hover or focus, always reachable by
   keyboard. */
.flow-run { margin: 3px 0 0; }
.flow-run button { font-size: 11.5px; opacity: 0; transition: opacity .12s ease; }
.flow-step:hover .flow-run button,
.flow-run button:focus-visible { opacity: 1; }
@media (hover: none) { .flow-run button { opacity: 1; } }

/* One column, where the two-column layout would spend half a screen saying
   "nothing was dropped". */
.onecol { display: block; }
.onecol > .card { margin-bottom: 18px; }


/* --- the stage editor --------------------------------------------------- */
/* One block per stage rather than a table row. A stage carries a number, a
   name, a paragraph explaining what it does and up to six settings; a table
   made every one of those a column, which is why Selection's target band was
   nowhere to be seen. */
.stagecard {
  border: 1px solid var(--line); border-radius: 6px;
  padding: 14px 16px; margin-bottom: 12px; background: var(--surface-2, #f8f9fb);
}
.stagecard-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.stagecard-head .wt { width: 4rem; }
.stagecard-head .wt.sub { width: 3rem; }
.stagecard-head .stagename { flex: 1 1 18rem; min-width: 12rem; }
/* The number reads; the arrows move it. It is the specification's own number
   and its gaps are deliberate, so it is not a position to be typed. */
.stageno { display: flex; align-items: center; gap: 8px; flex: none; }
.stageno-n {
  font-family: var(--mono); font-size: 15px; font-weight: 600;
  color: var(--ink); min-width: 2.2rem; text-align: right;
  font-variant-numeric: tabular-nums;
}
.stageno-move { display: flex; flex-direction: column; gap: 2px; }
.nudge {
  display: block; width: 20px; height: 15px; padding: 0;
  border: 1px solid var(--line); border-radius: 3px;
  background: var(--card); color: var(--ink-3);
  font-size: 8px; line-height: 1; cursor: pointer;
}
.nudge:hover:not(:disabled) {
  color: var(--accent); border-color: var(--accent); background: var(--surface-2);
}
.nudge:disabled { opacity: .3; cursor: default; }
/* The type is what the stage does, so it is editable — until the stage has run
   and owns a record of what it did, when it renders fixed rather than absent. */
.stagecard-head .stagetype { flex: 0 1 14rem; min-width: 10rem; }
.stagecard-head .stagetype:disabled {
  background: var(--flat-bg); color: var(--ink-3);
  border-color: var(--line-2); cursor: not-allowed;
}
.stagecard-what {
  font-size: 12.5px; color: var(--ink-3); line-height: 1.5;
  margin: 10px 0 0; max-width: 82ch;
}
.stagecard-settings {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(12.5rem, 1fr));
  gap: 16px 14px; margin-top: 12px;
  padding-top: 12px; border-top: 1px solid var(--line-2);
}
/* Three rows per setting — label, control, hint — on a shared track, so a
   label that wraps to two lines does not push its own input below the one
   beside it. That misalignment was the whole problem: four boxes in a row at
   four different heights read as four unrelated controls. */
.setting {
  display: grid; grid-template-rows: auto auto 1fr; gap: 5px;
  margin: 0; min-width: 0;
}
.setting > label {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin: 0;
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
/* What the number counts, beside the name rather than buried in the hint. */
.setting .unit {
  flex: none; font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--ink-3);
  background: var(--flat-bg); border: 1px solid var(--flat-line);
  border-radius: 3px; padding: 1px 5px;
}
.setting > input { width: 100%; box-sizing: border-box; }
.setting .fieldhint { margin: 0; font-size: 11.5px; line-height: 1.4; }


/* --- a run: the sequence beside what happened in it ---------------------- */
/* Timeline left, detail right. Reading a stage on its own page meant losing
   sight of where it sat in the sequence, and going back and forth to compare
   two of them. The timeline is narrow and fixed so the detail keeps the width. */
.runlayout {
  display: grid;
  grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
  margin-bottom: 18px;
}
@media (max-width: 900px) {
  .runlayout { grid-template-columns: 1fr; }
}

.timeline {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 6px;
  position: sticky;
  top: 12px;
}
.timeline ol { list-style: none; margin: 0; padding: 0; }

.tl-item > a {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 0 10px;
  padding: 9px 10px 10px;
  border-radius: 6px;
  text-decoration: none;
  color: inherit;
}
.tl-item > a:hover { background: var(--surface-2, #f1f4f8); }
.tl-item.is-selected > a { background: #eef3fb; }
.tl-item.is-selected .tl-name { font-weight: 600; color: var(--ink); }

/* The marker and the line through it carry the sequence, so a reader can see
   at a glance how far a run got before it stopped doing real work. */
.tl-marker {
  position: relative;
  width: 10px; height: 10px; margin: 5px 0 0 4px;
  border-radius: 50%;
  background: var(--line);
  box-shadow: 0 0 0 2px var(--card);
}
.tl-item:not(:last-child) .tl-marker::after {
  content: ""; position: absolute; left: 4px; top: 12px;
  width: 2px; height: calc(100% + 26px);
  background: var(--line-2);
}
.tl-item.st-done .tl-marker { background: var(--pos); }
.tl-item.st-blocked .tl-marker { background: var(--warn); }
.tl-item.st-failed .tl-marker { background: var(--neg); }
.tl-item.st-skipped .tl-marker { background: var(--card); box-shadow: 0 0 0 2px var(--line); }

.tl-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.tl-head { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.tl-num {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  font-variant-numeric: tabular-nums; flex: none;
}
.tl-name {
  font-size: 13px; color: var(--ink-2); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tl-meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--ink-3);
}
.tl-meta strong { font-family: var(--mono); color: var(--ink-2); font-weight: 600; }
.tl-meta .pill { font-size: 9.5px; padding: 1px 5px; }

/* Share of where the sequence started, so the narrowing reads as a shape. */
.tl-bar { display: block; height: 3px; background: var(--line-2); border-radius: 2px; margin-top: 3px; }
.tl-fill { display: block; height: 100%; background: var(--accent); opacity: .5; border-radius: 2px; }

.stagepanel { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.stagepanel .dashhead h2 { font-size: 17px; }
.stagepanel h3 { margin: 0; font-size: 14px; }


/* --- a run, as one screen ----------------------------------------------- */
/* The sequence on the left and the open stage on the right, both bounded to
   the viewport so the tables scroll inside their own panels. Before this the
   page stacked a process diagram, a timeline, two tables and a summary table,
   and reading the second table meant scrolling past everything above it. */
.runlayout {
  height: calc(100vh - 210px);
  min-height: 420px;
  align-items: stretch;
}
.runlayout .timeline {
  position: static;
  overflow-y: auto;
  max-height: 100%;
}
.stagepanel { min-height: 0; height: 100%; }

/* Kept and dropped side by side. Comparing what survived against what did not
   is the question the panel exists to answer, and stacking them put the answer
   below the fold. */

@media (max-width: 900px) {
  .runlayout { height: auto; }
  .runlayout .timeline { max-height: 320px; }
}

.stagehead-right { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.stagehead-right .btn { padding: 5px 11px; font-size: 12.5px; }

/* Tabs inside the stage panel. The workings table is wide, so it scrolls in
   both directions inside its own card rather than moving the page. */
.stagetabs { margin: 0 0 12px; }
.stagepanel .workings { display: flex; flex-direction: column; min-height: 0; flex: 1; margin-bottom: 0; }
.stagepanel .workings .tablewrap { overflow: auto; flex: 1; min-height: 0; max-height: none; }
/* A dropped row is greyed rather than hidden: the comparison against the names
   that survived is the point of showing it. */
.workings tr.is-dropped td { color: var(--ink-3); }
.workings tr.is-dropped .tick { opacity: .75; }


/* --- a run, as a dashboard ---------------------------------------------- */
/* The head is the run's numbers, not a sentence about them: a reader wants to
   know how far 503 names narrowed and how long it took, and reading that out of
   prose is slower than reading it off a row of figures. */
.runhead {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; margin-bottom: 16px;
}
.runhead-title h1 { margin: 0 0 2px; font-size: 22px; letter-spacing: -.01em; }
.runhead-title p { margin: 0; font-size: 12.5px; }

.runstats { display: flex; gap: 22px; margin: 0; flex-wrap: wrap; }
.runstats > div { display: flex; flex-direction: column; gap: 2px; }
.runstats dt {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3);
}
.runstats dd {
  margin: 0; font-size: 17px; font-weight: 600; color: var(--ink);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.runstats dd.accent { color: var(--accent); }
.runstats dd .of { font-size: 12px; font-weight: 400; color: var(--ink-3); }
.runstats .pill { font-size: 10px; }

/* One panel, not three stacked cards with one line in each. */
.stageview {
  display: flex; flex-direction: column; min-height: 0; height: 100%;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}
.stageview-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 14px 18px 12px;
}
.stageview-title .eyebrow {
  display: block; font-family: var(--mono); font-size: 10px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
  margin-bottom: 3px;
}
/* Sentence case at a readable size. The old heading shouted the stage name in
   capitals across two lines, which cost a fifth of the panel to say one thing. */
.stageview-title h2 {
  margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.01em;
  color: var(--ink); text-transform: none;
}
.stageview-stats { display: flex; align-items: center; gap: 16px; }
.stageview-stats span { font-size: 12px; color: var(--ink-3); }
.stageview-stats b {
  font-family: var(--mono); font-size: 14px; font-weight: 600; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stageview-stats .btn { padding: 5px 12px; font-size: 12.5px; }

.stageview-note {
  margin: 0; padding: 0 18px 14px;
  font-size: 13px; line-height: 1.5; color: var(--ink-2); max-width: 90ch;
}

/* A tab strip reads as tabs — an underline on the current one — rather than as
   a bordered box containing a single word. */
.tabstrip {
  display: flex; gap: 2px; padding: 0 18px;
  border-bottom: 1px solid var(--line); flex: none;
}
.tabstrip a {
  padding: 8px 12px 9px; font-size: 13px; font-weight: 500;
  color: var(--ink-3); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabstrip a:hover { color: var(--ink-2); }
.tabstrip a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }
.tabcount {
  display: inline-block; margin-left: 5px; padding: 1px 6px;
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  color: var(--ink-3); background: var(--flat-bg);
  border: 1px solid var(--flat-line); border-radius: 9px;
}
.tabstrip a[aria-current="page"] .tabcount {
  color: var(--accent); background: var(--accent-bg, var(--flat-bg));
  border-color: var(--flat-line);
}

/* The tables live inside the panel and scroll there. */
.stageview .workings { margin: 0; border: 0; border-radius: 0; flex: 1; min-height: 0; }
.stageview .tablecap { padding: 12px var(--cell-x) 8px; }
.stageview .tablescroll { max-height: none; }
.stageview .tablecap h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); font-weight: 600; }
.stageview .tablecap .fieldhint { margin-top: 3px; font-size: 11.5px; }
.stageview .grid thead th { background: var(--card); }

/* The left rail: tighter rows, so twelve stages fit without scrolling. */
.timeline { padding: 4px; }
.tl-item > a { padding: 7px 9px 8px; }
.tl-name { font-size: 12.5px; }
.tl-meta { font-size: 11px; }
.tl-item:not(:last-child) .tl-marker::after { height: calc(100% + 20px); }

@media (max-width: 900px) {
  .runhead { align-items: flex-start; }
}

/* Spacing on this page specifically. The defaults are set for a document with
   a few cards down the page; a dashboard bounded to the viewport needs the gaps
   pulled in or half the height goes to whitespace between things. */
.runlayout { gap: 14px; margin-bottom: 0; }
.runlayout .card { margin-bottom: 0; }
.stagepanel { gap: 0; }
.stageview .grid td, .stageview .grid th { padding: 6px 18px; }
.stageview .grid thead th { padding-top: 8px; padding-bottom: 8px; }
.timeline .tl-bar { margin-top: 4px; }
.crumbs { margin-bottom: 10px; }


/* --- the Portfolio Manager review --------------------------------------- */
/* Turnover on the left, because that is the longest list; the limits and the
   decision on the right, so a reviewer reads the evidence and records the
   decision without leaving the page. */
.reviewgrid {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(320px, 1fr);
  gap: 16px; align-items: start;
}
.reviewside { display: flex; flex-direction: column; gap: 16px; }
.reviewgrid .tablewrap { max-height: 420px; overflow-y: auto; }
/* Why a strategy is blocked, on its own row under it. A count with no reason
   makes the reader open the page to find out what it meant — but the reason
   cannot live in the status cell, because every cell in a .tablewrap grid is
   nowrap, so it would widen the column instead of wrapping. */
.grid tr.whyrow > td {
  padding: 0 var(--pad) 10px; border-top: 0;
  white-space: normal; color: var(--ink-3);
}
/* The rule belongs under the pair, not between them: a border above the
   reason would attach it to the row below instead of the row it explains. */
.grid tbody tr.hasreason > td { border-bottom: 0; }
.why {
  display: block; max-width: 90ch;
  font-size: 11.5px; line-height: 1.4;
}
.why::before { content: "↳ "; color: var(--warn); }
.limitnote {
  display: block; font-size: 11px; color: var(--ink-3); margin-top: 2px;
  max-width: 30ch; line-height: 1.35;
}
.limitfoot { padding: 0 var(--cell-x) var(--cell-x); margin: 8px 0 0; }
/* Beside the caption it belongs to, so three tables on one page each carry
   their own export rather than sharing one ambiguous button. */
/* A short list of links inside a card, without the bullet indent a default
   list brings. */
.plainlist { margin: 0; padding: 0; list-style: none; }
.plainlist li {
  padding: 6px 0; font-size: 13px; color: var(--ink-2);
  border-bottom: 1px solid var(--line-2);
}
.plainlist li:last-child { border-bottom: 0; }

/* A caption is a header row, not a stack: what the table is on the left, what
   you can do with it on the right. The export had been a third line of prose
   under the heading, which read as a label rather than a control. */
.tablecap.caprow {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px;
}
.capmain { min-width: 0; }
.capmain h3, .capmain .fieldhint { margin: 0; }
.capmain .fieldhint { margin-top: 3px; }

.csvbtn {
  flex: none; align-self: center;
  padding: 5px 12px; font-size: 12.5px; white-space: nowrap;
}
.csvicon {
  font-family: var(--mono); font-size: 13px; line-height: 1;
  margin-right: 4px; opacity: .75;
}
/* A named breach is the line the reviewer is meant to act on, so it reads at
   body weight rather than as a footnote under it. */
.limitnote.strong { color: var(--neg); font-size: 11.5px; max-width: 42ch; }
.bookvalue { padding: 12px var(--cell-x) var(--cell-x); border-top: 1px solid var(--line-2); }
.bookvalue .f { margin: 0; max-width: 22rem; }
.bookvalue .f-actions { margin-top: 10px; }
.runstats dd.warn { color: var(--warn); }
.runstats dd.small { font-size: 13px; font-weight: 500; }
.reviewactions { flex-wrap: wrap; }
.reviewactions .btn { flex: none; }
@media (max-width: 900px) { .reviewgrid { grid-template-columns: 1fr; } }


/* =========================================================================
   FORMS — one system
   =========================================================================
   Six had accumulated: .f, .auth, .formcard, .stackform, .wrow and .ucard-new,
   each redefining its own label and its own control. The differences were 14px
   against 15px and eight pixels of padding against nine — no decision, just
   drift, and six places to change when the answer moves.

   Control *appearance* is not here at all: it lives in the global :where()
   layer above, so every input on the site already looks the same. This is the
   layout around one — label, control, hint — and the row of actions under it.

   `.field` is the name to write in new markup. The others are listed with it so
   the twenty templates already using them look identical today rather than
   after a migration.
   ---------------------------------------------------------------------- */

.form, .stackform { display: flex; flex-direction: column; gap: 16px; }

.field, .f, .wrow, .stackform .f {
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
}

/* One label. Uppercase and letter-spaced because a field name is a label rather
   than a sentence — the exception below is a checkbox, whose label *is* one. */
.field > label,
.f > label,
.wrow > label,
.auth label,
.formcard label,
.ucard-new label {
  display: block;
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; color: var(--ink-3);
  margin: 0;
}
/* "optional", inline in a label, is prose and should not shout. */
.field > label .opt,
.formcard label .opt,
.f > label .opt {
  text-transform: none; letter-spacing: 0; font-weight: 500; color: var(--ink-3);
}

/* Controls fill their field; everything else about them is the global layer. */
.field > input, .field > select, .field > textarea,
.f > input, .f > select, .f > textarea,
.wrow > input, .wrow > select,
.auth input, .auth select,
.formcard input, .formcard select, .formcard textarea,
.stackform input, .stackform select, .stackform textarea,
.ucard-new input, .ucard-new select, .ucard-new textarea {
  width: 100%;
}
/* Prose fields get a measure: a textarea the full width of a wide card is a
   line too long to read comfortably. */
.field > textarea, .formcard textarea, .stackform textarea { max-width: 78ch; }
/* A weight or a threshold is a figure, so it is set in the figures face. */
.wrow > input, input.wt, input.fx { font-family: var(--mono); }

/* A checkbox or radio label is a sentence and is set as one. */
.field > label.radio,
.f > label.radio,
.stackform .f > label.radio,
label.radio {
  display: flex; gap: 9px; align-items: flex-start;
  text-transform: none; letter-spacing: 0;
  font-size: 13px; font-weight: 400; line-height: 1.45; color: var(--ink-2);
  margin: 0; cursor: pointer;
}

.fieldhint { font-size: 12.5px; line-height: 1.45; color: var(--ink-3); margin: 2px 0 0; }

/* Two or three fields on one line, for values that belong together. */
.field-row, .wcols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
}

/* Actions. The rule above the row separates the decision from the inputs. */
.form-actions, .formactions {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 8px; padding-top: 18px; border-top: 1px solid var(--line-2);
}
/* A single-purpose form — sign in, one control and one button — reads better
   with the button full width and no rule above it. */
.auth .form-actions, .auth .formactions,
.ucard-new .form-actions, .ucard-new .formactions { border-top: 0; padding-top: 0; }
.auth button, .ucard-new button { width: 100%; }
/* An actions row that is only buttons, inline in a card or a table cell. */
.f-actions { flex-direction: row; gap: 8px; border-top: 0; padding-top: 0; margin-top: 0; }


/* --- the CSV import panel ----------------------------------------------- */
/* The control first and narrow, its reference below and quiet. The checkbox
   had been laid out by a rule meant for radio lists, which put the box on one
   side of the panel and its sentence on the other. */
.importform { max-width: 34rem; padding: 4px 0 2px; }
.importform .f { margin-bottom: 14px; }
.checkline {
  display: flex; align-items: flex-start; gap: 9px;
  font-size: 13px; color: var(--ink-2); cursor: pointer;
  text-transform: none; letter-spacing: 0; font-weight: 400;
}
.checkline input { margin: 2px 0 0; flex: none; }
.checkline + .fieldhint { margin-top: 5px; padding-left: 25px; max-width: 46ch; }

.importref {
  margin-top: 18px; padding-top: 14px;
  border-top: 1px solid var(--line-2);
}
.importref .note { max-width: 74ch; margin: 0 0 10px; }
.importref .note:last-child { margin-bottom: 0; }
.importref .refpre { margin: 0 0 12px; }

/* --- the scoring console ------------------------------------------------ */
/* Provenance beside the title, not in a key/value table under a form: which
   model and which prompt package produced a score is context for the whole
   page. */
.provenance {
  display: flex; gap: 18px; align-items: center; flex-wrap: wrap;
  font-size: 12px; color: var(--ink-3);
}
.provenance b {
  display: block; font-size: 10px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 2px;
}
.provenance span { font-family: var(--mono); color: var(--ink-2); }

/* The worklist as a progression rather than a column of counts: a reader
   asking how far through we are should not have to do the division. */
.statelist { margin: 0; padding: 0 var(--cell-x); list-style: none; }
.statelist li {
  display: grid; grid-template-columns: 3.5rem 1fr 3rem;
  align-items: center; gap: 12px; padding: 9px 0;
  border-bottom: 1px solid var(--line-2);
}
.statelist li:last-child { border-bottom: 0; }
.state-n { font-size: 16px; font-weight: 600; color: var(--ink); text-align: right; }
.state-body { min-width: 0; }
.state-label {
  display: block; font-size: 12.5px; color: var(--ink-2); margin-bottom: 5px;
}
.statelist .bar {
  display: block; height: 4px; border-radius: 2px;
  background: var(--flat-bg); overflow: hidden;
}
.statelist .bar i { display: block; height: 100%; border-radius: 2px; }
.statelist .bar i.t-pos { background: var(--pos); }
.statelist .bar i.t-warn { background: var(--warn); }
.statelist .bar i.t-flat { background: var(--accent); }
.statelist .bar i.t-neutral { background: var(--flat); }
.state-share { font-size: 12px; text-align: right; }

/* A form inside a card that already has a caption needs its own padding. */
.cardform { padding: 12px var(--cell-x) var(--cell-x); }
.cardfoot { padding: 0 var(--cell-x) var(--cell-x); margin: 0; }

/* --- column visibility -------------------------------------------------- */
/* A checkbox per column. Collapsed to one control until it is wanted, and
   forced open whenever a column is hidden, since a table quietly missing a
   column is worse than a visible control saying so. */
.colvis { display: contents; }
.colvisbar {
  display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap;
  padding: 8px 18px; border-bottom: 1px solid var(--line);
  background: var(--surface-2); flex: none;
}
/* Closed, it is one control and should not occupy a full band of its own:
   right-aligned on a transparent ground until there is something to show. */
.colvisbar:not(.is-open) {
  justify-content: flex-end; background: none; padding: 6px 18px;
  border-bottom: 1px solid var(--line-2);
}
.colvislabel {
  font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
.colvistoggle {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); text-decoration: none;
}
.colvistoggle:hover { color: var(--accent); }
/* Sentence case and normal weight: these are column names, not headings, and
   the uppercase treatment above is what marks the control itself. */
.colvisitem {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--ink-2); cursor: pointer;
  text-transform: none; letter-spacing: 0; font-weight: 400; margin: 0;
}
.colvisitem input { margin: 0; }
.colvisapply { padding: 4px 12px; font-size: 12.5px; }



/* =========================================================================
   COLOUR — one interactive hue, and state that stays behind the content
   =========================================================================
   Three colours were competing for the same job: accent blue on every link,
   near-black navy on every button, and a saturated green pill — so a table of
   nine rows had nine bright blue names, four solid dark buttons and a scatter
   of tints, with nothing telling the eye where to go first.

   The rule now: accent is for the thing you click, navy is the brand and the
   one primary action on a page, and the state colours sit behind the content
   rather than in front of it.
   ---------------------------------------------------------------------- */

/* A link in a table row is the row. Nine of them in accent blue is not nine
   invitations, it is noise — so they take body colour with a quiet underline
   that says "link", and reserve the accent for hover and for actions. */
.grid td a:not(.btn):not(.tick):not(.pill) {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.grid td a:not(.btn):not(.tick):not(.pill):hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}
/* A ticker stays in the accent: it is short, monospaced, and the one thing a
   reader scans a rankings table for. */
.grid td a.tick { color: var(--accent); text-decoration: none; }
.grid td a.tick:hover { text-decoration: underline; }

/* One primary action per page, not one per row. A column of solid navy buttons
   reads as a wall and makes every row look equally urgent, so a button inside
   a table is quiet until it is hovered. */
.grid td .btn {
  padding: 4px 12px; font-size: 12.5px; font-weight: 550;
  background: var(--card); color: var(--navy);
  border: 1px solid var(--field);
}
.grid td .btn:hover {
  border-color: var(--accent); color: var(--accent);
}
/* The row's own primary keeps a hint of weight — a tinted ground rather than a
   solid one — so it still reads first among the row's actions. */
.grid td .btn:not(.ghost) {
  background: #eef3fb; border-color: #cfdff5; color: var(--navy-2);
}
.grid td .btn:not(.ghost):hover {
  background: var(--accent); border-color: var(--accent); color: #fff;
}

/* --- script-free tab panels ----------------------------------------------
   A radio per panel, labels styled as the tab strip, and the checked radio
   deciding which panel shows. The alternative — a tab per URL — reloads the
   page, and the factor editor is one form spanning two of its panels, so a
   reload would throw away every formula typed but not yet saved.

   Indexed by position rather than by id so the pattern is not welded to one
   page: the nth radio shows the nth panel. */
/* Positioned, so the off-screen radios stay inside this box: absolute against
   the viewport, a radio focused from the keyboard scrolls the page to wherever
   it landed rather than to the tab strip it belongs to. */
.tabset { position: relative; }
.tabpanel { display: none; }
.tabset > input:nth-of-type(1):checked ~ .tabpanels > .tabpanel:nth-of-type(1),
.tabset > input:nth-of-type(2):checked ~ .tabpanels > .tabpanel:nth-of-type(2),
.tabset > input:nth-of-type(3):checked ~ .tabpanels > .tabpanel:nth-of-type(3),
.tabset > input:nth-of-type(4):checked ~ .tabpanels > .tabpanel:nth-of-type(4) {
  display: block;
}
.tabset > input:nth-of-type(1):checked ~ .tabs > label:nth-of-type(1),
.tabset > input:nth-of-type(2):checked ~ .tabs > label:nth-of-type(2),
.tabset > input:nth-of-type(3):checked ~ .tabs > label:nth-of-type(3),
.tabset > input:nth-of-type(4):checked ~ .tabs > label:nth-of-type(4) {
  background: var(--navy); color: #fff;
}
.tabset > input:nth-of-type(1):checked ~ .tabs > label:nth-of-type(1) .tabcount,
.tabset > input:nth-of-type(2):checked ~ .tabs > label:nth-of-type(2) .tabcount,
.tabset > input:nth-of-type(3):checked ~ .tabs > label:nth-of-type(3) .tabcount,
.tabset > input:nth-of-type(4):checked ~ .tabs > label:nth-of-type(4) .tabcount {
  background: rgba(255, 255, 255, .13); color: #cddaec;
  border-color: rgba(255, 255, 255, .22);
}
/* The radio is off-screen, so the focus ring has to be drawn on its label or
   the tab strip cannot be seen to have focus while being driven from the
   keyboard — which is exactly how a radio group is driven. */
.tabset > input:nth-of-type(1):focus-visible ~ .tabs > label:nth-of-type(1),
.tabset > input:nth-of-type(2):focus-visible ~ .tabs > label:nth-of-type(2),
.tabset > input:nth-of-type(3):focus-visible ~ .tabs > label:nth-of-type(3),
.tabset > input:nth-of-type(4):focus-visible ~ .tabs > label:nth-of-type(4) {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* An unresolved problem on a panel that is not showing. A count would compete
   with the tab's own count; a dot says "look in here" and nothing more. */
.tabdot {
  width: 7px; height: 7px; margin-left: 5px; border-radius: 50%;
  background: var(--warn); flex: none;
}
/* The dot sits on a white tab and on the navy one, and no single amber clears
   3:1 against both: the text amber manages 6.6:1 on white but 2.4:1 on navy,
   the filled mark 5.4:1 on navy and 3.0:1 on white. So each background gets
   the one that works on it. */
.tabset > input:nth-of-type(1):checked ~ .tabs > label:nth-of-type(1) .tabdot,
.tabset > input:nth-of-type(2):checked ~ .tabs > label:nth-of-type(2) .tabdot,
.tabset > input:nth-of-type(3):checked ~ .tabs > label:nth-of-type(3) .tabdot,
.tabset > input:nth-of-type(4):checked ~ .tabs > label:nth-of-type(4) .tabdot {
  background: var(--warn-mark);
}

/* --- factor editor: one card per factor ----------------------------------
   The editor listed three add-forms, then every factor's table, then the
   overlay, in one column. A factor is the unit being edited, so it gets the
   card: its name, what its weights currently add up to, its sub-factors, and
   the controls that add to it — in that order, with nothing from another
   factor in between. */
.fcard {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 14px; overflow: hidden;
}
.fcard-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px 20px; flex-wrap: wrap; padding: 13px var(--cell-x);
  border-bottom: 1px solid var(--line-2);
}
.fcard-name { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.fcard-name h3 { margin: 0; font-size: 15px; }
.fcard-name .mono { font-size: 12px; }
.fcard-meta {
  display: flex; align-items: center; gap: 8px 16px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--ink-3);
}
.fcard .tablewrap { margin: 0; }
.fcard .grid tbody tr:last-child td { border-bottom: 0; }
.emptyrow { margin: 0; padding: 16px var(--cell-x); font-size: 13px; color: var(--ink-3); }

/* Adding to a factor happens inside that factor, so neither form has to ask
   which one it means. Folded shut: on a seven-factor model the fourteen add
   forms would otherwise be most of the page. */
.fcard-add {
  display: flex; gap: 10px 26px; flex-wrap: wrap; align-items: flex-start;
  padding: 10px var(--cell-x) 12px; border-top: 1px solid var(--line-2);
  background: #fbfcfd;
}
.fcard-add > details { flex: 1 1 340px; min-width: 0; }
.fcard-add summary {
  cursor: pointer; font-size: 13px; font-weight: 550; color: var(--accent);
  padding: 3px 0;
}
.fcard-add summary:hover { text-decoration: underline; }
.addrow {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px; align-items: end; padding: 12px 0 4px;
}
.addrow .note { grid-column: 1 / -1; margin: 2px 0 0; max-width: 78ch; }
.addfactor { margin-bottom: 18px; }
.addfactor .addrow { padding: 4px var(--cell-x) 14px; }
.reffold { margin-bottom: 16px; }

/* A category's sub-factor weights, shown beside the category rather than left
   for activation to complain about. Group headers are set in small uppercase;
   a pill inside one is a value, not a heading. */
.grid tr.grouprow td.groupsum { text-transform: none; letter-spacing: 0; }
.grouprow .pill { text-transform: none; letter-spacing: 0; font-weight: 550; }
.grid tr.warnrow th {
  background: var(--warn-bg); color: var(--warn);
  text-transform: none; letter-spacing: 0; font-weight: 550;
  white-space: normal;
}

/* The overlay matrix: a column is one complete allocation, so the column in
   force is marked and each column carries its own total. */
.overlaygrid tfoot th, .overlaygrid tfoot td {
  background: #fbfcfd; border-top: 2px solid var(--line);
  font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3);
}
.overlaygrid tfoot .pill { text-transform: none; letter-spacing: 0; }
.overlaygrid th.live { color: var(--accent); }
.overlaygrid th .pill { text-transform: none; letter-spacing: 0; font-weight: 550; }
.overlaygrid td .mono { font-size: 11.5px; }

/* Save covers both editable panels, so it belongs to neither — and the factor
   tables are long enough that a button under them is a scroll away from the
   field just typed into. */
.savebar {
  position: sticky; bottom: 0; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px 20px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 16px; margin: 18px 0 4px;
  box-shadow: 0 -3px 12px rgba(20, 24, 31, .07);
}
.savebar-state {
  margin: 0; font-size: 13px; color: var(--ink-2);
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
}
.savebar-actions { display: flex; gap: 8px; flex: none; }
@media (max-width: 700px) {
  .savebar { flex-direction: column; align-items: stretch; }
  .savebar-actions > .btn { flex: 1; text-align: center; }
}

/* The same row of facts as .runstats, for values that are words rather than
   headline figures: "Neutral zero (Z=0, no reweighting)" set at 17px bold
   reads as a statistic when it is a setting. */
.runstats.settings { gap: 14px 26px; }
.runstats.settings dd {
  font-size: 13.5px; font-weight: 550; line-height: 1.4; color: var(--ink-2);
}

/* The factors panel: a factor's shape, without its formulas. Categories are a
   short table of their own here, so the panel answers "what is this factor
   made of and how is it weighted" without scrolling past fifty formula
   fields to find out. */
.catgrid { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.catgrid th, .catgrid td {
  padding: 7px var(--cell-x); text-align: left;
  border-bottom: 1px solid var(--line-2);
}
.catgrid thead th {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 600;
}
.catgrid tbody tr:last-child th, .catgrid tbody tr:last-child td { border-bottom: 0; }
.catgrid td.r, .catgrid th.r { text-align: right; }
.catgrid .subcount { color: var(--ink-3); font-size: 12.5px; }
/* Shown instead of the category table, so it is a sibling of .catgrid and
   never a descendant -- as .catgrid .nocats it matched nothing and the
   paragraph sat flush against the card border while everything around it was
   inset. */
.nocats {
  padding: 12px var(--cell-x); font-size: 13px; color: var(--ink-3); margin: 0;
}

/* A factor's sub-factors, on their own panel. The card header names the factor
   and what its groups add up to; the formulas are the content. */
.sfcard-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px 20px; flex-wrap: wrap; padding: 12px var(--cell-x);
  border-bottom: 1px solid var(--line-2);
}
.sfcard-head h3 { margin: 0; font-size: 14.5px; }
.sfcard-head .mono { font-size: 12px; }

/* The do-not-buy lists a stage holds. A relation, not a setting, so it sits
   below the settings grid rather than inside it: the grid's auto-fit columns
   are sized for short numeric boxes, and a column of list names laid into one
   of those tracks wrapped every name onto its own pair of lines. */
.stagecard-lists {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line-2);
  display: grid; gap: 7px;
}
.stagecard-lists .listcap {
  margin: 0;
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
/* A stage that refuses to run until someone picks its list. Stated where the
   picking happens — the run log says the same thing, but the reader who can
   fix it is on this page. */
.listwarn {
  margin: 0; padding: 7px 10px;
  font-size: 12.5px; line-height: 1.45; color: var(--warn);
  background: var(--warn-bg);
  border: 1px solid var(--warn-line); border-radius: 4px;
}
