/*
 * Inspectorial UI — texture per ADR-0013 (c).
 * Reference: GitHub Actions runs page (table density, status icons, two-pane
 * drill-down). Explicitly NOT analytical-dashboard texture.
 *
 * Color system: neutral grays + status-driven accent colors. No iGaming-shaped
 * brand palette.
 */

:root {
  --color-fg: #1f2328;
  --color-fg-muted: #656d76;
  --color-bg: #ffffff;
  --color-bg-subtle: #f6f8fa;
  --color-bg-hover: #eaeef2;
  --color-border: #d0d7de;
  --color-border-muted: #d8dee4;
  --color-accent: #0969da;
  --color-accent-fg: #ffffff;
  --color-success: #1a7f37;
  --color-success-bg: #dcffe4;
  --color-danger: #cf222e;
  --color-danger-bg: #ffebe9;
  --color-warning: #9a6700;
  --color-warning-bg: #fff8c5;
  --color-error: #82071e;
  --color-error-bg: #ffebe9;

  /* Navy top bar (#1446). Dark chrome; light text/links against it. */
  --color-navy: #12294d;
  --color-navy-edge: #0c1c38;
  --color-navy-fg: #dbe4f0;
  --color-navy-muted: #93a6c4;
  --color-navy-link: #a9c7f5;

  --radius: 6px;
  --radius-sm: 3px;

  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;

  /* ─── Type scale (#1553, DoD item 22; retuned) ─────────────────────────
     Root history: 14px (pre-v2, too small — everything read as a dense
     admin panel) → 17.5px (#1553, overshot: the console read as a slide
     deck and cost real rows per screen) → 16px now. 16 is the browser
     default and the standard app root: comfortably larger than the 14px
     we started from, without spending a third of the viewport on type.

     Only the ROOT moves. Every rung is a 1.125 (major-second) step in rem,
     so the whole ladder rescales from this one line and keeps its
     proportions — that is the property that made this retune a one-token
     change rather than a sweep.

     Sizes are TOKENS ONLY — no bare `font-size: Npx` anywhere in this file
     except the two `.gar-score` SVG rules below, whose numbers are viewBox user
     units (a rem there would be measured against the root and blow the ring
     apart). Old px → rung, for reading diffs against pre-v2 CSS:
       9/9.5/10/10.5 → 3xs · 11/11.5 → 2xs · 12/12.5 → xs · 13 → sm
       14 → md (root) · 15/16 → lg · 17/18 → xl · 20/22 → 2xl · 24 → 3xl */
  --text-root: 16px;
  --text-3xs: 0.64rem;   /* 10.2px */
  --text-2xs: 0.72rem;   /* 11.5px */
  --text-xs: 0.81rem;    /* 13.0px */
  --text-sm: 0.911rem;   /* 14.6px — dominant table/body rung */
  --text-md: 1rem;       /* 16.0px — root */
  --text-lg: 1.125rem;   /* 18.0px */
  --text-xl: 1.266rem;   /* 20.3px */
  --text-2xl: 1.424rem;  /* 22.8px */
  --text-3xl: 1.602rem;  /* 25.6px — page h1 */

  /* ─── Frame geometry (#1553, DoD item 23) ──────────────────────────────
     One column definition shared by the top bar, the content pane and the
     footer, so all three land on the same left/right edge at any width. The
     sidebar is the frame's first column, NOT part of any centring maths —
     the FRAME centres, the pane never does. */
  --frame-max: 1400px;
  --gutter: 24px;
  /* 216 → 244 when the root hit 17.5px (labels were wrapping) → 224 now the
     root is back to 16px. The rail is chrome: every px it gives back is a px
     the content pane gets, and nothing in it wraps at this width. */
  --sidebar-w: 224px;
}

* { box-sizing: border-box; }

/* The rem anchor. Must be a length, not `1rem` — on the root element `rem`
   resolves against the browser default (16px), not against this rule. */
html { font-size: var(--text-root); }

body {
  margin: 0; padding: 0;
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--color-fg);
  background: var(--color-bg);
}

code, pre { font-family: var(--font-mono); font-size: 0.92em; }
pre {
  background: var(--color-bg-subtle);
  padding: 0.75em;
  border-radius: var(--radius);
  border: 1px solid var(--color-border-muted);
  overflow-x: auto;
  margin: 0.5em 0;
}

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

.muted { color: var(--color-fg-muted); }
.break-all { word-break: break-all; }

/* ─── Navy top bar (#1446) ───────────────────────────────────────────── */
/* Full-width navy bar: brand mark (left), centred platform title, and a
   top-right cluster (view-as · workspace · Account · Sign out). The operator
   view-as switcher is injected into the cluster by view-as-chrome.ts. */

.app-frame { display: flex; flex-direction: column; min-height: 100vh; }

.app-topbar {
  background: var(--color-navy);
  color: var(--color-navy-fg);
  border-bottom: 1px solid var(--color-navy-edge);
}
.app-topbar-inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 16px;
  /* Same column as .app-shell → the mark sits on the sidebar's text edge and
     the right-hand cluster lands on the content's right edge (item 23). The
     navy background stays full-bleed; only the inner content is constrained. */
  max-width: var(--frame-max);
  margin: 0 auto;
  padding: 9px var(--gutter);
}
.topbar-mark { color: #fff; font-size: var(--text-lg); font-weight: 700; line-height: 1; }
.topbar-mark:hover { text-decoration: none; }
.topbar-title {
  grid-column: 2;
  text-align: center;
  font-size: var(--text-lg);
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
}
.topbar-title:hover { text-decoration: none; }
.topbar-right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  font-size: var(--text-xs);
  flex-wrap: wrap;
}
.topbar-right a { color: var(--color-navy-link); }
/* The workspace pill that used to live here is gone — the Client ▸ Brand
   breadcrumb (.wsbc, below) replaced it in #1554. */
.topbar-account { font-weight: 500; }
.topbar-signout { color: var(--color-navy-muted); }

/* Narrow viewports: let the title drop its centring and the cluster wrap. */
@media (max-width: 720px) {
  .app-topbar-inner { grid-template-columns: auto auto; row-gap: 8px; }
  .topbar-title { grid-column: 1 / -1; grid-row: 2; text-align: left; white-space: normal; }
  .topbar-right { grid-column: 1 / -1; grid-row: 3; justify-content: flex-start; }
  /* Links-table actions: stack the Run now / Pause controls so the column
   * collapses to one-button width instead of sliding off the right edge
   * (#1446 Q2). The table-wrap keeps overflow-x:auto as a backstop. The column
   * is a flex container since #1557, so stacking is a direction flip. */
  .actions-col { white-space: normal; min-width: 0; }
  .row-actions { flex-direction: column; align-items: flex-end; }
  /* Page-header action cluster (+ Add a link / Import / Bulk edit / Workspace
   * configuration): stack the header vertically and let the button cluster wrap,
   * instead of forcing page-level horizontal scroll. The Q2 rule above only
   * stacked the per-row .actions-col; this handles the header cluster's own
   * overflow (#1464). align-items:stretch forces the cluster to the full row
   * width so its buttons actually wrap (a plain flex-wrap leaves it sized to
   * content). CSS-only, same "small responsive tidy" scope. */
  .links-header { flex-direction: column; align-items: stretch; }
  .links-header-actions { flex-wrap: wrap; }
}

/* Content fills its pane and takes the frame's gutter — it does NOT centre
   inside the pane. Centring the pane (a viewport minus a 240px rail) is what
   pushed content off the bar's axis; the frame centres instead (item 23). */
.app-main {
  padding: var(--gutter);
}

/* Shell-less pages (root list, operator console, error pages) put .app-main
   and the footer directly under .app-frame, so they carry the frame column
   themselves — same edges as the sidebar shell. */
.app-frame > .app-main,
.app-frame > .app-footer {
  width: 100%;
  max-width: var(--frame-max);
  margin-left: auto;
  margin-right: auto;
}

/* ─── Page header ────────────────────────────────────────────────────── */

.page-header { margin-bottom: 24px; }
.page-header h1 { margin: 0 0 4px 0; font-size: var(--text-3xl); font-weight: 600; }
.page-header .muted { font-size: var(--text-sm); }
.page-header-row { display: flex; align-items: center; gap: 12px; }

/* ─── Buttons ─────────────────────────────────────────────────────────── */

.btn {
  display: inline-block;
  padding: 6px 14px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  line-height: 1.5;
}
.btn:hover { text-decoration: none; }
.btn-primary {
  background: var(--color-accent);
  color: var(--color-accent-fg);
  border-color: var(--color-accent);
}
.btn-primary:hover { filter: brightness(0.9); }
.btn-secondary {
  background: var(--color-bg-subtle);
  color: var(--color-fg);
  border-color: var(--color-border);
}
.btn-secondary:hover { background: var(--color-bg-hover); }

/* ─── Status icons + badges ──────────────────────────────────────────── */

.status-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: var(--text-md);
  font-weight: 700;
}

.badge {
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border-muted);
}
.badge-pass, .badge-final { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success); }
.badge-fail, .badge-errored { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger); }
.badge-pending, .badge-partial { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }
.badge-not_evaluated { background: var(--color-bg-subtle); color: var(--color-fg-muted); border-color: var(--color-border-muted); }
.badge-not_applicable { background: var(--color-bg-subtle); color: var(--color-fg-muted); border-color: var(--color-border-muted); }
.badge-complete { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success); }
/* insights_status axis (#1472, JD-11). `skipped` + `not enabled` are neutral —
   they are statements about whether the insight lane looked at the audit, never
   about the audit's quality, so they must not borrow verdict colours. */
.badge-skipped, .badge-not_enabled { background: var(--color-bg-subtle); color: var(--color-fg-muted); border-color: var(--color-border-muted); }
/* Persisted-headline badge (#607, ADR-0024 06-10b) — OK/WARN/FAIL vocabulary. */
.badge-headline-OK { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success); }
.badge-headline-WARN { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }
.badge-headline-FAIL { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger); }

.provenance-chip {
  display: inline-block;
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
  font-size: 0.85em;
  color: var(--color-fg-muted);
  white-space: nowrap;
}

/* ─── Recent failures widget ─────────────────────────────────────────── */

.failures-widget {
  background: var(--color-danger-bg);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 24px;
}
.failures-widget h2 { margin: 0 0 8px 0; font-size: var(--text-md); color: var(--color-danger); }
.failures-widget ul { list-style: none; padding: 0; margin: 0; }
.failures-widget li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 0;
  font-size: var(--text-sm);
}
.failure-count {
  margin-left: auto;
  color: var(--color-danger);
  font-weight: 500;
  font-size: var(--text-xs);
}

/* ─── Empty state ────────────────────────────────────────────────────── */

.empty-state {
  text-align: center;
  padding: 48px 24px;
  background: var(--color-bg-subtle);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
}
.empty-state p { margin-bottom: 16px; color: var(--color-fg-muted); }

/* ─── Audit table (list view) ────────────────────────────────────────── */

.audit-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.audit-table thead th {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--color-border);
  font-weight: 600;
  color: var(--color-fg-muted);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.audit-table tbody tr { border-bottom: 1px solid var(--color-border-muted); }
.audit-table tbody tr:hover { background: var(--color-bg-subtle); }
.audit-table td { padding: 10px 12px; vertical-align: middle; }

.col-status { width: 32px; }
.col-audit-id { width: 120px; }
.col-stages { font-variant-numeric: tabular-nums; }
.col-provenance { white-space: nowrap; }

.stage-fraction {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

/* ─── Drill-down two-pane ─────────────────────────────────────────────── */

.drill-grid {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) 2fr;
  gap: 24px;
  margin-top: 24px;
}
@media (max-width: 900px) {
  .drill-grid { grid-template-columns: 1fr; }
}

.stage-panel, .evidence-panel {
  background: var(--color-bg);
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius);
  padding: 16px;
}
.stage-panel h2, .evidence-panel h2 {
  margin: 0 0 12px 0;
  font-size: var(--text-md);
  color: var(--color-fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.status-axes {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding: 12px 16px;
  background: var(--color-bg-subtle);
  border-radius: var(--radius);
  font-size: var(--text-xs);
}

.polling-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: #b54708;
  font-weight: 500;
}
.polling-indicator .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #b54708;
  animation: polling-pulse 1.6s ease-in-out infinite;
}
@keyframes polling-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.8); }
}

.failure-reason {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius);
  padding: 8px 12px;
  font-size: var(--text-sm);
  margin: 12px 0;
}

/* ─── First-level diagnosis block (#831) ──────────────────────────────────
   The decisive-finding headline at the top of the drill-down. Severity-tinted
   left border; the inconclusive (our-side errored) tier is grey, never red. */
.diagnosis-block {
  border: 1px solid var(--color-border-muted);
  border-left-width: 3px;
  border-radius: var(--radius);
  padding: 10px 14px;
  margin: 12px 0;
  background: var(--color-bg-subtle);
}
.diagnosis-audit_ending, .diagnosis-stage_blocking { border-left-color: var(--color-danger); }
.diagnosis-non_blocking { border-left-color: var(--color-warning); }
.diagnosis-inconclusive, .diagnosis-unknown { border-left-color: #8c959f; }
.diagnosis-headline { margin: 0 0 6px 0; font-weight: 600; font-size: var(--text-lg); }
.diagnosis-code { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--color-fg-muted); font-weight: 400; }
.diagnosis-detail { margin: 4px 0; font-size: var(--text-sm); }

/* ─── Stages list ─────────────────────────────────────────────────────── */

.stages-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.stage {
  border-bottom: 1px solid var(--color-border-muted);
}
.stage:last-child { border-bottom: 0; }
.stage details { padding: 8px 0; }
.stage summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-sm);
  list-style: none;
}
.stage summary::-webkit-details-marker { display: none; }
.stage-key { font-family: var(--font-mono); font-weight: 600; }
.stage-name { font-size: var(--text-xs); }
.reason-codes { display: inline-flex; gap: 4px; margin-left: auto; }
.stage-detail { padding: 8px 0 8px 26px; font-size: var(--text-xs); }
.stage-data summary { font-size: var(--text-xs); cursor: pointer; }

.skipped-stages {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border-muted);
  font-size: var(--text-xs);
}
.skipped-stages h3 { margin: 0 0 8px 0; font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.stages-skipped { list-style: none; padding: 0; margin: 0; }
.stages-skipped .stage { padding: 6px 0; border-bottom: 1px dashed var(--color-border-muted); }
.stages-skipped .stage:last-child { border-bottom: 0; }

/* Skipped (per-shape) stages: dimmed + slashed for visual distinction from
   traversed-with-verdict stages (pass/fail/pending) and from traversed-but-
   not_evaluated stages. Stage 19 platform-scope skip, stages 1-9 promo_code
   shape-level skip — same visual treatment per ADR-0009 verdict-state inventory. */
.stage-not_applicable {
  color: var(--color-fg-muted);
  opacity: 0.7;
}
.stage-not_applicable .stage-key { text-decoration: line-through; }
.stage-not_applicable .stage-summary {
  display: flex;
  align-items: center;
  gap: 8px;
}
.stage-icon-not_applicable {
  display: inline-flex;
  width: 16px;
  height: 16px;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

/* ─── Evidence sections ──────────────────────────────────────────────── */

.evidence-section {
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--color-border-muted);
}
.evidence-section:last-child { border-bottom: 0; padding-bottom: 0; }
.evidence-section summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--text-sm);
  padding: 4px 0;
}

.hops-table, .cookies-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-xs);
  margin-top: 8px;
}
.hops-table th, .cookies-table th {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--color-border);
  font-weight: 600;
  color: var(--color-fg-muted);
}
.hops-table td, .cookies-table td {
  padding: 6px 8px;
  border-bottom: 1px solid var(--color-border-muted);
  vertical-align: top;
}

.screenshots-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.screenshots-grid figure { margin: 0; }
.screenshots-grid img {
  width: 100%;
  height: auto;
  display: block;
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius-sm);
  background: var(--color-bg-subtle);
}
.screenshots-grid figcaption {
  margin-top: 4px;
  font-size: var(--text-2xs);
  color: var(--color-fg-muted);
  text-align: center;
}

/* ─── Submit form ────────────────────────────────────────────────────── */

.submit-form {
  max-width: 640px;
}
.submit-form fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 16px 20px;
  margin-bottom: 16px;
}
.submit-form legend {
  padding: 0 8px;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.submit-form label {
  display: block;
  margin-bottom: 12px;
}
.submit-form label span {
  display: block;
  font-size: var(--text-xs);
  font-weight: 600;
  margin-bottom: 4px;
  color: var(--color-fg);
}
.submit-form input, .submit-form select {
  width: 100%;
  padding: 6px 10px;
  font-size: var(--text-sm);
  font-family: inherit;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
}
.submit-form input:focus, .submit-form select:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.2);
}
.form-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}
.form-errors {
  background: var(--color-danger-bg);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 16px;
  color: var(--color-danger);
  font-size: var(--text-sm);
}
.form-errors ul { margin: 8px 0 0 20px; padding: 0; }

/* Import intake refusal banner (#690 — SSRF/parse refusals on the Sheets path). */
.import-error {
  background: var(--color-danger-bg);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 16px;
  color: var(--color-danger);
  font-size: var(--text-sm);
}

.param-description {
  display: block;
  margin-top: 4px;
  font-size: var(--text-2xs);
  color: var(--color-fg-muted);
  font-weight: 400;
  line-height: 1.4;
}

/* ─── Drill-down: Slice 7 (#16) auto-download targets + request logs ─── */

.per-ua-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-xs);
  margin-top: 8px;
}
.per-ua-table th, .per-ua-table td {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--color-border-muted);
  vertical-align: top;
}
.per-ua-table th {
  border-bottom-color: var(--color-border);
  font-weight: 600;
  color: var(--color-fg-muted);
}
.per-ua-table tr.per-ua-resolved {
  background: var(--color-success-bg, rgba(46, 160, 67, 0.08));
}

.request-log-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
}
.request-log-entry {
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin-bottom: 8px;
  font-size: var(--text-xs);
}
.request-log-entry header {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 6px;
}
.request-log-entry pre {
  margin: 0;
  padding: 8px;
  background: var(--color-bg-subtle);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  font-size: var(--text-2xs);
}

.evidence-type-tag {
  display: inline-block;
  margin-right: 4px;
  padding: 0 4px;
  font-size: var(--text-3xs);
  color: var(--color-fg-muted);
}

/* ─── Translation layer (#171) ──────────────────────────────────────────── */

/* §6.5 #3 — "What is an audit?" intro on submit page */
.audit-intro {
  margin: 8px 0 20px;
  padding: 12px 16px;
  background: var(--color-bg-subtle);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-fg);
}

/* §4c/§4e — above-the-fold callouts (blind-spot, pending_clarification) */
.callout {
  margin: 12px 0;
  padding: 12px 16px;
  border-radius: var(--radius);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.callout p { margin: 0; }
.callout-blind-spot {
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-fg-muted);
}
.callout-pending-clarification {
  background: var(--color-warning-bg);
  border: 1px solid var(--color-warning);
  border-left: 4px solid var(--color-warning);
}

/* §6.5 #1 — traffic-light legend (popover on list + one-liner on drill-down) */
.traffic-light-legend {
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}
p.traffic-light-legend { margin: 6px 0 0; }
details.traffic-light-legend {
  display: inline-block;
  position: relative;
}
details.traffic-light-legend > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-bg-subtle);
  font-size: var(--text-2xs);
  font-weight: 600;
  color: var(--color-fg-muted);
}
details.traffic-light-legend > summary::-webkit-details-marker { display: none; }
details.traffic-light-legend[open] > summary {
  background: var(--color-bg-hover);
  color: var(--color-fg);
}
details.traffic-light-legend ul {
  position: absolute;
  z-index: 10;
  top: 24px;
  left: 0;
  min-width: 320px;
  margin: 0;
  padding: 8px 12px;
  list-style: none;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--color-fg);
}
details.traffic-light-legend li { padding: 4px 0; line-height: 1.4; }
details.traffic-light-legend li + li { border-top: 1px solid var(--color-border-muted); }

/* §1 — reason-code expansion: per-code observation + action rows */
.reason-code-explanations {
  margin: 8px 0 0;
  border-top: 1px solid var(--color-border-muted);
  padding-top: 8px;
}
.reason-code-row {
  margin: 4px 0;
  padding: 4px 0;
}
.reason-code-row > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.reason-code-row > summary::-webkit-details-marker { display: none; }
.reason-code-row > summary::before {
  content: '▸';
  display: inline-block;
  width: 12px;
  color: var(--color-fg-muted);
  font-size: var(--text-2xs);
}
.reason-code-row[open] > summary::before { content: '▾'; }
.reason-code-badge {
  font-size: var(--text-2xs);
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border-muted);
}
.reason-code-audit_ending .reason-code-badge { color: var(--color-danger); border-color: var(--color-danger); }
.reason-code-stage_blocking .reason-code-badge { color: var(--color-warning); border-color: var(--color-warning); }
.reason-code-non_blocking .reason-code-badge { color: var(--color-fg-muted); }
.reason-code-unknown .reason-code-badge { color: var(--color-fg-muted); font-style: italic; }
.reason-code-content {
  margin: 6px 0 0 20px;
  padding: 6px 10px;
  background: var(--color-bg-subtle);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  line-height: 1.5;
}
.reason-code-content p { margin: 4px 0; }
.customer-observation strong, .customer-action strong { color: var(--color-fg); font-weight: 600; }

/* §4d — platform-skip caption beneath skipped-stage row */
.platform-skip-caption {
  margin: 4px 0 0 28px;
  font-size: var(--text-2xs);
  line-height: 1.5;
  color: var(--color-fg-muted);
}

/* §5 — display_label rendering: muted slug suffix in list shape column */
.shape-slug {
  font-size: var(--text-2xs);
  color: var(--color-fg-muted);
}

/* ─── Configuration panel (#621) ─────────────────────────────────────── */
.config-panel { margin: 12px 0; padding: 8px 12px; border: 1px solid var(--color-border-muted); border-radius: 6px; }
.config-panel summary h3 { display: inline; font-size: 0.95rem; }
.config-grid { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin-top: 8px; }
.config-row { display: contents; }
.config-value { word-break: break-all; }
.config-geo { margin-top: 8px; }
.config-geo-mismatch { border-left: 3px solid var(--color-danger); padding-left: 8px; }
.geo-mismatch { color: var(--color-danger); font-weight: 600; }

/* ─── Live progress page for ad-hoc runs (#692) ────────────────────────────
   Calm/dense texture (ADR-0013 c). Whitespace + hairline rows do the grouping;
   the errored tier is grey, never red. */
.cycle-progress-page { max-width: 760px; }
.progress-counter {
  font-size: var(--text-lg); font-weight: 600; margin: 8px 0 16px 0;
}
.progress-eta { font-size: var(--text-sm); color: var(--color-fg-muted); margin: -8px 0 16px 0; }
.progress-headline {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; margin-bottom: 12px;
  border: 1px solid var(--color-border, #d0d7de); border-radius: 8px;
  background: var(--color-bg-subtle, #f6f8fa);
}
.progress-headline .status-icon { font-size: var(--text-2xl); }
.progress-headline-label { font-size: var(--text-xl); font-weight: 600; }
.progress-actions { display: flex; gap: 10px; margin-bottom: 24px; }
.coord-table { width: 100%; border-collapse: collapse; }
.coord-table thead th {
  text-align: left; font-size: var(--text-xs); font-weight: 600;
  color: var(--color-fg-muted, #656d76);
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 6px 12px; border-bottom: 1px solid var(--color-border, #d0d7de);
}
.coord-row td { padding: 14px 12px; border-bottom: 1px solid var(--color-border-muted, #eaeef2); }
.coord-light { width: 28px; text-align: center; }
.coord-name { font-variant-numeric: tabular-nums; }
.coord-state { color: var(--color-fg-muted, #656d76); white-space: nowrap; }
.coord-pending-icon { color: var(--color-fg-muted, #9a6700); }
.coord-dash { color: var(--color-fg-muted, #656d76); font-weight: 700; }
/* Errored coordinate — grey tier, distinct from a FAIL verdict. Never red. */
.coord-errored td { color: var(--color-fg-muted, #656d76); font-style: italic; }
.coord-not-an-audit td { color: var(--color-fg-muted, #656d76); font-style: italic; }

/* ─── Links home (calm lens, #689 · ADR-0035 §(e)+(h)) ──────────────────────
 * Ported from the picked calm-lens proto. Table rules are scoped under
 * `.links-table` so no other table in the app is restyled; neutrals use the
 * app's tokens, the soft chip palette is the design winner's. */

/* Nightly-check banner */
.nightly-banner {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; margin-bottom: 20px;
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border-muted); border-radius: 8px;
}
.banner-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--color-fg-muted); }
.banner-dot-green { background: var(--color-success); }
.banner-dot-amber { background: var(--color-warning); }
.banner-dot-red { background: var(--color-danger); }
.banner-text strong { font-weight: 600; color: var(--color-fg); }
.banner-aside { font-size: var(--text-sm); color: var(--color-fg-muted); }
.banner-aside .cant-measure { color: var(--color-warning); font-weight: 500; }
.banner-link { margin-left: auto; font-size: var(--text-sm); font-weight: 500; white-space: nowrap; }

/* Header row */
.links-header { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 24px; }
.links-header-text { flex: 1; }
.links-header .page-title { margin: 0; font-size: var(--text-2xl); font-weight: 700; letter-spacing: -0.01em; }
.links-header .page-subtitle { margin: 4px 0 0; font-size: var(--text-md); color: var(--color-fg-muted); }
.links-header .quota-counter { margin: 4px 0 0; font-size: var(--text-sm); }
.links-header-actions { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }

.links-empty {
  padding: 32px; text-align: center; color: var(--color-fg-muted);
  background: var(--color-bg-subtle); border: 1px solid var(--color-border-muted); border-radius: 12px;
}

/* Table card */
/* overflow-x:auto (not hidden) so the Actions column is never cropped — it fits
 * with no scroll at normal widths and degrades to a scroll on narrow viewports. */
.links-table-wrap { background: var(--color-bg); border: 1px solid var(--color-border-muted); border-radius: 12px; overflow-x: auto; }
.links-table { width: 100%; border-collapse: collapse; }
.links-table thead th {
  padding: 12px 20px; text-align: left;
  font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-fg-muted); background: var(--color-bg-subtle);
  border-bottom: 1px solid var(--color-border-muted);
  /* Six columns since #1557 — a wrapped two-line "AUDIT SHAPE" beside a
     one-line neighbour reads as a broken header, so headers never wrap. */
  white-space: nowrap;
}
.links-table thead th.actions-col { text-align: right; }
.links-table tbody tr { border-bottom: 1px solid var(--color-border-muted); }
.links-table tbody tr:last-child { border-bottom: none; }
.links-table tbody tr:hover { background: var(--color-bg-subtle); }
.links-table tbody tr.row-fail { border-left: 3px solid var(--color-danger); }
/* 18px → 11px vertical. Six short fields do not need a 130px row; at five links
   the board already ran past a screen, and the page exists to be scanned. */
.links-table td { padding: 11px 16px; vertical-align: top; }

/* Link label + url */
/* THE COLUMN BUDGET. An affiliate tracking URL is routinely 250+ characters, and
   an auto-layout table sizes a column to its widest cell — so every free-running
   string in this cell is a lever on the whole table's width. Each of the three
   lines below is capped at this one budget, which is what the other five columns
   can spare. Measured at a 1280 viewport (a ~1002px card): the six columns used
   to sum to 1075px and the card scrolled sideways; capped, they sum to 974px and
   a 380-character URL costs the table the same as a 30-character one. Change
   this number and re-measure — 220px still fitted, but with 12px of slack. */
:root { --link-cell-max: 200px; }

.link-label { font-size: var(--text-md); font-weight: 600; color: var(--color-fg); line-height: 1.4; margin-bottom: 3px; }
/* The name is held to the same budget, but it WRAPS rather than ellipsising on
   the first line: real labels run past 60 characters ("Rabona — nostrabet review
   placement (ReferOn mid 45437_535161)") and a few are a pasted URL, and the
   name is the one thing in the row you actually scan — cutting it at 24
   characters would be the worse bug. Wrapping costs width nothing (a wrappable
   line contributes only its longest word, and `anywhere` bounds the URL-shaped
   labels), but it does cost HEIGHT, and #1557 spent real effort getting the row
   down to 11px padding: unclamped, that Rabona label takes four lines. Two lines
   then ellipsis is the bound that keeps both — ~50 characters shown, the row no
   taller than the actions cell beside it, full name on hover. Scoped to
   `.links-table` so bulk edit, whose four-column budget was measured separately
   in #1636 finding 3, keeps its own. */
.links-table .link-label {
  max-width: var(--link-cell-max); overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
/* The name is the row's door to the link detail (#1636 finding 8). It inherits
   the label's weight and colour so the row still scans as a name, not a link
   farm; the underline on hover/focus is what says it is clickable. */
.link-name-link { color: inherit; text-decoration: none; }
.link-name-link:hover, .link-name-link:focus-visible { text-decoration: underline; }
.link-url {
  /* 360px, then 300px, was what pushed the six-column table (#1557 added Status)
     past its wrapper and clipped the Actions column. The URL is a truncated
     identifier, not something anyone reads to the end — it yields first, and it
     yields furthest: one rung smaller than the rest of the cell so the name
     stays the thing you scan. Hover (or the detail page) has the full string. */
  display: block; max-width: var(--link-cell-max);
  font-size: var(--text-2xs); color: var(--color-fg-muted);
  font-family: ui-monospace, "SF Mono", "Fira Mono", Consolas, monospace;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Status chip. Link Admin carries the OPERATIONAL state (active/paused) in
 * chip-active/chip-paused since #1557 item 10; the health variants below serve
 * other surfaces — #1446 kept health off this table and that still holds. */
.status-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 20px; font-size: var(--text-xs); font-weight: 600; white-space: nowrap;
}
.chip-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.chip-ok    { background: #dcfce7; color: #15803d; }
.chip-ok    .chip-dot { background: #22c55e; }
.chip-warn  { background: #fef3c7; color: #92400e; }
.chip-warn  .chip-dot { background: #f59e0b; }
.chip-fail  { background: #fee2e2; color: #b91c1c; }
.chip-fail  .chip-dot { background: #ef4444; }
.chip-never { background: var(--color-bg-subtle); color: var(--color-fg-muted); }
.chip-never .chip-dot { background: var(--color-border); }
.status-sowhat { margin-top: 5px; max-width: 260px; font-size: var(--text-xs); line-height: 1.45; color: var(--color-fg-muted); }
.status-sowhat.sowhat-fail { color: #991b1b; font-weight: 500; }
.status-sowhat.sowhat-warn { color: #78350f; }
.fail-action-note {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 7px;
  padding: 4px 10px; font-size: var(--text-xs); font-weight: 600;
  color: #b91c1c; background: var(--color-danger-bg); border: 1px solid #fca5a5; border-radius: 5px;
}
.cant-measure-note { margin-top: 5px; font-size: var(--text-xs); color: var(--color-warning); }
.in-flight-note { margin-top: 5px; font-size: var(--text-xs); color: var(--color-fg-muted); }

/* Coverage + last checked */
.coverage-col { min-width: 140px; }
.coverage-geos { font-size: var(--text-sm); font-weight: 500; color: var(--color-fg); }
.coverage-devices { margin-top: 2px; font-size: var(--text-xs); color: var(--color-fg-muted); }
.checked-col { min-width: 110px; white-space: nowrap; font-size: var(--text-sm); color: var(--color-fg); }

/* Status — the OPERATIONAL axis (#1557 item 10), rendered by statusChip() in
   its own colours so it can never be read as a health verdict. */
.status-col { min-width: 90px; }

/* Actions (#1557 item 12). Real buttons on a row of controls, not text links
   pretending to be actions: each one mutates the link it sits on. They sit on
   one line and wrap together, so a narrow table stacks them cleanly. */
/* The flex container is an inner div, never the <td> itself: display:flex on a
   table cell drops it out of the row's cell layout and the row's borders stop
   short of it. */
/* 205px is what the rest of the table can spare, NOT what the primary pair
   needs (Run now + Pause checks want 200px of content box and this cell's
   padding takes 40 of the 205), so the pair wraps to its own second line and
   the cell reads as three lines. Widening it to 240 overflows .links-table-wrap
   instead — measured 2026-08-12. The fix is a column budget, not a min-width. */
/* 205 → 230. The measured budget was taken at the 17.5px root, where the two
   primary buttons summed to ~202px and sat one bad rounding away from wrapping
   — which is exactly what they did, turning every row into three stacked lines.
   At the 16px root they need ~185px; 230 buys headroom so line 1 stays ONE
   line, which is where most of the row-height saving actually comes from. */
.actions-col { text-align: right; white-space: nowrap; min-width: 230px; }
/* Two deliberate lines rather than one wrapping cluster (#1557 item 11 added a
   third and fourth control, #1558 item 21 a fifth, and a plain flex-wrap
   staggered them down the cell at three different indents). Line 1 is what you
   DO to a link now; line 2 is what you do to the link itself, in quieter text. */
.row-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.row-actions-primary { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.row-actions-secondary { display: flex; justify-content: flex-end; gap: 12px; }
.row-actions form { display: inline; }
.row-link { font-size: var(--text-xs); color: var(--color-accent); }
.row-link-quiet { color: var(--color-fg-muted); }
.row-link-quiet:hover { color: var(--color-danger); }
.row-action { padding: 5px 11px; font-size: var(--text-xs); }
/* Still worn by the link-detail "View live progress" link (#1551) — a real
   navigation, not a row control, so it keeps the text-link treatment. */
.action-link { font-size: var(--text-sm); font-weight: 500; }

/* Footer (every page) */
/* Was max-width:1100 against the content's 1200 — a 50px-per-side mismatch
   that read as "nothing lines up". Now the same gutter as .app-main, and the
   frame column is applied above for the shell-less pages (item 23). */
.app-footer {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  margin: 48px 0 0; padding: 16px var(--gutter);
  border-top: 1px solid var(--color-border-muted); font-size: var(--text-sm);
}

/* ── Guided link-mask wizard (#780, ADR-0043 §b,c,h) ─────────────────────────
   Ported from the prototype's inline <style> (link-mask.ts) on productionisation.
   Kept as literal values rather than var(--token) to preserve the reviewed
   prototype look 1:1; a follow-up can tokenise. */
.mask-page { max-width: 760px; }
.mask-steps { display: flex; gap: .5rem; list-style: none; padding: 0; margin: 0 0 1.5rem; flex-wrap: wrap; }
.mask-step { font-size: .8rem; color: #8a93a2; display: flex; align-items: center; gap: .35rem; }
.mask-step span {
  display: inline-flex; width: 1.5rem; height: 1.5rem; border-radius: 50%;
  background: #e6e9ef; color: #5b6472; align-items: center; justify-content: center; font-weight: 600;
}
.mask-step.now { color: #1a1f29; font-weight: 600; }
.mask-step.now span { background: #2f6fed; color: #fff; }
.mask-step.done span { background: #2fae6b; color: #fff; }
.mask-explain {
  background: #f5f7fb; border-left: 3px solid #2f6fed; padding: .75rem 1rem;
  border-radius: 4px; color: #3a4252; font-size: .92rem; line-height: 1.5;
}
.mask-ticks { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: .5rem; }
/* .mask-page scope wins specificity over the house ".submit-form label{display:block}"
   rule. The per-link edit form (#1557 item 11) borrows the same tick/radio/toggle
   vocabulary, so it is named here too — without it the house rule stacks each
   control's input above its label at opposite ends of the page. */
.mask-page .mask-tick, .mask-page .mask-radio, .mask-page .mask-toggle,
.link-edit-form .mask-radio, .link-edit-form .mask-toggle {
  display: flex; flex-direction: row; gap: .5rem; align-items: flex-start;
  padding: .6rem .75rem; border: 1px solid #dfe3ea; border-radius: 6px; cursor: pointer; margin-bottom: .6rem;
}
.mask-page .mask-tick input, .mask-page .mask-radio input, .mask-page .mask-toggle input,
.link-edit-form .mask-radio input, .link-edit-form .mask-toggle input {
  margin-top: .2rem; width: auto; flex: 0 0 auto;
}
.mask-page .mask-tick span, .mask-page .mask-radio span, .mask-page .mask-toggle span,
.link-edit-form .mask-radio span, .link-edit-form .mask-toggle span {
  display: inline; margin-bottom: 0; font-size: inherit; font-weight: inherit;
}
.mask-radios { display: flex; flex-direction: column; gap: .5rem; max-width: 420px; }
/* Duplicate's provenance note on step 1 (#1558 item 21) — it sits ABOVE the
   first explainer, so it is tinted differently from one: it reports where the
   answers came from, it does not explain the field below it. */
.mask-seeded {
  background: #eef6ef; border: 1px solid #b9e0c6; border-radius: 6px;
  padding: .75rem 1rem; margin-bottom: 1rem; color: #3a4252;
  font-size: .92rem; line-height: 1.5;
}
.mask-summary td:first-child { color: #6b7280; padding-right: 1rem; white-space: nowrap; }
.mask-fanout {
  display: flex; gap: 1rem; align-items: center; background: #eef6ef;
  border: 1px solid #b9e0c6; border-radius: 8px; padding: 1rem 1.25rem; margin: 1.25rem 0;
}
.mask-fanout-num { font-size: 2.4rem; font-weight: 700; color: #2fae6b; line-height: 1; }
.mask-onswitch { background: #fafbfc; border: 1px dashed #cfd5de; border-radius: 8px; padding: .75rem; margin-bottom: 1rem; }
.mask-done p { margin: .5rem 0; font-size: 1.02rem; }

/* ════════════════════════════════════════════════════════════════════════
   Frontend-platform shell (#513): left-sidebar console, sign-in screen,
   greyed section placeholders, account mockup. Reuses the tokens above.
   ════════════════════════════════════════════════════════════════════════ */

/* ─── App shell: sidebar + content pane ──────────────────────────────────── */
/* Sits below the navy bar. One page scroll — the sidebar is a normal column
   (no nested sticky/overflow), so page and container scrolling never fight. */
.app-shell {
  display: flex; flex: 1 1 auto; align-items: stretch;
  width: 100%; max-width: var(--frame-max); margin: 0 auto;
}

.app-sidebar {
  flex: 0 0 var(--sidebar-w); width: var(--sidebar-w); min-width: 0;
  /* 11 + the item's 3px transparent border + its 10px inset = 24px, so nav
     labels sit exactly on the gutter the bar's mark uses (item 23). */
  padding: 14px 11px;
  background: var(--color-bg-subtle);
  border-right: 1px solid var(--color-border);
}
.app-pane { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.app-pane .app-main { width: 100%; }

.sidebar-nav { display: flex; flex-direction: column; gap: 1px; }
.sidebar-item {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px; border-radius: var(--radius);
  color: var(--color-fg); font-size: var(--text-sm); font-weight: 500;
  border-left: 3px solid transparent;
}
a.sidebar-item:hover { background: var(--color-bg-hover); text-decoration: none; }
.sidebar-icon { display: inline-flex; flex: 0 0 16px; color: var(--color-fg-muted); }
.sidebar-icon svg {
  width: 16px; height: 16px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.sidebar-label { flex: 1 1 auto; }

/* Group header (#1554, item 5) — a section LABEL, never a link. Small, muted
   and letter-spaced so it reads as a different class of thing from the items
   under it; the generous top padding is what actually creates the grouping. */
.sidebar-group {
  text-transform: uppercase; letter-spacing: 0.07em;
  font-size: var(--text-3xs); font-weight: 700; color: var(--color-fg-muted);
  padding: 18px 10px 5px 13px; cursor: default; user-select: none;
}
.sidebar-nav > .sidebar-group:first-child { padding-top: 4px; }

.sidebar-item.is-active {
  background: var(--color-bg-hover);
  border-left-color: var(--color-accent);
  color: var(--color-fg); font-weight: 600;
}
.sidebar-item.is-active .sidebar-icon { color: var(--color-accent); }

/* Sketched (not-yet-built) sections: muted. Soon leaves with no path aren't links. */
.sidebar-item.is-soon { color: var(--color-fg-muted); }
.sidebar-item.is-soon .sidebar-icon { color: var(--color-border); }
div.sidebar-item.is-soon { cursor: default; }
.soon-pill {
  font-size: var(--text-3xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 1px 6px; border-radius: 999px;
  background: var(--color-warning-bg); color: var(--color-warning);
  border: 1px solid var(--color-warning-bg);
}

/* Narrow viewports: sidebar stacks above the content (still a vertical list, so
   the indentation reads); everything stays visible, one vertical scroll. */
@media (max-width: 860px) {
  .app-shell { flex-direction: column; }
  .app-sidebar {
    flex-basis: auto; width: auto;
    border-right: none; border-bottom: 1px solid var(--color-border);
  }
}

/* ─── Sign-in screen (auth variant) ──────────────────────────────────────── */
.auth-body { background: var(--color-bg-subtle); }
.auth-main { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.auth-card {
  width: 100%; max-width: 380px;
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: 10px; padding: 28px 28px 24px;
  box-shadow: 0 6px 24px rgba(31, 35, 40, 0.08);
}
.auth-brand { display: flex; align-items: center; gap: 6px; font-size: var(--text-sm); font-weight: 600; color: var(--color-fg-muted); margin-bottom: 18px; }
.auth-title { margin: 0 0 4px; font-size: var(--text-2xl); font-weight: 600; }
.auth-sub { margin: 0 0 20px; font-size: var(--text-sm); color: var(--color-fg-muted); }
.auth-form label { display: block; margin-bottom: 14px; }
.auth-form label > span { display: block; font-size: var(--text-xs); font-weight: 600; margin-bottom: 4px; }
.auth-form input[type="text"], .auth-form input[type="password"] {
  width: 100%; padding: 8px 10px; font-size: var(--text-md); font-family: inherit;
  border: 1px solid var(--color-border); border-radius: var(--radius); background: var(--color-bg);
}
.auth-form input:focus { outline: none; border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.2); }
.auth-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; font-size: var(--text-xs); }
.auth-remember { display: inline-flex !important; align-items: center; gap: 6px; margin: 0 !important; }
.auth-remember input { width: auto; }
.auth-remember > span { display: inline !important; font-weight: 400 !important; margin: 0 !important; }
.auth-forgot { font-size: var(--text-xs); }
.auth-submit { width: 100%; justify-content: center; text-align: center; padding: 9px; font-size: var(--text-md); }
.auth-foot { margin: 18px 0 0; font-size: var(--text-xs); line-height: 1.5; }
.auth-sketch { margin: 10px 0 0; font-size: var(--text-2xs); font-style: italic; }
.auth-notice {
  background: var(--color-bg-subtle); border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-accent); border-radius: var(--radius);
  padding: 10px 14px; margin-bottom: 16px; font-size: var(--text-xs); line-height: 1.5;
}
.auth-notice p { margin: 0; }

/* ─── Section placeholders (Dashboard / Audit results / Monitoring) ───────── */
.soon-badge { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }
.placeholder {
  text-align: center; padding: 40px 24px;
  background: var(--color-bg-subtle); border: 1px dashed var(--color-border); border-radius: var(--radius);
}
.placeholder-icon { display: inline-flex; color: var(--color-border); margin-bottom: 8px; }
.placeholder-icon svg {
  width: 40px; height: 40px; fill: none; stroke: currentColor; stroke-width: 1.2;
  stroke-linecap: round; stroke-linejoin: round;
}
.placeholder h2 { margin: 0 0 4px; font-size: var(--text-lg); font-weight: 600; }
.placeholder-planned {
  display: inline-block; text-align: left; margin: 12px auto 0; padding-left: 20px;
  font-size: var(--text-sm); color: var(--color-fg); line-height: 1.8;
}
.placeholder-available { margin-top: 24px; }
.placeholder-available h2 { font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-muted); margin: 0 0 8px; }
.placeholder-links { list-style: none; padding: 0; margin: 0; }
.placeholder-links li { padding: 6px 0; border-bottom: 1px solid var(--color-border-muted); font-size: var(--text-sm); }
.placeholder-links li:last-child { border-bottom: none; }

/* ─── Account page ────────────────────────────────────────────────────────
   Live blocks (profile, sign-in security, account access, user management) sit
   at full opacity; the 0.75 dim is reserved for the `Soon` mockup blocks, which
   are the ones rendered as a `disabled` fieldset. Dimming every card made the
   whole page read as inactive (#1636 finding 13). */
.account-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; max-width: 760px; }
.account-block {
  border: 1px solid var(--color-border); border-radius: var(--radius);
  padding: 16px 20px; margin: 0; opacity: 0.75;
}
.account-block:not([disabled]) { opacity: 1; }
/* Read-only facts (#1636): a definition list, sharing the `.config-grid` idiom
   with the Audit setup page. */
.account-facts { margin: 0 0 4px; }
.account-block legend { padding: 0 8px; font-weight: 600; font-size: var(--text-sm); color: var(--color-fg-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.account-block label { display: block; margin-bottom: 12px; }
.account-block label > span { display: block; font-size: var(--text-xs); font-weight: 600; margin-bottom: 4px; }
/* Every remaining input on the page is genuinely editable (the 2FA code, the
   admin reset username), so they get the normal editable-field palette — the
   grey-on-grey treatment was a leftover from when facts were inputs too. */
.account-block input {
  width: 100%; padding: 6px 10px; font-size: var(--text-sm); font-family: inherit;
  border: 1px solid var(--color-border); border-radius: var(--radius);
  background: var(--color-bg); color: var(--color-fg);
}
.account-2fa { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; padding-top: 4px; font-size: var(--text-sm); }
.account-2fa > p { margin: 0; }
.account-hint { font-size: var(--text-2xs); margin: 4px 0 0; }

/* ─── TOTP 2FA enrolment (#1385, made mandatory + workspace-independent #1407) ─
 * The setup page renders two account-blocks side by side (Scan / Confirm); the
 * grid falls back to a single column on narrow viewports. Reuses the account
 * palette + radius tokens — no new visual language. */
.account-2fa-setup { align-items: start; max-width: 720px; }
.account-2fa-setup .account-block { opacity: 1; }
/* Server-rendered inline QR: constrain + center; a white plate keeps the QR
 * high-contrast and scannable regardless of the surrounding surface. */
.twofa-qr { max-width: 220px; margin: 4px auto 8px; padding: 12px; background: #ffffff;
  border: 1px solid var(--color-border); border-radius: var(--radius); }
.twofa-qr svg { display: block; width: 100%; height: auto; }
/* Manual-entry key: boxed, monospaced, letter-spaced, wraps on overflow. */
.twofa-secret { display: inline-block; padding: 8px 12px; font-family: var(--font-mono);
  font-size: var(--text-md); letter-spacing: 0.18em; word-break: break-all;
  background: var(--color-bg-subtle); border: 1px solid var(--color-border-muted);
  border-radius: var(--radius); color: var(--color-fg); }
/* Code-entry form (setup confirm + account-page disable): a compact, centred
 * numeric field with generous tracking so the 6 digits read clearly. */
.account-2fa-form { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; margin: 0; }
.account-2fa-form label { margin-bottom: 0; }
.account-2fa-form input { max-width: 180px; text-align: center; font-family: var(--font-mono);
  font-size: var(--text-xl); letter-spacing: 0.35em; padding: 8px 10px; color: var(--color-fg); }
.account-usage-bar { height: 8px; border-radius: 999px; background: var(--color-bg-hover); overflow: hidden; }
.account-usage-bar > span { display: block; height: 100%; background: var(--color-accent); opacity: 0.5; }

/* ───────────────────────────────────────────────────────────────────────────
 * Dashboard cockpit (#815, ADR-0047). Circle-GAR health widgets. Reuses the
 * status color system above; grey = "couldn't be measured" (set aside, never a
 * fail). Zero client JS — group/sort is a server-rendered segmented control.
 * ─────────────────────────────────────────────────────────────────────────── */
:root {
  --gar-ok: var(--color-success);
  --gar-warn: var(--color-warning);
  --gar-fail: var(--color-danger);
  --gar-grey: #8c959f;
}

/* circle-GAR ring (inline SVG donut) */
.gar-ring { display: block; }
.gar-ring-lg { width: 92px; height: 92px; }
.gar-ring-sm { width: 56px; height: 56px; }
.gar-track { stroke: var(--color-bg-hover); stroke-width: 3.2; }
.gar-seg { stroke-width: 3.6; stroke-linecap: butt; }
.gar-seg-ok { stroke: var(--gar-ok); }
.gar-seg-warn { stroke: var(--gar-warn); }
.gar-seg-fail { stroke: var(--gar-fail); }
.gar-seg-grey { stroke: var(--gar-grey); }
/* The centre now reads "75%" (item 7), so one size serves both rings — 4
   glyphs ("100%") stay inside the 28-unit inner circle. The `/100` sub-label it
   replaced is gone. */
.gar-score { font-family: var(--font-sans); font-weight: 600; fill: var(--color-fg); }
.gar-ring-lg .gar-score { font-size: 9px; }
.gar-ring-sm .gar-score { font-size: 9px; }

/* status dots */
.gar-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; vertical-align: middle; margin: 0 4px; }
.gar-dot-ok { background: var(--gar-ok); }
.gar-dot-warn { background: var(--gar-warn); }
.gar-dot-fail { background: var(--gar-fail); }
.gar-dot-grey { background: var(--gar-grey); }

/* Headline verdict badge (#1446 Q1) — banded on the score so the WORD agrees
   with the number; sits beside the ring in the rollup head + each widget title.
   Palette mirrors .chip-ok/warn/fail. The honest hover lives on the element. */
.gar-badge {
  display: inline-flex; align-items: center; margin-left: 8px;
  padding: 2px 10px; border-radius: 999px;
  font-size: var(--text-2xs); font-weight: 600; white-space: nowrap; vertical-align: middle;
}
.gar-badge-ok   { background: #dcfce7; color: #15803d; }
.gar-badge-warn { background: #fef3c7; color: #92400e; }
.gar-badge-fail { background: #fee2e2; color: #b91c1c; }
.gar-badge-grey { background: var(--color-bg-subtle); color: var(--color-fg-muted); }

/* workspace roll-up — the frame comes from the card() it sits in (#1555), so
   this rule owns layout only; a second border here would double-box it. */
.gar-rollup { display: flex; align-items: center; gap: 22px; }
.card-rollup { margin-bottom: 16px; }
.gar-rollup-ring { flex: 0 0 auto; }
.gar-rollup-body { flex: 1 1 auto; min-width: 0; }
.gar-rollup-head { display: flex; align-items: center; gap: 6px; }
.gar-rollup-title { font-weight: 600; font-size: var(--text-lg); }
.gar-rollup-headline { margin: 2px 0 10px 0; color: var(--color-fg-muted); }
.gar-breakdown { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; }
.gar-breakdown-label { font-size: var(--text-xs); color: var(--color-fg-muted); width: 64px; flex: 0 0 auto; }
.gar-chip {
  display: inline-flex; align-items: center; font-size: var(--text-xs);
  padding: 1px 8px 1px 4px; border: 1px solid var(--color-border-muted);
  border-radius: 999px; background: var(--color-bg);
}

/* group / sort segmented control */
.gar-controls { display: flex; flex-wrap: wrap; gap: 18px; margin: 4px 0 16px 0; align-items: center; }
.gar-control { display: flex; align-items: center; gap: 8px; }
.gar-control-label { font-size: var(--text-xs); color: var(--color-fg-muted); }
.gar-segmented { display: inline-flex; border: 1px solid var(--color-border); border-radius: var(--radius); overflow: hidden; }
.gar-seg-opt {
  padding: 4px 12px; font-size: var(--text-sm); color: var(--color-fg);
  border-left: 1px solid var(--color-border);
}
.gar-seg-opt:first-child { border-left: none; }
.gar-seg-opt:hover { background: var(--color-bg-hover); text-decoration: none; }
.gar-seg-opt.is-active { background: var(--color-accent); color: var(--color-accent-fg); }

/* widget grid + cards */
.gar-group { margin-bottom: 22px; }
.gar-group-title { font-size: var(--text-sm); font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-fg-muted); margin: 0 0 10px 0; }
/* align-items:start — an open card must not stretch its row-mates into tall
   empty boxes (the drill-down is per-card, so equal heights are a lie). */
.gar-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
  gap: 14px; align-items: start;
}
.gar-widget {
  border: 1px solid var(--color-border-muted); border-left-width: 3px;
  border-radius: var(--radius); background: var(--color-bg);
}
.gar-widget-ok { border-left-color: var(--gar-ok); }
.gar-widget-warn { border-left-color: var(--gar-warn); }
.gar-widget-fail { border-left-color: var(--gar-fail); }
.gar-widget-grey { border-left-color: var(--gar-grey); }
/* min-height keeps the grid even: cards carry 3 or 4 stacked lines depending on
   whether anything is broken, and without a floor the rows read ragged. */
.gar-widget-head { display: flex; gap: 14px; align-items: center; padding: 13px 15px; min-height: 132px; }
.gar-ring-wrap { flex: 0 0 auto; }
.gar-widget-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.gar-widget-title { font-weight: 600; }
.gar-widget-meta { font-size: var(--text-xs); color: var(--color-fg-muted); }
/* Item 7 — the score said out loud, so nobody has to guess the denominator. */
.gar-score-line { font-size: var(--text-sm); color: var(--color-fg-muted); margin-top: 3px; }
.gar-score-fraction { color: var(--color-fg); font-variant-numeric: tabular-nums; }
.gar-score-aside { color: var(--color-fg-muted); }
/* First-level diagnosis chip (#831) — the "what kind of problem" headline. */
.gar-diagnosis {
  display: inline-block; align-self: flex-start;
  font-size: var(--text-xs); font-weight: 600;
  padding: 2px 9px; margin-top: 4px;
  border-radius: 999px; border: 1px solid transparent;
}
.gar-diagnosis-fail { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger); }
.gar-diagnosis-warn { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }
.gar-widget-counts { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: var(--text-xs); margin-top: 4px; }
.gar-count { display: inline-flex; align-items: center; }
.gar-counts-empty { font-size: var(--text-xs); color: var(--color-fg-muted); font-style: italic; margin-top: 4px; }

/* drill-down table (inside disclosure-body). Denser than the page-level
   .audit-table it inherits from, and readable rather than mono-cryptic. */
.gar-cells { font-size: var(--text-sm); }
.gar-cells thead th { padding: 6px 10px; }
.gar-cells td { padding: 7px 10px; }
.gar-cells tbody tr:last-child { border-bottom: none; }
.gar-cell-coord { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* The verdict word and its reason share a cell, stacked: the word stays the
   scannable column, the reason sits under it in quieter type. `nowrap` is
   dropped from the wrapper (a reason phrase must be allowed to wrap) and kept
   on the verdict line, which must never break mid-word. */
.gar-cell-state { white-space: normal; }
.gar-cell-state > .gar-dot { vertical-align: baseline; }
/* Per-row reason (#831 tail). Fault rows take the banded colour; grey rows stay
   muted so a measurement limit never wears fault colours (ADR-0024). */
.gar-cell-reason { display: block; font-size: var(--text-xs); line-height: 1.35; margin-top: 1px; }
.gar-cell-reason-fail { color: var(--color-danger); }
.gar-cell-reason-warn { color: var(--color-warning); }
.gar-cell-reason-grey { color: var(--color-fg-muted); font-style: italic; }
/* An OK row with a code (a non-decisive advisory) states it, but quietly. */
.gar-cell-reason-ok { color: var(--color-fg-muted); }
/* the header inherits .audit-table's left align, so the column would disagree
   with its own cells without this */
.gar-cells thead th.gar-cell-open { text-align: right; }
.gar-cell-open { text-align: right; white-space: nowrap; }
.gar-cellrow-fail .gar-cell-coord { font-weight: 600; }
.gar-evidence-link { font-weight: 500; white-space: nowrap; }
.gar-evidence-link:hover { text-decoration: underline; }

/* ─── Per-link status history (#691) ─────────────────────────────────────── */
/* Traffic-light verdict classes used by renderCell / renderCycle headline.   */
.tl-ok   { color: var(--color-success); font-weight: 600; }
.tl-warn { color: var(--color-warning); font-weight: 600; }
.tl-fail { color: var(--color-danger);  font-weight: 600; }
.tl-unknown { color: var(--color-fg-muted); }

.history-header { margin-bottom: 24px; }
.history-title  { margin: 0 0 4px; font-size: var(--text-2xl); }
/* The detail page is where the FULL tracking URL is legitimately readable — it
   is the one place that must not truncate. It must not run off the page either:
   a URL with no slash or hyphen in 300 characters offers a browser no soft-wrap
   opportunity at all, and the page then scrolls sideways. `anywhere` gives it
   one; the measure keeps the wrapped block from spanning a wide viewport. */
.history-url {
  margin: 0; max-width: 90ch; font-size: var(--text-xs); color: var(--color-fg-muted);
  overflow-wrap: anywhere;
}
.history-url code { font-family: ui-monospace, "SF Mono", "Fira Mono", Consolas, monospace; }

.history-feed { display: flex; flex-direction: column; gap: 16px; }
.history-empty, .history-more, .history-end {
  font-size: var(--text-sm); color: var(--color-fg-muted); padding: 8px 0;
}

/* Cycle article */
.history-cycle {
  border: 1px solid var(--color-border); border-radius: var(--radius);
  overflow: hidden;
}
.history-cycle__header {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; background: var(--color-bg-subtle);
  border-bottom: 1px solid var(--color-border-muted); font-size: var(--text-sm);
}
.history-cycle__kind  { font-weight: 600; }
.history-cycle__when  { color: var(--color-fg-muted); font-size: var(--text-xs); }
.history-cycle__headline { margin-left: auto; font-size: var(--text-sm); }
.history-cycle__summary  { color: var(--color-fg-muted); font-size: var(--text-xs); }

/* Transition banner */
.transition-banner {
  padding: 6px 14px; font-size: var(--text-xs); font-weight: 500;
  background: var(--color-warning-bg); color: var(--color-warning);
  border-bottom: 1px solid var(--color-border-muted);
}

/* ─── Scheduler configuration block (#1625, epic #1627 Gate 4) ──────────────
 * The "scheduled checks are not running" axis. Amber like the other
 * needs-a-human callouts, and deliberately NOT any of the traffic-light or
 * status-chip colours: a blocked link's health is still whatever its last
 * completed check said. */
.scheduler-block {
  margin: 12px 0; padding: 14px 16px;
  background: var(--color-warning-bg);
  border: 1px solid var(--color-warning); border-left: 4px solid var(--color-warning);
  border-radius: var(--radius);
}
.scheduler-block__title {
  margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--color-warning);
}
.scheduler-block__reason {
  margin: 6px 0 0; font-size: var(--text-sm); line-height: 1.5; color: var(--color-fg);
}
.scheduler-block__facts {
  display: flex; flex-wrap: wrap; gap: 8px 28px; margin: 12px 0 0;
  font-size: var(--text-xs);
}
.scheduler-block__fact dt { color: var(--color-fg-muted); }
.scheduler-block__fact dd { margin: 2px 0 0; font-weight: 500; color: var(--color-fg); }

/* Row treatment on Link Admin — sits under the operational Status chip. */
.block-chip { display: block; margin-top: 6px; font-size: var(--text-xs); line-height: 1.35; }
.block-chip__label { display: block; font-weight: 600; color: var(--color-warning); }
.block-chip__reason { display: block; color: var(--color-fg-muted); }

/* Cells table */
.history-cells { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.history-cell td { padding: 7px 14px; border-top: 1px solid var(--color-border-muted); }
.history-cell__coord   { font-family: var(--font-mono); font-size: var(--text-xs); }
.history-cell__verdict { white-space: nowrap; }
.history-cell__actions { text-align: right; }

.history-cell--tl-fail .history-cell__coord { font-weight: 600; }

/* Errored / pending / suspect rows — no accent colour */
.history-cell__verdict--errored,
.history-cell__verdict--not-an-audit,
.history-cell__verdict--pending { color: var(--color-fg-muted); font-style: italic; }

/* Re-check inline form */
.recheck-form { display: inline; }
.recheck-btn  {
  font-size: var(--text-xs); padding: 2px 8px;
  border: 1px solid var(--color-border); border-radius: var(--radius);
  background: var(--color-bg); cursor: pointer; color: var(--color-accent);
}
.recheck-btn:hover { background: var(--color-bg-hover); }

/* Workspace configuration — read-only brand-spec view (#1045) */
.config-section { margin-top: 24px; }
.config-section > h2 { font-size: var(--text-lg); margin: 0 0 8px; }
.config-foot { margin-top: 24px; max-width: 60ch; }
.config-key { white-space: nowrap; }
.cov-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.cov-chip {
  display: inline-block; padding: 2px 8px; font-size: var(--text-xs);
  border: 1px solid var(--color-border); border-radius: var(--radius);
  background: var(--color-bg-subtle); color: var(--color-fg);
}
.config-table { border-collapse: collapse; width: 100%; max-width: 640px; margin-top: 8px; }
.config-table th, .config-table td {
  text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--color-border-muted);
  vertical-align: top;
}
.config-table th { font-size: var(--text-xs); color: var(--color-fg-muted); font-weight: 600; }
.shape-name { font-weight: 500; }
.shape-slug { font-size: var(--text-xs); font-family: var(--font-mono, monospace); margin-top: 2px; }
.badge-ready { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success); }
.badge-draft { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning); }

/* ── Client ▸ Brand breadcrumb switcher (#1554, items 3 + 4) ─────────────────
   Supersedes the two separate #1352/#1446 pills. One breadcrumb in the navy
   bar's top-right cluster, `▸`-separated, so the customer→brand nesting is the
   first thing the eye gets (item 4).

   Item 3 was "the switcher is too subtle — it felt like a hover". The old pill
   sat at 0.08 alpha on navy with no caret, so at rest it read as a label that
   happened to react to the mouse. The fixes here are all at-rest ones: a
   readable fill and border before any interaction, a persistent ▾ caret on
   anything switchable, and a chip with no caret at all when there is nothing to
   switch to — so the caret always means "this opens". Zero JS (<details>). */
.wsbc { display: flex; align-items: center; gap: 6px; min-width: 0; }
.wsbc-sep { color: var(--color-navy-muted); font-size: var(--text-xs); }
.wsbc-seg { position: relative; }
.wsbc-seg > summary { list-style: none; }
.wsbc-seg > summary::-webkit-details-marker { display: none; }

.wsbc-chip {
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 4px 10px; border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.26);
  white-space: nowrap; cursor: pointer;
}
.wsbc-seg[open] > .wsbc-chip,
.wsbc-chip:hover { background: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.4); }
/* Nothing to switch to → not a control: no caret, no pointer, recessed fill. */
.wsbc-chip.is-static { cursor: default; background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.16); }
.wsbc-label {
  font-size: var(--text-3xs); text-transform: uppercase; letter-spacing: 0.07em;
  font-weight: 700; color: var(--color-navy-muted);
}
.wsbc-name { font-size: var(--text-xs); font-weight: 600; color: #fff; }
.wsbc-caret { font-size: var(--text-3xs); color: var(--color-navy-muted); }
/* Amber = an operator scoped to one client, not admin-all. */
.wsbc-chip.is-acting { background: #b45309; border-color: #d97706; }
.wsbc-chip.is-acting .wsbc-label, .wsbc-chip.is-acting .wsbc-caret { color: #fed7aa; }

/* Popover under a segment (light card on the navy bar). */
.wsbc-menu {
  position: absolute; right: 0; z-index: 30; margin-top: 8px;
  min-width: 200px; display: flex; flex-direction: column; gap: 2px;
  padding: 6px; background: #fff; color: var(--color-fg);
  border: 1px solid var(--color-border); border-radius: 8px;
  box-shadow: 0 6px 20px rgba(15, 23, 42, 0.18);
}
.wsbc-option {
  display: block; padding: 6px 10px; border-radius: 6px;
  font-size: var(--text-sm); font-weight: 500; white-space: nowrap;
  color: var(--color-fg) !important; /* beat .topbar-right a (navy link) */
}
.wsbc-option:hover { background: var(--color-bg-subtle); text-decoration: none; }

/* The client popover carries a form (select + Switch) rather than brand links. */
.wsbc-menu-form { flex-direction: row; gap: 6px; align-items: center; min-width: 0; }
.wsbc-menu-form select { max-width: 240px; }

/* ─── Journey insights (advisory) panel — #1472, epic #1375 ─────────────────
   The advisory tier is deliberately monochrome. Insights DECORATE the audit
   (docs/jie-design.md § Dual architecture); reusing the success/warning/danger
   hues here would let an Observation read as a WARN and an advisory Blocker as
   a FAIL, which is exactly the confusion ADR-0056 D2's two-track split exists
   to prevent. Severity escalates by weight and contrast instead. */
.insight-panel {
  margin-top: 24px;
  padding: 16px;
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius);
  background: var(--color-bg);
}
.insight-panel h2 { margin: 0 0 6px; font-size: var(--text-lg); }
.insight-panel-intro { margin: 0 0 12px; font-size: var(--text-xs); max-width: 90ch; }

.insight-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.insight-entry {
  padding: 10px 12px;
  border: 1px solid var(--color-border-muted);
  border-left: 3px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-subtle);
}
.insight-header { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.insight-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--color-bg);
  color: var(--color-fg-muted);
  border: 1px solid var(--color-border-muted);
}
.insight-chip-observation { color: var(--color-fg-muted); }
.insight-chip-defect { color: var(--color-fg); border-color: var(--color-fg-muted); font-weight: 700; }
.insight-chip-blocker { background: var(--color-navy); color: var(--color-navy-fg); border-color: var(--color-navy-edge); font-weight: 700; }
.insight-chip-unrecognised { border-style: dashed; }

.insight-category code { font-size: var(--text-2xs); }
.insight-finding-class { font-size: var(--text-2xs); }
.insight-title { margin: 8px 0 4px; font-size: var(--text-sm); }
.insight-seen { margin: 4px 0; font-size: var(--text-2xs); }

.insight-grounding { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 3px; font-size: var(--text-xs); }
.insight-grounding .ref-kind {
  display: inline-block; min-width: 78px;
  font-size: var(--text-3xs); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-fg-muted);
}
.insight-grounding-missing { margin: 6px 0 0; font-size: var(--text-xs); }

/* Model prose. Collapsed by default and labelled non-forwardable per
   ADR-0056 D7 — free prose never leaves this element. */
.insight-hypothesis { margin-top: 8px; }
.insight-hypothesis > summary {
  cursor: pointer;
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-fg-muted);
}
.insight-hypothesis-text {
  margin: 6px 0 0;
  padding: 8px 10px;
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

/* ─── v2 foundation additions (#1553) ────────────────────────────────────
   New classes only — nothing above is changed, so no existing surface shifts.
   Wired into surfaces by the v2 flow issues (statusChip → Link Admin #1557;
   card/dataTable → Link-Health home #1555). */

/* Operational status chip (active/paused) — its own axis, NOT the health RAG.
   A paused link can still be green-healthy, so these must read differently from
   chip-ok/warn/fail (DoD item 10). */
.chip-active { background: #dbeafe; color: #1d4ed8; }
.chip-active .chip-dot { background: #2563eb; }
.chip-paused { background: var(--color-bg-subtle); color: var(--color-fg-muted); }
.chip-paused .chip-dot { background: var(--color-border); }
/* 'On request' — a Journey Audit link (#1726, ADR-0067 §g / ADR-0068 §a) has
   no roster state at all. Violet: neither roster blue/grey nor a health colour. */
.chip-on-request { background: #ede9fe; color: #6d28d9; }
.chip-on-request .chip-dot { background: #7c3aed; }

/* Placement + Journey lines (#1726) — under the URL on the board and on the
   link detail header; the detail's Journey note is the one line that says why
   the link has no roster state. */
.link-placement {
  display: block; max-width: var(--link-cell-max); margin-top: 2px;
  font-size: var(--text-2xs); color: var(--color-fg-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.coverage-coordinate { font-size: var(--text-sm); font-weight: 500; color: var(--color-fg); }
.history-placement { margin: 4px 0 0; max-width: 90ch; font-size: var(--text-sm); color: var(--color-fg-muted); overflow-wrap: anywhere; }
.history-subject { margin: 4px 0 0; font-size: var(--text-sm); color: var(--color-fg-muted); }
.history-journey-note { margin: 6px 0 0; font-size: var(--text-sm); color: #6d28d9; font-weight: 500; }
.link-edit-journey-note { margin-top: 8px; }

/* dataTable() empty-state row. */
.data-table-empty { text-align: center; padding: 24px 12px; color: var(--color-fg-muted); }

/* card() — bordered content panel (no prior .card existed). */
.card {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  padding: 16px;
}
.card + .card { margin-top: 16px; }
.card-header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 12px;
}
.card-title { margin: 0; font-size: var(--text-lg); font-weight: 600; }

/* disclosure() — zero-JS expander whose affordance is part of the primitive: a
   full-width, hoverable bar that NAMES what opening reveals, plus a chevron
   rotated by [open]. The label swap is two spans toggled in CSS, so the state
   reads correctly without a line of client JS (DoD item 8). */
.disclosure-summary { display: block; cursor: pointer; list-style: none; }
.disclosure-summary::-webkit-details-marker { display: none; }
.disclosure-summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.disclosure-cta {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 15px;
  border-top: 1px solid var(--color-border-muted);
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--color-bg-subtle);
  color: var(--color-accent);
  font-size: var(--text-sm); font-weight: 600;
}
.disclosure-summary:hover .disclosure-cta { background: var(--color-bg-hover); }
.disclosure[open] .disclosure-cta { border-radius: 0; }
.disclosure[open] .disclosure-cta-closed { display: none; }
.disclosure:not([open]) .disclosure-cta-open { display: none; }
.disclosure-chev {
  width: 15px; height: 15px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
  transition: transform 120ms ease;
}
.disclosure[open] .disclosure-chev { transform: rotate(90deg); }
.disclosure-body { padding: 4px 15px 14px 15px; }
@media (prefers-reduced-motion: reduce) {
  .disclosure-chev { transition: none; }
}

/* ─── Reports: one card per cycle run (#1556, DoD item 6) ─────────────────────
   The card drops its own padding so the disclosure CTA can run edge to edge the
   way it does on a cockpit widget — the bar has to look like the bottom of the
   card, not a boxed-in button. `overflow:hidden` lets the card's radius clip
   the bar's square bottom corners. */
.rp-runs { display: flex; flex-direction: column; gap: 8px; }
.rp-runs .card + .card { margin-top: 0; }
.rp-run { padding: 0; overflow: hidden; }
.rp-run-head {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 10px 14px;
}
/* The run's identity. When + type stay side by side — a timestamp over a badge
   spent a whole line to say one thing, and a list of reports whose rows all
   carry the same date is exactly where wasted height hurts most.
   #1636 finding 5 gave that first line something worth its height: the name of
   what the report covers, which is the only part of a row that differs between
   two same-day runs. Rows with no link keep the flat one-line shape. */
.rp-run-id { display: flex; align-items: baseline; gap: 10px; flex: 0 0 auto; min-width: 230px; }
.rp-run-id-named { flex-direction: column; align-items: flex-start; gap: 2px; min-width: 260px; }
.rp-links { font-weight: 600; font-size: var(--text-md); color: var(--color-fg); line-height: 1.3; }
/* Demoted to meta once a name leads: same information, quieter, one line. */
.rp-run-id-named .rp-meta { display: flex; align-items: baseline; gap: 10px; font-size: var(--text-sm); color: var(--color-fg-muted); }
.rp-run-id-named .rp-when { font-weight: 500; }
.rp-meta { display: flex; align-items: baseline; gap: 10px; }
.rp-when { font-weight: 600; }
/* The summary takes the slack so the primary action stays hard right. */
.rp-summary { flex: 1 1 220px; display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: var(--text-sm); }
.rp-count { display: inline-flex; align-items: center; white-space: nowrap; }
/* margin-left:auto is a no-op while the summary is growing beside it; it earns
   its keep once the head wraps, keeping the action right-aligned instead of
   stranding it under the counts. */
.rp-run-head .btn { flex: 0 0 auto; margin-left: auto; }

/* The revealed layer: destination first, then why you would go there. */
.rp-evidence { list-style: none; margin: 6px 0 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.rp-evidence-item { display: flex; flex-direction: column; gap: 2px; }
.rp-evidence-link { font-weight: 600; }
.rp-evidence-why { font-size: var(--text-sm); }

/* ── Per-link edit + archive (#1557 item 11) ────────────────────────────────
   Two new surfaces reached from a Link Admin row. Both lean on existing
   primitives (.config-section, .mask-* form vocabulary, .card), so what is
   added here is only what had no class: the read-only URL block, the quiet
   row-level Archive control, and the two destructive treatments. */

/* The one-way door. On the edit page it is a ghost button that must not compete
   with Save; on the confirm page it IS the primary action of that page, so the
   primary variant fills in danger red rather than inheriting accent blue (which
   left red text on a blue field). */
.btn.destructive { color: var(--color-danger); border-color: var(--color-border); }
.btn.destructive:hover { background: var(--color-danger-bg); border-color: var(--color-danger); }
.btn-primary.destructive {
  background: var(--color-danger); border-color: var(--color-danger); color: var(--color-accent-fg);
}
.btn-primary.destructive:hover {
  background: var(--color-error); border-color: var(--color-error); color: var(--color-accent-fg);
}

/* A URL shown, not edited — the identity of the link (ADR-0043 §c). Reads as
   data rather than as a disabled input, which would invite clicking it. */
.link-url-static {
  margin: 4px 0 0 0; padding: 8px 10px;
  background: var(--color-bg-subtle); border: 1px solid var(--color-border-muted);
  border-radius: var(--radius);
}
.link-url-static code { font-size: var(--text-xs); color: var(--color-fg-muted); }

/* Archive lives at the bottom of the edit page, fenced off from the save flow
   so it cannot be hit while scanning the form. */
.danger-zone { border-top: 1px solid var(--color-border); padding-top: 16px; }

/* The confirm page: one subject, the consequences as a list, the two ways out. */
.confirm-card { max-width: 60ch; margin-top: 16px; }
.confirm-subject { margin: 0 0 4px 0; }
.confirm-effects { margin: 12px 0; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; }

/* ── Link import preview (#1636 findings 1-3) ────────────────────────────────
   The import screen carried no rules at all, which is most of why it read as
   unfinished: its "filter chips" were unstyled anchors, so the one row on the
   page that was NOT a choice looked exactly like five links. The chips are gone
   (views/link-import.ts § importSummary); what stays needs enough shape to read
   as the three registers it now has — a setup statement, a count, and a
   per-group explanation. */
.import-shape-note {
  background: var(--color-bg-subtle);
  border: 1px solid var(--color-border-muted);
  border-left: 3px solid var(--color-fg-muted);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin: 16px 0 12px;
  line-height: 1.5;
}
.import-shape-note .shape-slug { font-size: 0.85em; }
.import-summary {
  margin: 12px 0 4px;
  font-size: 0.95rem;
}
.verdict-section { margin-top: 28px; }
.verdict-section-note {
  margin: 2px 0 10px;
  font-size: 0.88rem;
  line-height: 1.45;
}
/* The one group that asks the reader for a decision rather than reporting one. */
.verdict-section--warn .verdict-section-note { color: var(--color-warning); }

/* ── Link import intake (#1636 item 12) ──────────────────────────────────────
   The paste box is the screen's primary input and it was rendering at the
   browser's default textarea width — about 20 characters — beside two
   full-width inputs. A `rows="8"` box 20ch wide reads as an afterthought, and
   nothing in the stylesheet said otherwise because the intake form had no rules
   at all. Width comes from the form, not from a `cols` attribute; the max-width
   keeps a pasted URL list readable rather than letting it span an ultrawide. */
.import-inputs { display: flex; flex-direction: column; gap: 20px; max-width: 70ch; }
.import-input-group { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.import-input-group > label { font-weight: 600; font-size: var(--text-sm); }
.import-input-group > p { margin: 0; }
.import-inputs textarea,
.import-inputs input[type="url"] {
  width: 100%;
  box-sizing: border-box;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: var(--text-sm);
  line-height: 1.5;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-fg);
  text-align: left;
}
.import-inputs textarea { min-height: 11em; resize: vertical; }
.import-actions { margin-top: 20px; }

/* ── Coverage checkbox grid (#1636 item 10) ──────────────────────────────────
   Shared by the standalone coverage editor and the per-link Edit form. The
   grid had no rules either: twelve countries stacked one per line turned the
   most-edited setting on the form into a column of scrolling. */
.coverage-fieldset {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));
  gap: 4px 16px;
  border: 1px solid var(--color-border-muted);
  border-radius: var(--radius);
  padding: 10px 14px 14px;
  margin: 0 0 14px;
}
.coverage-fieldset > legend { grid-column: 1 / -1; font-weight: 600; font-size: var(--text-sm); padding: 0 6px; }
.coverage-checkbox { display: flex; align-items: center; gap: 8px; font-size: var(--text-sm); padding: 3px 0; }

/* The audit-setup footnote (#1636 item 11) — a pointer, not a control. */
.audit-setup-note { margin: 8px 0 0; font-size: var(--text-sm); max-width: 68ch; }
