/*
 * style.css — minimal styling for the PMV static pipeline shell (T-020 scaffold).
 *
 * Purpose: legible, uncluttered presentation of the shell chrome (header, pipeline nav,
 *   content region, footer) and the placeholder stage views. Low visual load per HFE-Mayer
 *   (C-013): one accent colour, generous whitespace, a single readable content column, and
 *   a clear active-stage affordance.
 *
 * Contract: pure presentation. No @import, no web-font fetch, no external URL of any kind
 *   (static-first; C-012 / KDL-008). System font stack only.
 * Constraints honored: C-012 (no external asset/runtime), C-013 (HFE-Mayer),
 *   C-019/C-021 (this docstring plus why-comments on the non-obvious rules).
 */

/* Design tokens. Deliberately few — one accent plus a small neutral ramp — so the shell
   stays low-load and a later task can restyle it without hunting hex codes. */
:root {
  --pmv-accent: #2f5d8a;
  --pmv-accent-weak: #eaf1f8;
  --pmv-ink: #1c2530;
  --pmv-ink-soft: #55606c;
  --pmv-line: #d7dde4;
  --pmv-bg: #ffffff;
  --pmv-note-bg: #fbf7ec;
  --pmv-note-line: #e3d4a8;
  --pmv-max-width: 46rem;
  --pmv-radius: 8px;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  /* System font stack: zero network fetch, native look on hospital Chrome/Edge. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  line-height: 1.55;
  color: var(--pmv-ink);
  background: var(--pmv-bg);
}

/* One centred column bounds line length for readability (HFE-Mayer). */
.app-header,
.pipeline-nav,
.app-content,
.app-footer { max-width: var(--pmv-max-width); margin-inline: auto; padding-inline: 1.25rem; }

.app-header { padding-top: 2rem; }
.app-title { margin: 0; font-size: 1.5rem; letter-spacing: 0.01em; }
.app-subtitle { margin: 0.25rem 0 0; color: var(--pmv-ink-soft); font-size: 0.95rem; }

/* Pipeline nav: a horizontal, ordered strip. The list resets remove default list chrome;
   flex-wrap keeps the four stages usable on a narrow window. */
.pipeline-nav { margin-top: 1.5rem; border-bottom: 1px solid var(--pmv-line); }
.pipeline-stages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}
.stage-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 0.9rem;
  text-decoration: none;
  color: var(--pmv-ink-soft);
  border-bottom: 3px solid transparent; /* reserve the active underline so nothing shifts */
  border-radius: var(--pmv-radius) var(--pmv-radius) 0 0;
  font-size: 0.95rem;
}
.stage-link:hover { color: var(--pmv-ink); background: var(--pmv-accent-weak); }

/* Active stage: the router sets .is-active + aria-current on the current link. Both the
   colour and the underline change so the cue never relies on colour alone. */
.stage-link.is-active {
  color: var(--pmv-accent);
  border-bottom-color: var(--pmv-accent);
  font-weight: 600;
}
.stage-link:focus-visible { outline: 2px solid var(--pmv-accent); outline-offset: 2px; }

/* The numeric step marker in each nav link. */
.stage-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--pmv-accent-weak);
  color: var(--pmv-accent);
  font-size: 0.8rem;
  font-weight: 600;
}

.app-content { padding-top: 1.75rem; padding-bottom: 2.5rem; min-height: 12rem; }

/* Stage view: one idea per screen. Badge -> title -> lede -> task note, top to bottom. */
.stage-badge {
  display: inline-block;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--pmv-accent);
  background: var(--pmv-accent-weak);
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
}
.stage-title { margin: 0.6rem 0 0.4rem; font-size: 1.4rem; }
.stage-lede { margin: 0 0 1rem; color: var(--pmv-ink); }

/* Task note: the "this is a placeholder, task T-0XX wires it" callout. Visually distinct so
   nobody mistakes a scaffold view for working functionality. */
.stage-note {
  margin: 0;
  padding: 0.85rem 1rem;
  background: var(--pmv-note-bg);
  border: 1px solid var(--pmv-note-line);
  border-left-width: 4px;
  border-radius: var(--pmv-radius);
  font-size: 0.92rem;
}

code {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 0.88em;
  background: #f2f4f7;
  padding: 0.05rem 0.3rem;
  border-radius: 4px;
}

.app-footer { border-top: 1px solid var(--pmv-line); padding-top: 1rem; padding-bottom: 2rem; }
.app-footer-note { margin: 0; color: var(--pmv-ink-soft); font-size: 0.85rem; }

/* =====================================================================================
   T-021 — styles for the wired Upload and Verify stages. APPENDED ONLY; nothing above
   this line was altered. Everything here stays inside the token palette declared at the
   top, plus the three outcome tokens below.
   ===================================================================================== */

/* Three new tokens, and only three: a success green, a failure red, and a caution amber.
   They tint outcome badges and status lines. They are NEVER the only signal — every badge
   and every status line states its meaning in words as well, so the page reads correctly
   in monochrome and for a colour-blind reviewer (and so a printed manifest review is not
   degraded). */
:root {
  --pmv-ok: #1d6b3f;
  --pmv-fail: #a32218;
  --pmv-caution: #8a5a08;
}

/* --- Buttons ------------------------------------------------------------------------
   .btn is the shared shape; the two modifiers carry emphasis. <a class="btn"> is styled
   identically to <button class="btn"> so "Continue to Verify →" (a real link, so it is
   navigable and bookmarkable) looks like the action it is. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 0.95rem;
  border-radius: var(--pmv-radius);
  border: 1px solid var(--pmv-accent);
  font: inherit;
  font-size: 0.95rem;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
}
.btn-primary { background: var(--pmv-accent); border-color: var(--pmv-accent); color: #fff; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-secondary { background: var(--pmv-bg); color: var(--pmv-accent); }
.btn-secondary:hover { background: var(--pmv-accent-weak); }

/* Disabled: dimmed AND non-interactive. The run button is disabled while a verification
   is in flight, so this state must be unmistakable — a second click would spend more of
   the free-tier request budget. */
.btn:disabled,
.btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  filter: none;
}

/* Keyboard focus must be at least as visible as hover — the whole shell is operable by
   keyboard, and the router deliberately moves focus on every route change. */
.btn:focus-visible { outline: 2px solid var(--pmv-ink); outline-offset: 2px; }

/* The stage heading receives programmatic focus on route change (tabindex="-1"). Show a
   quiet outline so a sighted keyboard user can see where focus landed. */
.stage-title:focus-visible { outline: 2px solid var(--pmv-accent); outline-offset: 4px; }

.action-row { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 1rem 0; align-items: center; }

/* --- Form fields --------------------------------------------------------------------- */
.field-row { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; margin: 0.75rem 0; }
.field-block { margin: 1.25rem 0; }
.field-label,
.file-label { display: inline-block; font-weight: 600; font-size: 0.92rem; margin-bottom: 0.25rem; }
.field-caption { margin: 0.3rem 0 0; color: var(--pmv-ink-soft); font-size: 0.85rem; }

.file-input,
.text-input {
  font: inherit;
  font-size: 0.95rem;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--pmv-line);
  border-radius: var(--pmv-radius);
  background: var(--pmv-bg);
  color: var(--pmv-ink);
  max-width: 100%;
}
.text-input { width: 22rem; }
.file-input:focus-visible,
.text-input:focus-visible { outline: 2px solid var(--pmv-accent); outline-offset: 1px; }

.file-summary { margin: 0.75rem 0 0.25rem; font-size: 0.92rem; }

/* --- Status / progress lines ---------------------------------------------------------
   These are the role="status" live regions. They are always present in the DOM (empty
   until there is something to say) so assistive tech has a stable node to watch; the
   border-left is what makes an outcome legible at a glance without relying on colour. */
.status-line {
  margin: 1rem 0 0.5rem;
  padding: 0.55rem 0.8rem;
  border-left: 4px solid var(--pmv-line);
  background: #f7f9fb;
  border-radius: 0 var(--pmv-radius) var(--pmv-radius) 0;
  font-size: 0.95rem;
  min-height: 1.2rem;
}
.status-line:empty { display: none; }
.status-line.is-ok { border-left-color: var(--pmv-ok); color: var(--pmv-ok); }
.status-line.is-error { border-left-color: var(--pmv-fail); color: var(--pmv-fail); }
.progress-line { font-variant-numeric: tabular-nums; }

/* --- Error lists ---------------------------------------------------------------------
   Schema errors are quoted verbatim from the validator and can be long; wrap rather than
   truncate. Truncating a validation message would hide the value that failed. */
.errors-list {
  margin: 0.75rem 0;
  padding-left: 1.2rem;
  font-size: 0.9rem;
  color: var(--pmv-fail);
}
.errors-list li { margin-bottom: 0.35rem; overflow-wrap: anywhere; }
.errors-list code { background: #f7ecea; color: var(--pmv-fail); }

/* --- Tables --------------------------------------------------------------------------
   Manifests can carry long titles and many columns. The wrapper scrolls horizontally so
   a narrow window never clips a verdict off-screen or forces the whole page sideways. */
.table-wrap {
  overflow-x: auto;
  margin: 1rem 0;
  border: 1px solid var(--pmv-line);
  border-radius: var(--pmv-radius);
}
.entries-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.88rem;
}
.entries-table th,
.entries-table td {
  text-align: left;
  vertical-align: top;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--pmv-line);
}
.entries-table thead th {
  background: var(--pmv-accent-weak);
  color: var(--pmv-accent);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}
.entries-table tbody tr:last-child td { border-bottom: none; }
/* Titles get room; the compact field-comparison column must not wrap mid-verdict. */
.entries-table .col-title { min-width: 16rem; }
.entries-table .col-fields { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* --- Classification badges -----------------------------------------------------------
   One modifier per terminal class (seven, matching the frozen schema enum). The BADGE
   TEXT always names the class — the colour is redundant reinforcement, never the message.
   Grouped by meaning: verified family green, failure family red, "look again" family
   amber, could-not-verify neutral (C-017: absence is not a fabrication verdict, so it
   must not be styled like one). */
.cls-badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  border: 1px solid var(--pmv-line);
  background: #f2f4f7;
  color: var(--pmv-ink);
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
}
.cls-verified,
.cls-verified-ahead-of-print { border-color: var(--pmv-ok); color: var(--pmv-ok); background: #eef6f1; }
.cls-verified-ambiguous,
.cls-version-near-miss { border-color: var(--pmv-caution); color: var(--pmv-caution); background: #fbf5e9; }
.cls-failed-mangled,
.cls-failed-confabulated { border-color: var(--pmv-fail); color: var(--pmv-fail); background: #fbeeed; }
.cls-could-not-verify { border-color: var(--pmv-ink-soft); color: var(--pmv-ink-soft); background: #f2f4f7; }

/* --- Run report ----------------------------------------------------------------------
   A responsive grid of small blocks: classification counts, network/rate log, contract
   check, timing. auto-fit keeps it one column on a phone without a media query. */
.report-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.9rem;
  margin: 0.75rem 0 1rem;
}
.report-block {
  border: 1px solid var(--pmv-line);
  border-radius: var(--pmv-radius);
  padding: 0.8rem 0.9rem;
  background: var(--pmv-bg);
}
.report-block p { margin: 0.25rem 0; font-size: 0.9rem; }
.block-title {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--pmv-ink-soft);
}
.count-list,
.readiness-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.88rem;
}
.count-list li,
.readiness-list li {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.15rem 0;
  border-bottom: 1px dotted var(--pmv-line);
  overflow-wrap: anywhere;
}
.count-list li:last-child,
.readiness-list li:last-child { border-bottom: none; }

/* The "(consulted by this run)" / "(supplementary — not consulted)" qualifier beside each
   source name. Quieter than the name, but always present: readiness alone must never be
   mistaken for evidence that a source was actually asked. */
.readiness-role { color: var(--pmv-ink-soft); font-size: 0.78rem; }

/* --- Per-entry detail disclosure ------------------------------------------------------
   Collapsed by default so the table stays scannable; the full note and the nine
   resolvedMetadata fields are one click away for anyone auditing a verdict. */
.entry-details { font-size: 0.86rem; }
.entry-details > summary {
  cursor: pointer;
  color: var(--pmv-accent);
  font-weight: 600;
  list-style-position: outside;
}
.entry-details > summary:focus-visible { outline: 2px solid var(--pmv-accent); outline-offset: 2px; }
.entry-details[open] > summary { margin-bottom: 0.4rem; }
.entry-note { margin: 0.25rem 0 0.5rem; max-width: 34rem; }

/* Definition list of the resolved record. Two columns so field names and values line up;
   null values render as an em dash, which must be as visible as any other value. */
.field-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.15rem 0.75rem;
  margin: 0.25rem 0 0.5rem;
  max-width: 34rem;
}
.field-grid dt { color: var(--pmv-ink-soft); font-size: 0.8rem; }
.field-grid dd { margin: 0; overflow-wrap: anywhere; }

/* =====================================================================================
   T-022 — styles for the wired Attest stage. APPENDED ONLY; nothing above this line was
   altered. The stage reuses the existing vocabulary wherever it can (.report-grid,
   .report-block, .count-list, .status-line, .errors-list, .btn, .field-block), so only
   three additions are needed.
   ===================================================================================== */

/* A third status tone beside is-ok and is-error. "Caution" means the merge SUCCEEDED but
   the citation work is not finished — rows are pending or await re-verification. It must
   not look like a failure (the round-trip worked) and must not look like a clean pass
   (something still has to be done). As everywhere else, the amber is reinforcement: the
   status line always says in words which rows are outstanding. */
.status-line.is-caution { border-left-color: var(--pmv-caution); color: var(--pmv-caution); }

/* The re-verification warning. Same amber, given a full box rather than a left rule
   because it carries an instruction and a list of entry ids, not a one-line outcome. The
   heading text inside states the requirement outright, so a monochrome print-out or a
   colour-blind reviewer loses nothing. */
.warn-note {
  margin: 1rem 0;
  padding: 0.85rem 1rem;
  border: 1px solid var(--pmv-caution);
  border-left-width: 4px;
  border-radius: var(--pmv-radius);
  background: #fbf5e9;
  font-size: 0.92rem;
}
.warn-note p { margin: 0.35rem 0; }
.warn-note code { background: #f6ecd8; color: var(--pmv-caution); overflow-wrap: anywhere; }

/* The step-1 instructions the human follows outside this tab. A real <ol>: the four steps
   are a sequence performed in order, and the numbers are the point. */
.steps-list {
  margin: 0.5rem 0 1.5rem;
  padding-left: 1.4rem;
  font-size: 0.92rem;
  max-width: 40rem;
}
.steps-list li { margin-bottom: 0.35rem; }

/* The summary panel's heading takes programmatic focus after a merge repaints the stage
   body (tabindex="-1"), so it needs the same visible landing marker as the stage title —
   a keyboard user must be able to SEE where focus went. */
.summary-title:focus-visible { outline: 2px solid var(--pmv-accent); outline-offset: 4px; }

.stage-results { margin-top: 0.5rem; }

/* =====================================================================================
   T-021.5 — styles for the Compare stage (the pentad's compare leg). APPENDED ONLY;
   nothing above this line was altered. The stage reuses the existing vocabulary almost
   entirely (.entries-table, .table-wrap, .report-grid, .report-block, .count-list,
   .status-line, .errors-list, .btn, .field-block, .stage-note), so this block is three
   small additions: a multi-line question field, the counts table's numeric column, and
   the notes list.
   ===================================================================================== */

/* The question field is a <textarea> because a real clinical question runs past one line
   and must be readable in full while it is being typed — a single-line input that scrolls
   its own text sideways invites a truncated question, and the question is what the whole
   downstream triage step judges scope against. It inherits .text-input's chrome; only the
   height, width, and resize behaviour differ. */
.textarea-input {
  width: 100%;
  max-width: 34rem;
  min-height: 4.5rem;
  resize: vertical;
  line-height: 1.45;
}

/* The counts table is two columns, not six: a label and a number. Right-aligning and
   tabular-figuring the number column makes the magnitudes comparable down the column at a
   glance, which is the only reading anyone does of a bucket list. The label column is
   allowed to wrap (these labels say what each count MEANS and must not be clipped). */
.counts-table .col-count {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.counts-table td:first-child { min-width: 18rem; }

/* The run's note lines: the pipeline's own sentences plus the two standing caveats. A
   plain list, full sentences, no truncation — each line is a caveat about how the numbers
   above should be read, so hiding or shortening one defeats its purpose. */
.notes-list {
  margin: 0.5rem 0 1rem;
  padding-left: 1.2rem;
  font-size: 0.9rem;
  max-width: 40rem;
}
.notes-list li { margin-bottom: 0.35rem; overflow-wrap: anywhere; }

/* =====================================================================================
   T-023 — styles for the Keys & lanes utility page and the utility nav link. APPENDED
   ONLY; nothing above this line was altered. The page reuses the existing vocabulary
   almost entirely (.stage-view, .block-title, .status-line, .table-wrap, .entries-table,
   .counts-table, .btn, .field-block, .field-label, .field-caption, .action-row), so this
   block is four small additions: the unnumbered nav link, the key rows, the caps grid,
   and the presence indicator.
   ===================================================================================== */

/* The nav becomes a flex row so the utility link can sit on the same line as the numbered
   stage list and be pushed to the far end. Declared here rather than edited into the
   original .pipeline-nav rule so the T-020 block above stays byte-identical. */
.pipeline-nav { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.25rem; }
.pipeline-stages { flex: 0 1 auto; }

/* The utility link carries no step number and is set apart from the numbered sequence — a
   divider on its left, a quieter colour, pushed to the trailing edge. The separation is the
   message: Keys & lanes is a settings page, not a sixth step (C-009/C-010 — a run needs no
   keys at all). It keeps .stage-link's shape, hover, focus ring, and active underline, so
   the router's is-active handling needs no special case. */
.utility-link {
  margin-left: auto;
  border-left: 1px solid var(--pmv-line);
  padding-left: 0.9rem;
  color: var(--pmv-ink-soft);
  font-size: 0.9rem;
}

/* --- The key slots ------------------------------------------------------------------- */

/* Each settings region is a bordered card, like a .report-block, so the four ideas on this
   page (keys, remembering them, lane status, caps) read as four separate decisions rather
   than one long form. */
.keys-block {
  border: 1px solid var(--pmv-line);
  border-radius: var(--pmv-radius);
  padding: 0.9rem 1rem;
  margin: 1.25rem 0;
}
.keys-block p { font-size: 0.92rem; }

/* One slot: label, then the one-line purpose, then the controls. A grid rather than a flex
   row because the purpose line must sit directly under its own label — pairing a benefit
   with the wrong key is how someone ends up registering for something they did not need. */
.key-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.1rem;
  padding: 0.6rem 0;
  border-bottom: 1px dotted var(--pmv-line);
}
.key-row:last-of-type { border-bottom: none; }
.key-purpose { margin: 0 0 0.35rem; }
.key-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
/* Narrower than the default .text-input: an API key box does not need 22rem, and a shorter
   field leaves the Set button and the presence indicator on the same line at normal widths. */
.key-input { width: 18rem; }

/* The presence indicator. It shows "set (in memory)" or "not set" and NEVER a key value —
   the text is the whole signal, and the colour is redundant reinforcement, so the page
   reads identically in monochrome. */
.key-status {
  font-size: 0.85rem;
  color: var(--pmv-ink-soft);
  white-space: nowrap;
}
.key-status.is-set { color: var(--pmv-ok); font-weight: 600; }

/* --- The caps editor ------------------------------------------------------------------ */

/* Label/field pairs: a label column sized to its longest lane name, and a fixed narrow
   number column. Ten lanes therefore read as ten short rows rather than ten full-width
   ones, and the numbers line up in a single column so a reader can compare the caps down
   the page at a glance. max-content on the label column means no lane name is ever
   clipped — a truncated lane name beside an editable number is how someone caps the
   wrong lane. */
.caps-grid {
  display: grid;
  grid-template-columns: max-content 6rem;
  gap: 0.35rem 0.75rem;
  align-items: center;
  margin: 0.75rem 0;
}
.caps-grid .field-label { margin-bottom: 0; font-weight: 400; font-size: 0.9rem; }
.num-input { width: 6rem; font-variant-numeric: tabular-nums; }

/* The lane table's own panel spacing; the table itself is a plain .entries-table. */
.lane-panel { margin: 1.25rem 0; }

/* =====================================================================================
   T-027 — styles for the Roster de-identify utility page. APPENDED ONLY; nothing above
   this line was altered. The page reuses the existing vocabulary almost entirely
   (.stage-view, .stage-note, .keys-block, .block-title, .status-line, .errors-list,
   .notes-list, .table-wrap, .entries-table, .textarea-input, .btn, .field-block,
   .field-label, .field-caption, .action-row), so this block is two small additions the
   review table needs and nothing else.
   ===================================================================================== */

/* The context column shows the matched name inside the surrounding words — that snippet IS
   the evidence the reviewer decides on, so it must wrap in full rather than be clipped, and
   it is set smaller so a six-column table still fits the one-column layout. */
.roster-context {
  font-size: 0.85rem;
  min-width: 14rem;
  overflow-wrap: anywhere;
}

/* The accept cell: a checkbox and its label on one line. Every checkbox carries a real
   <label for>, and the label's text is the candidate NUMBER — never the name — so a screen
   reader announcing the control alone still says which row it belongs to without reading a
   real person's name aloud. It is quiet and small because the row's own columns repeat it. */
/* Amended 2026-09-03 (Codex gate review): the label now also carries the occurrence position
   and the risk ("CAND-001 · match 2 of 4 · initial"), so it is no longer a short token and
   must be allowed to wrap — nowrap on that cell would have stretched the accept column wide
   enough to push the context column off the table. A min-width keeps the checkbox and the
   first line of its label together. */
.roster-accept { min-width: 10rem; }
.roster-accept-label {
  margin-left: 0.3rem;
  font-size: 0.8rem;
  color: var(--pmv-ink-soft);
  font-variant-numeric: tabular-nums;
}

/* Added 2026-09-03 (Codex second-round review): the number picker an AMBIGUOUS row carries.
   It sits under the checkbox rather than beside it, because it is a second decision about
   the same row — which number to write — and a control on its own line is not mistaken for
   part of the label above it. Tabular figures so CAND-001 and CAND-002 line up. */
.roster-choice { margin-top: 0.3rem; }
.roster-number-choice {
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  max-width: 100%;
}
