/* Kennel UI chassis — the ported SUBSET of the old app's Fjord design system
   (watchdog.canine.dev saas/Watchdog.Api/wwwroot/app.css). No new design language: tokens, rail,
   cards, tabs, page-head, dialogs, band vars, cai-ladder and the light/dark themes are copied;
   only the dev-auth banner and the chassis auth cards are new rules. theme.js flips data-theme
   before first paint. Served as RCL static web assets (_content/Kennel.Ui/app.css). */
@font-face {
  font-family: "Schibsted Grotesk";
  src: url("fonts/schibsted-var.woff2") format("woff2-variations");
  font-weight: 400 900;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/jetbrains-var.woff2") format("woff2-variations");
  font-weight: 100 800;
  font-display: swap;
}
:root {
  /* neutrals — dark "graphite" */
  --bg:#15191E; --surface:#1C2127; --surface-2:#232A31;
  --border:#2D353E; --border-strong:#3A444F;
  --ink:#E4E9ED; --ink-soft:#B9C2CB; --muted:#8694A1; --heading:#F2F5F8;
  /* steel */
  --accent:#7FAACE; --accent-ink:#9BBEDB; --accent-wash:#1E2C39; --accent-strong:#B7D2E8;
  --on-accent:#15191E;
  /* bands: strong / wash / on-wash */
  --band-exemplary:#4D9B74; --band-exemplary-wash:#16352A; --band-exemplary-ink:#A9D9C2;
  --band-healthy:#6FAE85;  --band-healthy-wash:#1A3326;  --band-healthy-ink:#B5DCC4;
  --band-fair:#CFA53C;     --band-fair-wash:#393012;     --band-fair-ink:#E8D49A;
  --band-poor:#CF7858;     --band-poor-wash:#3A2118;     --band-poor-ink:#EFC4B4;
  --band-critical:#D86A60; --band-critical-wash:#3A1A18; --band-critical-ink:#F0BFBA;
  --band-exemplary-solid-ink:#14181D; --band-healthy-solid-ink:#14181D; --band-fair-solid-ink:#14181D;
  --band-poor-solid-ink:#14181D; --band-critical-solid-ink:#14181D;
  /* band TEXT tokens — colour for band-keyed numerals/labels; dark = saturated (already AA on dark) */
  --band-exemplary-text:#4D9B74; --band-healthy-text:#6FAE85; --band-fair-text:#CFA53C; --band-poor-text:#CF7858; --band-critical-text:#D86A60;
  /* CAI ladder marker: THEME-FIXED dark ink + explicit white casing — defined once on :root and
     NOT overridden in the light theme, so the dark-badge-on-white-ring premise holds in BOTH themes. */
  --mk:#1C2522; --mk-on:#FFFFFF;
  /* shape & depth */
  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-full:999px;
  --shadow-overlay:0 4px 16px rgb(0 0 0 / .35);
  --shadow-modal:0 16px 48px rgb(0 0 0 / .5);
  /* type */
  --font-ui:"Schibsted Grotesk",system-ui,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,monospace;
  --fs-2xs:11px; --fs-xs:12px; --fs-sm:13px; --fs-md:14px; --fs-lg:16px;
  --fs-xl:20px; --fs-2xl:25px; --fs-3xl:31px; --fs-4xl:39px; --fs-num:56px;
  --control-h:36px; --control-pad-y:8px; --control-pad-x:10px;
  /* spacing scale */
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:24px; --space-6:32px;
  /* legacy aliases (kept so ported component rules recolour from this block alone) */
  --panel: var(--surface); --text: var(--ink); --text-soft: var(--ink-soft);
  color-scheme: dark;
}
:root[data-theme="light"] {
  /* neutrals — light "paper" */
  --bg:#FCFCFD; --surface:#F5F7F9; --surface-2:#EDF0F3;
  --border:#E1E6EB; --border-strong:#CBD3DA;
  --ink:#1C2126; --ink-soft:#434B54; --muted:#616B76; --heading:#14181D;
  --accent:#4682B4; --accent-ink:#2F5D85; --accent-wash:#EAF1F7; --accent-strong:#264B6B;
  --on-accent:#FFFFFF;
  --band-exemplary:#1E6B47; --band-exemplary-wash:#DCEDE4; --band-exemplary-ink:#0E2A1C;
  --band-healthy:#55966B;  --band-healthy-wash:#E2F0E7;  --band-healthy-ink:#16331F;
  --band-fair:#B58A1F;     --band-fair-wash:#F6ECD4;     --band-fair-ink:#3D2E08;
  --band-poor:#B5563A;     --band-poor-wash:#F6E0D7;     --band-poor-ink:#3E1D11;
  --band-critical:#AD3A34; --band-critical-wash:#F5DAD7; --band-critical-ink:#3A1210;
  --band-exemplary-solid-ink:#FCFCFD; --band-healthy-solid-ink:#14181D; --band-fair-solid-ink:#14181D;
  --band-poor-solid-ink:#FCFCFD; --band-critical-solid-ink:#FCFCFD;
  /* band TEXT tokens — darkened so band-keyed numerals clear WCAG AA on light surfaces */
  --band-exemplary-text:#1E6B47; --band-healthy-text:#2E6A43; --band-fair-text:#806012; --band-poor-text:#984530; --band-critical-text:#AD3A34;
  --shadow-overlay:0 4px 16px rgb(20 25 30 / .10);
  --shadow-modal:0 16px 48px rgb(20 25 30 / .16);
  color-scheme: light;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 400 var(--fs-md)/1.5 var(--font-ui);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
code { background: var(--surface-2); padding: 1px 5px; border-radius: var(--r-sm); font: 500 var(--fs-xs) var(--font-mono); }
.num, td.num, .t-num { font-variant-numeric: tabular-nums lining-nums; }
/* Icons: Lucide via the inlined sprite. Stroke inherits text colour; never filled. */
.icon { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2;
        stroke-linecap: round; stroke-linejoin: round; flex: none; vertical-align: -3px; }
.icon-20 { width: 20px; height: 20px; }
.icon-24 { width: 24px; height: 24px; }
.icon-48 { width: 48px; height: 48px; stroke-width: 1.5; }
/* The Canine badge symbol is a filled mark, not a stroked glyph. */
.icon.icon-badge { fill: currentColor; stroke: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}
.muted { color: var(--muted); }
.small { font-size: var(--fs-sm); }

/* Brand lockup — badge spanning two rows, product name top-right, byline beneath. */
.brand {
  position: relative;
  display: inline-grid; grid-template-columns: auto auto; column-gap: 7px; align-items: center;
  font-size: 18px; font-weight: 600; letter-spacing: -0.01em;
}
.brand a, .brand .brand-mark, .brand .brand-text { color: inherit; text-decoration: none; }
.brand .brand-mark { grid-row: 1 / 3; display: inline-flex; align-items: center; color: var(--heading); }
.brand .brand-mark .icon { width: 24px; height: 27px; }
.brand .brand-text { grid-column: 2; grid-row: 1; line-height: 1.05; align-self: end; }
.brand .byline { grid-column: 2; grid-row: 2; align-self: start; font-size: 0.6rem; font-weight: 400; color: var(--muted); line-height: 1.2; white-space: nowrap; }
.brand a:hover { opacity: .8; }

/* Ghost-loading skeletons. */
@keyframes wd-shimmer { 0% { background-position: -200px 0; } 100% { background-position: 200px 0; } }
.skel { background: linear-gradient(90deg, var(--border) 0px, var(--surface-2) 80px, var(--border) 160px); background-size: 400px 100%; animation: wd-shimmer 1.2s linear infinite; border-radius: var(--r-sm); display: inline-block; }
.skel-line { height: 14px; width: 100%; margin: 6px 0; }
.skel-line.short { width: 40%; }
.skel-box { height: 60px; width: 100%; margin: 8px 0; border-radius: var(--r-sm); }

/* ── Buttons — the ONE system. btn = secondary (outline) by default. ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font: 500 var(--fs-md)/1.2 var(--font-ui); color: var(--ink);
  background: transparent; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 8px 14px; cursor: pointer; text-decoration: none;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.btn:hover { background: var(--surface-2); text-decoration: none; }
.btn-primary { background: var(--accent-strong); border-color: var(--accent-strong); color: var(--on-accent); font-weight: 600; }
.btn-primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.btn-quiet { border-color: transparent; color: var(--muted); }
.btn-quiet:hover { color: var(--ink); background: var(--surface-2); }
.btn-danger { border-color: var(--band-critical); color: var(--band-critical); background: transparent; }
.btn-danger:hover { background: var(--band-critical-wash); }
.btn-link { border-color: transparent; background: transparent; color: var(--muted); padding: 2px 4px; font-size: var(--fs-sm); }
.btn-link:hover { color: var(--ink); background: transparent; text-decoration: underline; }
.btn-sm, .btn.sm { padding: 6px 10px; font-size: var(--fs-sm); }
.btn-lg { padding: 12px 20px; font-size: var(--fs-lg); }
.btn-block { display: flex; width: 100%; text-align: center; }
.btn:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; }
.row-actions { display: inline-flex; gap: .35rem; align-items: center; flex-wrap: wrap; }
.row-actions form { display: inline-flex; gap: .35rem; align-items: center; margin: 0; }
.theme-toggle { padding: 6px; }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: inline-block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* ── Chips — the ONE system + band/ink/fill utilities. ── */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-xs); font-weight: 600; line-height: 1.4;
  border-radius: var(--r-full); padding: 2px 10px; white-space: nowrap;
}
.chip-neutral { background: var(--surface-2); color: var(--muted); }
.band-exemplary { background: var(--band-exemplary-wash); color: var(--band-exemplary-ink); }
.band-healthy   { background: var(--band-healthy-wash);   color: var(--band-healthy-ink); }
.band-fair      { background: var(--band-fair-wash);      color: var(--band-fair-ink); }
.band-poor      { background: var(--band-poor-wash);      color: var(--band-poor-ink); }
.band-critical  { background: var(--band-critical-wash);  color: var(--band-critical-ink); }
.band-neutral   { background: var(--surface-2);           color: var(--muted); }
.chip-solid.band-exemplary, .band-bar.band-exemplary { background: var(--band-exemplary); color: var(--band-exemplary-solid-ink); }
.chip-solid.band-healthy,   .band-bar.band-healthy   { background: var(--band-healthy);   color: var(--band-healthy-solid-ink); }
.chip-solid.band-fair,      .band-bar.band-fair      { background: var(--band-fair);      color: var(--band-fair-solid-ink); }
.chip-solid.band-poor,      .band-bar.band-poor      { background: var(--band-poor);      color: var(--band-poor-solid-ink); }
.chip-solid.band-critical,  .band-bar.band-critical  { background: var(--band-critical);  color: var(--band-critical-solid-ink); }
.ink-exemplary { color: var(--band-exemplary-text); } .ink-healthy { color: var(--band-healthy-text); }
.ink-fair { color: var(--band-fair-text); } .ink-poor { color: var(--band-poor-text); } .ink-critical { color: var(--band-critical-text); }
.ink-neutral { color: var(--muted); } .ink-accent { color: var(--accent-ink); }
.fill-exemplary { background: var(--band-exemplary); } .fill-healthy { background: var(--band-healthy); }
.fill-fair { background: var(--band-fair); } .fill-poor { background: var(--band-poor); }
.fill-critical { background: var(--band-critical); } .fill-accent { background: var(--accent); }

/* ── Discounts "in neon" — coupon & referral savings glow green so they pop against the muted plan
   rows (a saved € is a good state, so it borrows the healthy/exemplary band, deliberately louder). ── */
.discount-neon {
  color: var(--band-healthy-text);
  font-weight: 700;
  text-shadow: 0 0 7px color-mix(in oklab, var(--band-healthy) 60%, transparent);
}
.discount-referral {
  color: var(--band-exemplary-text);
  text-shadow: 0 0 7px color-mix(in oklab, var(--band-exemplary) 60%, transparent);
}

/* ── The site-wide setup nudge (the "neon sign") — a soft banner the shell shows a signed-in user
   until they choose a cohort. Borrows the healthy-band glow so it invites rather than warns. ── */
.nudge-neon {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  border: 1px solid color-mix(in oklab, var(--band-healthy) 55%, transparent);
  box-shadow: 0 0 12px color-mix(in oklab, var(--band-healthy) 30%, transparent),
              inset 0 0 18px color-mix(in oklab, var(--band-healthy) 8%, transparent);
}
.nudge-neon > span {
  color: var(--band-healthy-text);
  font-weight: 600;
  text-shadow: 0 0 7px color-mix(in oklab, var(--band-healthy) 45%, transparent);
}

/* ── CAI band ladder + "you are here" marker (old .cai-ladder, verbatim) ──────────────────────────
   A fixed worst→best rail of the five band colours; position on the rail IS the reading. The
   diamond is the compact card marker; the Score pin is the full variant. */
.cai-ladder { --mk-foot: 9px; margin: 6px 0 2px; }
.cai-rail { position: relative; height: 11px; overflow: visible; }
.cai-segs { display: flex; height: 11px; border-radius: 6px; overflow: hidden; }
.cai-segs > i { flex: 1; display: block; }
.cai-segs > i.seg-critical  { background: var(--band-critical); }
.cai-segs > i.seg-poor      { background: var(--band-poor); }
.cai-segs > i.seg-fair      { background: var(--band-fair); }
.cai-segs > i.seg-healthy   { background: var(--band-healthy); }
.cai-segs > i.seg-exemplary { background: var(--band-exemplary); }
.cai-caps { display: flex; justify-content: space-between; font-size: var(--fs-2xs); color: var(--muted); margin-top: 9px; }
.cai-mk { position: absolute; top: 0; bottom: 0; width: 0; z-index: 3; pointer-events: none; color: var(--mk); }
/* Score pin — diamond on the rail, drop-line, score badge above; all white-cased */
.cai-pin .cai-pin-foot {
  position: absolute; top: 50%; left: 0; width: var(--mk-foot); height: var(--mk-foot);
  transform: translate(-50%, -50%) rotate(45deg); background: var(--mk); box-shadow: 0 0 0 2px var(--mk-on);
}
.cai-pin .cai-pin-line {
  position: absolute; bottom: 50%; left: 0; width: 3px; height: 12px; transform: translateX(-50%);
  background: var(--mk); border-radius: 2px 2px 0 0; box-shadow: 0 0 0 1.5px var(--mk-on);
}
.cai-pin .cai-pin-badge {
  position: absolute; bottom: calc(50% + 12px); left: 0; transform: translateX(-50%);
  min-width: 25px; height: 22px; padding: 0 7px; display: flex; align-items: center; justify-content: center;
  background: var(--mk); color: var(--mk-on); font: 700 13px/1 var(--font-ui); border-radius: 6px; white-space: nowrap;
  box-shadow: 0 0 0 2px var(--mk-on), 0 2px 5px rgb(20 40 30 / .3);
}
.cai-pin .cai-pin-badge::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--mk);
}
/* White diamond (cards) — filled with the SCORE's band colour (--dia) + white outline. */
.cai-diamond .cai-diamond-foot {
  position: absolute; top: 50%; left: 0; width: 14px; height: 14px;
  transform: translate(-50%, -50%) rotate(45deg); background: var(--dia, var(--mk-on)); border: 2.5px solid var(--mk-on);
  border-radius: 2px; box-shadow: 0 1px 4px rgb(15 25 20 / .45);
}
.cai-diamond::before {
  content: ""; position: absolute; left: 0; bottom: calc(50% + 6px); width: 2px; height: 10px;
  transform: translateX(-50%); background: var(--dia, var(--mk)); border-radius: 1px 1px 0 0;
  box-shadow: 0 0 0 1px var(--mk-on);
}
.cai-ladder.compact .cai-caps { display: none; }
.wd-card .cai-ladder { margin: 16px 0 16px; }
.wd-card .cai-ladder + .hd-spark { margin-top: 0; }

/* Visually-hidden utility (screen-reader only) — e.g. the sparkline trend summary. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* a11y hardening: forced-colors + prefers-contrast fall back to system tokens. */
@media (prefers-contrast: more) {
  .cai-pin .cai-pin-foot, .cai-pin .cai-pin-line, .cai-pin .cai-pin-badge { box-shadow: 0 0 0 2px var(--mk-on); }
}
@media (forced-colors: active) {
  .cai-segs > i { forced-color-adjust: none; }
  .cai-pin .cai-pin-foot, .cai-pin .cai-pin-line, .cai-pin .cai-pin-badge { background: CanvasText; color: Canvas; box-shadow: 0 0 0 2px Canvas; }
  .cai-pin .cai-pin-badge::after { border-top-color: CanvasText; }
}

/* ── In-house confirm/alert dialog (kennel-ui.js provides KennelDialog). ── */
dialog.wd-dialog {
  background: var(--surface); color: var(--ink); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-modal); padding: 20px;
  max-width: min(440px, 90vw); font: 400 var(--fs-md)/1.5 var(--font-ui);
}
dialog.wd-dialog::backdrop { background: rgba(0, 0, 0, .55); }
dialog.wd-dialog .wd-dialog-msg { margin: 0 0 16px; white-space: pre-line; }
dialog.wd-dialog .wd-dialog-actions { display: flex; gap: 10px; justify-content: flex-end; }

main { max-width: 1280px; margin: 0 auto; padding: 24px; }

/* Breadcrumb-as-heading: the crumb's active segment IS the page title. */
.crumbs { max-width: 1280px; margin: 0 auto; padding: 14px 24px 0; font-size: 13px; color: var(--muted);
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--text); text-decoration: none; }
.crumbs .sep { margin: 0 8px; opacity: .5; }
.crumbs .here { font-size: 1.45rem; font-weight: 650; color: var(--heading); letter-spacing: -0.01em; }

/* Shared empty / zero-data state (EmptyState.razor). */
/* Full width (design standard 2026-08-19): a narrow centered box made whichever page hit its empty
   state look like a different product. The box now spans the content column like every panel; the
   TEXT inside stays centered and measure-capped. */
.empty-state { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px;
  padding: 40px 24px; margin: 24px 0; }
.empty-state-title, .empty-state-desc { max-width: 52ch; }
.empty-state-icon { width: 30px; height: 30px; fill: none; stroke: currentColor; stroke-width: 1.5;
  color: var(--muted); opacity: .7; }
.empty-state-title { font-size: var(--fs-lg); font-weight: 600; color: var(--text); }
.empty-state-desc { font-size: var(--fs-sm); color: var(--muted); line-height: 1.55; }
.empty-state-desc a { color: var(--accent-strong); }
.empty-state-action { margin-top: 6px; }
/* Page-level empty state = the SAME solid panel chrome as .settings-section, so an empty page keeps
   the page anatomy (owner 2026-08-19: bare dashed boxes made c4/threat-model read as a different
   product). Nested inside a panel it stays the dashed inset (the Diagnosis treatment). */
.empty-state-bordered { border: 1px solid var(--border); border-radius: var(--r-md); background: var(--panel); }
.settings-section .empty-state-bordered { border: 1px dashed color-mix(in srgb, var(--border), var(--text) 18%); background: transparent; margin: 8px 0; }
h1 { font-size: 22px; margin: 8px 0 20px; }
h2 { font-size: 16px; margin: 32px 0 14px; border-bottom: 1px solid var(--border); padding-bottom: 8px; }

/* ── A row of headline facts: label above, number, context below ─────────────────────────────────
   Used by AgreementReport, LanguageTraining, LanguageTrainingOverview, LanguageTrainingNoise and the
   rater-karma console. It had NO rules anywhere in this sheet, so every one of those pages rendered its
   facts as inline spans that butt together — "Disagreement4.2%gate ≤ 10% · 8 of 190" as one run of text.
   The same defect .hd-meta already documents for a different row, and invisible in a unit test.
   ★ .ok/.warn/.bad are set by AgreementReport on .v and coloured here, so a number that carries a
   judgement carries it in BOTH themes: the band-*-text tokens are redefined in the light block, which a
   hand-picked hex would not be. */
.facts { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5); }
.fact { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fact .k { font-size: var(--fs-2xs); color: var(--muted); text-transform: uppercase;
           letter-spacing: .05em; font-weight: 650; }
.fact .v { font-size: var(--fs-2xl); font-weight: 700; line-height: 1.1;
           color: var(--heading); letter-spacing: -.01em; }
.fact .v.ok   { color: var(--band-healthy-text); }
.fact .v.warn { color: var(--band-fair-text); }
.fact .v.bad  { color: var(--band-critical-text); }
.fact .small  { font-size: var(--fs-xs); }

/* ── Cards ── */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.card {
  display: block; background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 16px; color: var(--text);
}
a.card:hover { border-color: var(--accent); text-decoration: none; }
.card-top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.card .repo { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 auto; }
.card .repo strong { color: var(--text); }

/* ── Assay decision-reports GALLERY: onramp row + card internals (buyer-UX redesign 2026-07). Card
   name/source, a verdict row, and a price footer priced-before-you-buy — only the pieces the shared
   .card / .chip / .btn primitives don't already provide. ── */
.onramp { display: flex; gap: 9px; flex-wrap: wrap; margin: 4px 0 12px; }
.card .card-top { align-items: flex-start; }
.card .nm { display: inline-block; font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--text); word-break: break-word; line-height: 1.3; }
.card .nm.prod { font-family: inherit; font-size: 15px; }
.card a.nm:hover { color: var(--accent-ink); }
.card .src { font-size: var(--fs-xs); color: var(--muted); margin-top: 2px; }
.card .cai-row { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); margin-top: 10px; }
.card .cai-row .score { font-family: var(--font-mono); font-weight: 600; color: var(--text); }
.card .price { margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border); }
.card .price .amt { font-family: var(--font-mono); font-weight: 600; font-size: 15px; }
.card .price .amt.incl { color: var(--band-healthy-text); font-family: inherit; }
.card .price .amt.free { color: var(--accent-ink); }
.card .price .note { font-size: var(--fs-xs); color: var(--muted); margin-top: 1px; }
.card .price .free { color: var(--accent-ink); font-weight: 600; }
.card .cta { margin-top: 11px; }
.card .cta form { margin: 0; }

/* ---- shared repo card (ScoreCard.razor): the hero-demo anatomy on every surface ---- */
.wd-card .hd-top { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Warning chips replacing the band chip (2026-08-19): wrap onto their own line rather than squeezing
   the repo NAME to an ellipsis — the name is the card's identity and always wins the width fight. */
.wd-card .hd-chips { display: inline-flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; margin-left: auto; }
.wd-card .hd-name { min-width: 0; line-height: 1.25; color: var(--text); }
.wd-card .hd-name .repo-name { display: block; font-weight: 600; font-size: 1.05em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wd-card .hd-name .owner { display: block; color: var(--muted); font-weight: 400; font-size: .85em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wd-card .hd-scoreline { margin-top: 4px; }
.wd-card .hd-score { font-size: var(--fs-num); font-weight: 700; line-height: 1.1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums lining-nums; }
.wd-card .hd-unit { font-size: var(--fs-lg); color: var(--muted); font-weight: 400; }
.wd-card .hd-bar { height: 6px; border-radius: var(--r-full); margin: 10px 0 12px; }
.wd-card .hd-spark { width: 100%; min-height: 34px; display: block; margin: 2px 0 6px; }
.wd-card .hd-rows { margin-top: 6px; }
.wd-card .hd-row { display: flex; justify-content: space-between; font-size: var(--fs-sm); padding: 6px 0; border-bottom: 1px solid var(--border); }
.wd-card .hd-row:last-child { border-bottom: 0; }
.wd-card .hd-row .num { font-weight: 600; }
/* A row of separate facts, so it needs the same flex+gap its siblings above and below use.
   Without it the spans butt together and the public embed reads "15 June 202636.0k lines"
   as one string — invisible in the app, where this row holds .chip children that carry
   their own padding, and visible on the marketing card, where the facts are bare spans. */
.wd-card .hd-meta { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 8px; }
.wd-card .hd-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
/* Server-side SVG sparkline (Sparkline.razor) — replaces the old uPlot canvas stack. */
.hd-spark svg { display: block; width: 100%; height: 100%; }

/* ── Repo wall (W1) — the full card + wall anatomy ported from old-SaaS app.css verbatim ────────── */
/* Card economics row: asset value + bus factor. */
.wd-card .card-econ { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 6px; }
/* Urgency action-flags — critical-toned (regression, CVE, secrets, build broken). */
.wd-card .alerts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.wd-card .alert { font-size: 11px; color: var(--band-critical-text); border: 1px solid var(--band-critical);
  border-radius: var(--r-sm); padding: 1px 6px; white-space: nowrap; }

/* OSS card wrapper + discrete corner "remove from your wall" control. */
.oss-card { position: relative; display: block; }
.oss-card .wd-card-link { width: 100%; }
.oss-remove {
  position: absolute; top: -8px; right: -8px; z-index: 3;
  width: 24px; height: 24px; padding: 0; line-height: 1; font-size: 16px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-full); border: 1px solid var(--border);
  background: var(--panel); color: var(--muted); cursor: pointer;
  opacity: 0; transition: opacity .12s ease, color .12s ease, border-color .12s ease;
}
.oss-card:hover .oss-remove, .oss-card:focus-within .oss-remove, .oss-remove:focus { opacity: 1; }
.oss-remove:hover { color: var(--band-critical-text); border-color: var(--band-critical); }

/* Live filter: search box + toggleable alert-tag chips. */
.repo-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 4px 0 16px; }
.repo-search { flex: 1 1 260px; max-width: 420px; padding: 8px 12px; border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--bg); color: var(--text); font: inherit; }
.repo-search:focus { outline: none; border-color: var(--accent); }
.repo-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.repo-tag { cursor: pointer; border: 1px solid var(--border); background: var(--panel); color: var(--muted); }
.repo-tag.on, .repo-tag[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-wash); color: var(--ink); }

/* Shared list controls (search + facet chips + paging) — the reusable <ListControls> chrome. Reuses
   the .repo-filter/.repo-search/.repo-tag primitives; adds facet grouping, the live count and the pager. */
.list-controls { margin: 4px 0 16px; }
.list-controls .repo-filter { margin: 0; }
.list-facet { display: flex; flex-wrap: wrap; gap: 6px; }
.list-count { margin: 8px 0 0; }
.list-more { display: flex; justify-content: center; margin: 16px 0 4px; }

/* Multiple-choice facet dropdown (a native <details> disclosure holding checkboxes). */
.facet-dropdown { position: relative; display: inline-block; }
.facet-dropdown > summary { list-style: none; cursor: pointer; user-select: none; white-space: nowrap; }
.facet-dropdown > summary::-webkit-details-marker { display: none; }
.facet-dropdown > summary::after { content: "▾"; margin-left: 6px; font-size: 10px; opacity: .7; }
.facet-dropdown[open] > summary { border-color: var(--accent); color: var(--text); }
.facet-dropdown .facet-menu { position: absolute; z-index: 60; margin-top: 4px; min-width: 190px; max-height: 300px;
  overflow-y: auto; background: var(--panel); border: 1px solid var(--border-strong); border-radius: 8px;
  box-shadow: 0 8px 26px rgba(0,0,0,.18); padding: 6px; display: flex; flex-direction: column; gap: 1px; }
.facet-opt { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 6px; cursor: pointer;
  color: var(--text); font-size: var(--fs-sm); font-weight: 400; }
.facet-opt:hover { background: var(--surface-2); }
.facet-opt input { flex: none; margin: 0; }
.facet-count { color: var(--accent); font-weight: 600; }

/* Estate-synthesis header: the owned-portfolio €-verdict on the wall (target D4). */
.estate-synthesis { margin-bottom: 16px; }
.estate-synthesis .estate-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.estate-synthesis .estate-head h2 { margin: 0; border: 0; padding: 0; }
.estate-synthesis .estate-cai { display: inline-flex; align-items: center; gap: 8px; font-size: var(--fs-lg); }
.estate-synthesis .estate-stats { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 8px; font-size: var(--fs-sm); }

/* Modals + page header. */
dialog.wd-modal { border: 1px solid var(--border); border-radius: var(--r-md); background: var(--panel); color: var(--text); padding: 22px 24px; max-width: 460px; width: calc(100% - 32px); box-shadow: 0 12px 40px rgba(0,0,0,.35); }
dialog.wd-modal.wd-modal-wide { max-width: 560px; }

/* ── Right-side slide-in drawer (a <dialog> variant) ─────────────────────────────────────────────
   Used by the Deliveries wall: a row opens a per-delivery drawer with its detail + actions. Same
   showModal()/Esc/backdrop semantics as .wd-modal (so kennel-ui.js needs no new JS), but pinned to
   the right edge, full height, and it slides in via a transform transition. */
dialog.wd-drawer { position: fixed; top: 0; right: 0; left: auto; height: 100%; max-height: 100%;
  width: 420px; max-width: calc(100% - 24px); margin: 0; border: 0; border-left: 1px solid var(--border);
  border-radius: 0; background: var(--panel); color: var(--text); padding: 22px 24px; overflow-y: auto;
  box-shadow: -12px 0 40px rgba(0,0,0,.35);
  transform: translateX(100%); transition: transform .22s ease; }
dialog.wd-drawer[open] { transform: translateX(0); }
dialog.wd-drawer::backdrop { background: rgba(0,0,0,.45); }
dialog.wd-drawer .wd-drawer-x { display: flex; justify-content: flex-end; margin: -6px -6px 4px 0; }
dialog.wd-drawer h2 { margin: 0 0 4px; }
.wd-drawer-sec { margin-top: 18px; }
.wd-drawer-sec h3 { margin: 0 0 6px; font-size: var(--fs-sm); color: var(--muted); font-weight: 650; }
.wd-drawer-id { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wd-drawer-id code { word-break: break-all; font-size: var(--fs-xs); }
.wd-drawer-act { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
@media (prefers-reduced-motion: reduce) {
  dialog.wd-drawer { transition: none; }
}

/* ── Deliveries wall: a clean clickable list (repository · verdict · minted), each row opening the
   drawer. Native <button> rows for full keyboard access; laid out as an aligned grid. */
.dlv-list { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.dlv-head, .dlv-row { display: grid; grid-template-columns: minmax(0,2.2fr) minmax(0,1.4fr) minmax(0,1fr); gap: 12px; align-items: center; padding: 11px 16px; text-align: left; }
.dlv-head { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--muted); background: var(--surface-2); border-bottom: 1px solid var(--border); }
.dlv-row { width: 100%; background: var(--panel); color: var(--text); border: 0; border-top: 1px solid var(--border); cursor: pointer; font: inherit; }
.dlv-row:first-of-type { border-top: 0; }
.dlv-row:hover { background: var(--surface-2); }
.dlv-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.dlv-row .dlv-repo strong { display: block; }
.page-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 4px; }
.page-head h1 { margin: 0; }
.page-head .ph-title h1 { margin: 0; }
.page-head .ph-sub { color: var(--muted); font-size: var(--fs-sm); margin-top: 3px; max-width: 70ch; }
.page-actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* ── PageHeader.razor: the ONE page-header layout (breadcrumb + title + (i) + subtitle + actions + tabs).
   Fixed order + spacing so the header reads the same on every page and never jumps between sibling tabs. */
.pg-crumbs { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; font-size: var(--fs-sm); color: var(--muted); margin: 0 0 7px; }
.pg-crumbs a { color: var(--muted); }
.pg-crumbs a:hover { color: var(--text); text-decoration: none; }
.pg-crumbs .sep { opacity: .5; margin: 0 2px; }
.pg-head { margin: 6px 0 16px; }
.pg-titlerow { display: flex; align-items: flex-start; gap: 12px; }
.pg-title { font-size: 22px; font-weight: 650; line-height: 1.2; letter-spacing: -0.01em; color: var(--heading); margin: 0; }
.pg-titlerow .pg-actions { margin-left: auto; flex: none; display: flex; gap: 8px; flex-wrap: wrap; }
.pg-sub { color: var(--muted); font-size: var(--fs-sm); margin: 5px 0 0; max-width: 70ch; }
/* A tab bar directly under the header sits close to the title (TabBar's .repo-nav adds its own 4px top). */
.pg-head + .wd-tabs { margin-top: 0; }
/* Page actions on a TABBED page render as a right-aligned toolbar just below the tab bar (inside the
   tab group), not up in the shared header above the tabs. */
.pg-tabactions { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; margin: 14px 0 4px; }
.pg-tabactions:empty { display: none; }

/* Pending-request action strip on the relationship hubs (Customers / Suppliers): shown only when there
   are requests, at the top, as accept/decline cards. */
.req-strip { background: var(--band-fair-wash); border: 1px solid var(--border); border-left: 3px solid var(--band-fair);
  border-radius: var(--r-md); padding: 12px 14px; margin-bottom: 18px; }
.req-strip-h { font-size: var(--fs-sm); font-weight: 650; color: var(--text); margin-bottom: 10px; display: flex; align-items: center; }
.req-card { display: flex; align-items: center; justify-content: space-between; gap: 12px; background: var(--panel);
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 9px 12px; font-size: var(--fs-sm); margin-top: 8px; }
.req-card:first-of-type { margin-top: 0; }
.req-card-acts { display: flex; gap: 6px; flex: none; }

/* Compact one-line budget indicator (Repositories header action) — replaces the tall quota-mini widget. */
.budget-pill { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border: 1px solid var(--border);
  border-radius: var(--r-full); font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; }
.budget-pill:hover { border-color: var(--accent); color: var(--text); }
.budget-pill-bar { position: relative; width: 54px; height: 6px; border-radius: var(--r-full); background: var(--surface-2); overflow: hidden; }
.budget-pill-bar > span { position: absolute; inset: 0; height: 100%; border-radius: var(--r-full); }
.budget-pill-pct { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.dialog-form { display: flex; flex-direction: column; gap: 10px; margin: 0; }
.dialog-form h3 { margin: 0; }
.dialog-form input, .dialog-form select, .dialog-form textarea { width: 100%; }
.dialog-form > label { display: flex; flex-direction: column; gap: 4px; color: var(--muted); font-size: var(--fs-sm); }
.dialog-form .form-label { color: var(--text); }
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
.icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; flex: none;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--panel); color: var(--muted); cursor: pointer; }
.icon-btn:hover { color: var(--ink); border-color: var(--muted); }

/* Stacked settings sections + label-above-control form fields. */
.settings-section { background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-md); padding: 18px 20px; margin-bottom: 16px; }
.settings-section h2 { margin: 0 0 4px; }
.settings-section h3 { margin: 18px 0 4px; font-size: var(--fs-md); }
.settings-subsection { border-top: 1px solid var(--border); margin-top: 24px; padding-top: 20px; }
.settings-subsection:first-of-type { border-top: none; margin-top: 4px; padding-top: 0; }
.msg-banner { margin-bottom: 16px; }
.form-group { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; margin: 14px 0; }
.form-group > label { margin: 0; color: var(--muted); font-size: var(--fs-sm); }
.has-rail main .form-group > input:not([type=checkbox]), .has-rail main .form-group > select, .has-rail main .form-group > textarea { width: 100%; max-width: 480px; }
.form-group.chk { flex-direction: row; align-items: center; gap: 8px; }

/* ── D2: advisory findings on/off (org + per-repo) ───────────────────────────────────────────
   Built to the approved mock docs/langtrain/d2-advisory-settings-mock.html. */

/* Our own published measurement, stated where the choice is made. */
.advisory-evidence { display: flex; gap: 12px; align-items: flex-start; background: var(--surface-2);
  border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: var(--r-sm);
  padding: 10px 14px; margin: 16px 0; font-size: var(--fs-sm); color: var(--ink-soft); }
.advisory-evidence b { color: var(--heading); font-variant-numeric: tabular-nums; }

/* One lens: the switch a customer reaches for, with its dimensions one click away. The count/disclosure
   sits at the row's right edge so a collapsed lens costs ONE line, not two. */
.advisory-lens { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-sm); margin: 8px 0; background: var(--bg); padding: 9px 14px; }
.advisory-lens > input[type=checkbox] { flex: none; width: auto; margin: 0; }
.advisory-lens > label { flex: 1 1 auto; padding-right: 150px; color: var(--text); font-weight: 600; font-size: var(--fs-sm); }
.advisory-lens > .count, .advisory-lens > details > summary { position: absolute; right: 14px; top: 10px;
  color: var(--muted); font-size: var(--fs-xs); white-space: nowrap; }
.advisory-lens > details { flex: 0 0 100%; order: 2; }
.advisory-lens > details > summary { list-style: none; cursor: pointer; user-select: none; }
.advisory-lens > details > summary::-webkit-details-marker { display: none; }
.advisory-lens > details > summary::after { content: " \25BE"; opacity: .7; }
.advisory-lens > details[open] > summary::after { content: " \25B4"; opacity: .7; }
.advisory-lens > details > summary:hover { color: var(--ink); }
.advisory-lens > details > .dims { margin-top: 8px; padding-left: 20px; border-top: 1px solid var(--border); }

/* One switchable dimension: the id + name carry the row, the sentence sits under it. */
.advisory-lens .dim { display: flex; gap: 10px; align-items: flex-start; padding: 9px 0; border-bottom: 1px solid var(--border); }
.advisory-lens .dim:last-child { border-bottom: 0; }
.advisory-lens .dim > input[type=checkbox] { flex: none; margin-top: 3px; width: auto; }
.advisory-lens .dim .dim-body { min-width: 0; }
.advisory-lens .dim .dim-name { color: var(--text); font-size: var(--fs-sm); font-weight: 600; }
.advisory-lens .dim .dim-name .id { font-family: var(--font-mono); color: var(--accent-ink); font-weight: 500; }
.advisory-lens .dim .dim-what { color: var(--muted); font-size: var(--fs-sm); line-height: 1.45; margin: 1px 0 0; }

/* The per-repository override is TRI-STATE per item, and its "default" option NAMES the organisation's
   value — "default" with nothing after it is a word the reader has to go and look up. */
.advisory-lens .tri { position: absolute; right: 14px; top: 6px; width: 190px; font-size: var(--fs-sm); padding: 5px 8px; }
.advisory-lens.has-tri > label { padding-right: 340px; }
.advisory-lens.has-tri > details > summary { right: 214px; }
.advisory-lens .dim .tri { position: static; width: 190px; flex: none; margin-left: auto; }
.advisory-lens .dim.has-tri { align-items: center; }
.advisory-lens .dim.has-tri .dim-body { flex: 1 1 auto; }

/* ── Bulk select on the reviews table (assign internal / external / unassign) ──────────────── */
.bulk { position: sticky; top: 0; z-index: 5; display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 8px 12px; margin-bottom: 12px; }
.bulk .count { font-size: var(--fs-sm); color: var(--ink-soft); margin-right: auto; }
th.sel, td.sel { width: 34px; text-align: center; padding-right: 0; }
tr.picked { background: color-mix(in srgb, var(--accent-wash) 55%, transparent); }
/* One rater in an assign/unassign dialog. */
.rater-list { text-align: left; max-height: 46vh; overflow-y: auto; }
.rater { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.rater:last-child { border-bottom: 0; }
.rater > input { margin-top: 3px; flex: none; width: auto; }
.rater .who { min-width: 0; }
.rater .nm { color: var(--text); font-size: var(--fs-sm); font-weight: 600; display: block; }
.rater .em { color: var(--muted); font-size: var(--fs-xs); display: block; }
.rater .on { color: var(--muted); font-size: var(--fs-xs); display: block; margin-top: 1px; }
.rater .on > * { margin-right: 4px; }
.rater .on [data-on]:empty { margin-right: 0; }
/* Named in amber, not grey: this is the rater whose removal moves a published κ. */
.rater .on .submitted { color: var(--band-fair-ink, var(--warning)); }
.dlg-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px;
  padding-top: 12px; border-top: 1px solid var(--border); }

/* WP-3 provider repo picker: the connected-account repo list on the track page. */
.picker-search-label { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; margin: 6px 0 14px; color: var(--muted); font-size: var(--fs-sm); }
.picker-search-label .form-label { color: var(--text); }
.picker-search-label .repo-search { flex: 0 0 auto; width: 100%; max-width: 420px; }
.picker-table { width: 100%; }
.picker-table td, .picker-table th { vertical-align: middle; }
.picker-track-form { display: flex; gap: 8px; align-items: center; justify-content: flex-end; margin: 0; }
.picker-track-form select { max-width: 220px; }
.manual-add-fallback { }
.manual-add-fallback > summary { cursor: pointer; font-weight: 600; color: var(--muted); }
.manual-add-fallback[open] > summary { margin-bottom: 12px; color: var(--text); }
.form-group.chk > input[type=checkbox] { flex: none; width: auto; }
.form-group.chk > label { color: var(--text); }
input, select, textarea {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--control-pad-y) var(--control-pad-x); font: inherit;
}

/* sec-head: H2 + trailing meta; the rule between a page's acts. */
.sec-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 24px 0 12px; flex-wrap: wrap; }
.sec-head h2 { margin: 0; }
.sec-head .meta { color: var(--muted); font-size: var(--fs-xs); }
.rule { height: 1px; background: var(--border); margin: 26px 0; border: 0; }

/* Tables (shared minimal treatment). */
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
th { color: var(--muted); font-weight: 600; }

/* ── The table utilities the pages were already written against. ──────────────────────────────────
   ★★ ALL OF THESE WERE USED AND DEFINED NOWHERE — .tablewrap by 3 pages, .legend by 10, .mono by 16,
   the right-align .r by 5. An unknown class is not an error anywhere in the toolchain: the browser
   ignores it, the razor compiler never sees it, and a render test asserting the class ATTRIBUTE passes.
   Same failure as .facts, which shipped for months rendering four pages' headline numbers as one run of
   text. StyleUtilitiesExistTests now fails if any of them goes missing again. */
.tablewrap { overflow-x: auto; }             /* a wide table scrolls in ITSELF, never widening the page */
.legend { color: var(--muted); font-size: var(--fs-sm); line-height: 1.55; margin: 12px 0 0; }
.mono { font-family: var(--font-mono); font-size: var(--fs-xs); }
th.r, td.r, .r { text-align: right; }        /* numeric columns line up on their last digit */

/* ── Share bar ──
   A thin proportional bar under a table label, for a row's SHARE of the total. Fill is --accent and never a
   band token: it expresses SIZE, and colouring it by band would read as a judgement about the row it sits
   under. Both tokens are redefined in the light block, so it carries in both themes. */
.bar { display: block; height: 5px; border-radius: 3px; background: var(--surface-2); margin-top: 4px; }
.bar > i { display: block; height: 100%; border-radius: 3px; background: var(--accent); }

/* A <details> whose summary IS the button that opens it — the zero-JS disclosure for an action that
   needs a form. ★ Styled as a button on purpose: a summary rendered as muted text reads as a label, and
   a row action nobody recognises as clickable is the same defect as the btn-quiet row actions that
   shipped looking like plain text. */
summary.btn { list-style: none; display: inline-flex; }
summary.btn::-webkit-details-marker { display: none; }
details[open] > summary.btn { background: var(--surface-2); color: var(--ink); }

/* Inline progress spinner. */
.spin {
  display: inline-block; width: 14px; height: 14px; vertical-align: -2px; margin-right: 6px;
  border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%;
  animation: wd-spin .8s linear infinite;
}
@keyframes wd-spin { to { transform: rotate(360deg); } }

/* ── wd-tabs: the shared tab bar (TabBar.razor). ── */
.wd-tabs {
  display: flex; gap: 2px; align-items: flex-end;
  border-bottom: 1px solid var(--border);
  margin: 22px 0 18px;
}
.wd-tab {
  appearance: none; background: none; border: none; font: inherit;
  padding: 10px 14px 9px; margin-bottom: -1px;
  color: var(--muted); font-weight: 500; font-size: var(--fs-md);
  border-bottom: 2px solid transparent; border-radius: var(--r-sm) var(--r-sm) 0 0;
  cursor: pointer; white-space: nowrap; text-decoration: none;
}
.wd-tab:hover { color: var(--text); background: var(--surface); }
.wd-tab[aria-selected="true"], .wd-tab.active {
  color: var(--heading); font-weight: 600;
  border-bottom-color: var(--accent);
}
.wd-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.wd-tab-badge { color: var(--accent-ink); font-weight: 600; }
.tab-panel[hidden] { display: none; }
/* Repo sibling-nav: anchor tabs on the hub + every repo sub-page; artifact tabs after a faint rule.
   W18: the 12-tab bar wrapped to two ragged rows around 1280px and was hard to scan. Keep it on ONE
   line and let it scroll horizontally when it doesn't fit, rather than wrapping — a single scannable
   row at any width. The scrollbar is thin and only appears when needed. */
.repo-nav {
  flex-wrap: nowrap; margin-top: 4px;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
  -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity;
}
.repo-nav::-webkit-scrollbar { height: 6px; }
.repo-nav::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
.repo-nav .wd-tab { flex: none; }
.repo-nav-sep { align-self: center; flex: none; width: 1px; height: 18px; background: var(--border); margin: 0 8px -1px; }
.repo-nav .wd-tab.artifact-tab { color: var(--ink-soft); }

/* Report/artifact frame (sandboxed iframe hosts reuse). W21: min/max-height + inner scroll so a short
   report doesn't leave a tall blank band and a long one still fits — the iframe body scrolls. */
.artifact-frame-wrap { border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.artifact-frame { display: block; width: 100%; height: 78vh; min-height: 320px; max-height: 78vh; border: 0; }

/* W7: copy-paste command/config blocks (agent hub MCP wiring). Long single-line commands must WRAP
   rather than force a page-wide horizontal scroll; a scroll bar inside the block is the fallback. */
pre.copy {
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
  max-width: 100%; overflow-x: auto; margin: 0;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 10px 12px; font-size: 12.5px; line-height: 1.5;
}

/* The "(i)" hint: explanatory copy tucked into a hover/focus tooltip so the page stays clean. */
.info-hint { position: relative; display: inline-flex; align-items: center; vertical-align: middle; margin-left: 6px; cursor: help; }
.info-hint:focus { outline: none; }
.info-hint-dot { width: 15px; height: 15px; border-radius: 50%; border: 1px solid var(--border-strong); color: var(--muted);
  font: italic 700 10px/1 Georgia, "Times New Roman", serif; display: grid; place-items: center; }
.info-hint:hover .info-hint-dot, .info-hint:focus .info-hint-dot { border-color: var(--accent); color: var(--accent); }
.info-hint-tip { position: absolute; left: 0; top: calc(100% + 8px); z-index: 60; width: max-content; max-width: 320px;
  background: var(--panel); color: var(--muted); border: 1px solid var(--border-strong); border-radius: 8px;
  box-shadow: 0 8px 26px rgba(0,0,0,.18); padding: 10px 12px; font-size: var(--fs-sm); font-weight: 400; line-height: 1.5;
  white-space: normal; text-align: left; opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity .12s ease, transform .12s ease; pointer-events: none; }
.info-hint-tip a { pointer-events: auto; }
/* Paragraphs inside a tip sit tight — the UA's 1em block margins read as gaps in a small pop. */
.info-hint-tip > p { margin: 4px 0 0; }
.info-hint-tip > p:last-child { margin-bottom: 0; }
.info-hint:hover .info-hint-tip, .info-hint:focus .info-hint-tip, .info-hint:focus-within .info-hint-tip {
  opacity: 1; visibility: visible; transform: none; pointer-events: auto; }
/* Flip to the right edge if the hint sits near the viewport's right (heading ends). */
.info-hint.hint-right .info-hint-tip { left: auto; right: 0; }
/* ★ hint-card: anchor the tip to the CARD it explains, not to the dot. On a narrow card neither
   left:0 nor right:0 works — the dot sits at the card's right edge, so any tip wider than the dot's
   offset overhangs the card's LEFT edge and, in the first column, the viewport. Spanning the card
   makes the tip exactly as wide as its subject, so it can never overflow at any column or width.
   The card must be the positioning parent for this: see .dim-trend below. */
.info-hint.hint-card { position: static; }
.info-hint.hint-card .info-hint-tip { left: 14px; right: 14px; width: auto; max-width: none; top: 44px; }
@media (prefers-reduced-motion: reduce) { .info-hint-tip { transition: none; } }
/* A compact key/value table inside a hint (e.g. "what each role can do") — widen the tip for it. */
.info-hint-tip:has(.info-table) { max-width: 440px; }
.info-hint-tip .info-table { border-collapse: collapse; width: 100%; }
.info-hint-tip .info-table th { text-align: left; vertical-align: top; padding: 3px 12px 3px 0; white-space: nowrap;
  color: var(--heading); font-weight: 600; }
.info-hint-tip .info-table td { text-align: left; vertical-align: top; padding: 3px 0; color: var(--muted); }

/* W4/W5: the repo-hub "Produce evidence" header — the delivery explainer + primary Run-a-scan action. */
.repo-run-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.repo-run-head-row .hd-actions { flex: none; }

/* Repo-hub command center (Option-4 IA): the repo's state as a grid of deep-linking cards. */
.repo-dash { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 0 0 8px; }
@media (max-width: 720px) { .repo-dash { grid-template-columns: 1fr 1fr; } }
@media (max-width: 440px) { .repo-dash { grid-template-columns: 1fr; } }
.repo-dash .dcard { display: flex; flex-direction: column; gap: 3px; background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 14px 16px; text-decoration: none; color: var(--text);
  transition: border-color .12s ease, transform .12s ease; }
.repo-dash .dcard:hover { border-color: var(--accent); transform: translateY(-1px); }
.repo-dash .dcard:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.repo-dash .dcard .t { font-size: var(--fs-xs, .72rem); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.repo-dash .dcard .v { font-size: 1.55rem; font-weight: 700; line-height: 1.15; letter-spacing: -.02em; }
.repo-dash .dcard .s { font-size: var(--fs-sm); color: var(--muted); }
.repo-dash .dcard.cta { border-style: dashed; border-color: var(--accent); }
.repo-dash .dcard.cta .v { font-size: 1.02rem; color: var(--accent); font-weight: 650; }
/* Navigation cards (Reports landing, Settings) — a name + description, not a big metric. */
.repo-dash .dcard.nav .v { font-size: 1.05rem; }
.repo-dash .dcard.nav .s { margin-top: 4px; }
.repo-dash .dcard .v.sm { font-size: 1.05rem; }
/* The 10-lens breakdown inside the Overview "Quality lenses" card — a readable grid, one lens per
   row (name left, band-coloured value right), columns filled left-to-right. */
.repo-dash .dcard .lensgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 0 22px; margin: 6px 0 4px; }
.repo-dash .dcard .lensrow { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 13px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.repo-dash .dcard .lensrow .m { color: var(--muted); }
.repo-dash .dcard .lensrow .n { font-family: var(--mono); font-weight: 650; }
/* A quiet divider that demotes the detailed score breakdown below the command center. */
.dash-break { display: flex; align-items: center; gap: 12px; margin: 20px 0 14px; }
.dash-break span { color: var(--muted); font-size: var(--fs-sm); }
.dash-break::before, .dash-break::after { content: ""; height: 1px; background: var(--border); flex: 1; }
@media (prefers-reduced-motion: reduce) { .repo-dash .dcard { transition: none; } }

/* W17: the raw cd_… delivery id as a truncated copy-chip — full value in the title + a Copy button. */
.delivery-id-cell { display: flex; align-items: center; gap: 6px; }
.copy-chip { display: inline-block; max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; }

/* ── Icon side rail: always-visible left navigation for signed-in pages. ── */
.side-rail {
  position: fixed; inset: 0 auto 0 0; width: 212px; z-index: 40;
  display: flex; flex-direction: column; gap: 4px;
  padding: 14px 10px; background: var(--panel); border-right: 1px solid var(--border);
  overflow-y: auto;
}
.rail-brand {
  padding: 4px 10px 14px; text-decoration: none; font-size: 17px;
}
.rail-brand .icon-badge { width: 22px; height: 25px; flex: none; }
.rail-brand:hover { opacity: .85; text-decoration: none; }
.rail-group { margin-top: 10px; }
.rail-label {
  padding: 0 10px 4px; font-size: 10.5px; font-weight: 700; letter-spacing: .8px;
  text-transform: uppercase; color: var(--muted); opacity: .75;
}
.rail-item {
  display: flex; align-items: center; gap: 10px; width: 100%; position: relative;
  padding: 8px 10px; border-radius: var(--r-sm); border: none; background: none; font: inherit;
  color: var(--muted); text-decoration: none; font-size: var(--fs-md); font-weight: 500; cursor: pointer;
  white-space: nowrap;
}
.rail-badge {
  margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; flex: none;
  background: var(--band-critical); color: #fff; font-size: 11px; font-weight: 700;
}
.rail-item .icon { width: 17px; height: 17px; flex: none; }
.rail-item:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.rail-item.on {
  color: var(--accent-strong); background: var(--accent-wash); font-weight: 600;
  box-shadow: inset 2px 0 0 var(--accent);
}
/* The current-org switcher under the brand (org-context port of the old rail OrgSwitcher). */
.rail-org { padding: 2px 0 6px; }
.rail-org-select {
  display: block; width: 100%; padding: 6px 8px; margin: 0;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  font: 500 var(--fs-sm)/1.3 inherit; font-family: inherit; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rail-org-select:hover { background: var(--surface-2); }

.rail-foot { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--border); }
.rail-user { display: flex; align-items: center; gap: 4px; font-weight: 600; }
.rail-user .rail-item { flex: 1 1 auto; width: auto; min-width: 0; }
.rail-user .rail-item .rail-text { overflow: hidden; text-overflow: ellipsis; }
.rail-gear { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px;
  border: none; background: none; color: var(--muted); border-radius: var(--r-sm); cursor: pointer; }
.rail-gear:hover { color: var(--text); background: var(--surface-2); }
.rail-gear .icon { width: 16px; height: 16px; }

/* ── Repo overview: header strip + triage columns + per-lens sparklines (2026-08-18 redesign). ── */
.hub-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) auto; gap: 20px; align-items: start; padding: 14px 16px; }
@media (max-width: 1200px) { .hub-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.hub-cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.hub-cell .k { font-size: 10.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--muted); }
.hub-cell .v { font-weight: 600; font-size: var(--fs-md); }
.hub-score { font-size: 30px; font-weight: 800; line-height: 1; letter-spacing: -.5px; }
.hub-cell .chip { align-self: flex-start; }
.hub-actions .hd-actions { margin-top: 2px; }
.hub-triage { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin: 14px 0; }
.hub-col { margin: 0; }
.hub-col h3 { margin: 0 0 8px; font-size: var(--fs-md); display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.hub-col h3 a { font-weight: 500; font-size: var(--fs-sm); }
.trow { display: flex; gap: 8px; align-items: baseline; padding: 7px 0; border-top: 1px solid var(--border); }
.trow:first-of-type { border-top: 0; }
.trow .n { flex: 1 1 auto; min-width: 0; }
.trow .m { color: var(--muted); font-size: var(--fs-sm); }
.hub-lens-row { grid-template-columns: 1.4fr 1fr 1fr; }
.lens-sparks { display: grid; grid-template-columns: 1fr 1fr; column-gap: 18px; }
.lens-sparks .ls {
  display: grid; grid-template-columns: 1fr 34px 88px; align-items: center; gap: 8px;
  padding: 3px 0; border-top: 1px solid var(--border); font-size: var(--fs-sm);
}
.lens-sparks .ls .n { text-align: right; font-weight: 600; }
.lens-sparks .ls .sp .hd-spark { margin: 0; }
@media (max-width: 1100px) {
  .hub-triage { grid-template-columns: 1fr; }
  .hub-lens-row { grid-template-columns: 1fr; }
  .lens-sparks { grid-template-columns: 1fr; }
}

/* ── Toggle switch (2026-08-19): the on/off control for settings — a bare checkbox floating over a
   label read as broken (owner). One pattern: <label class="switch"><input type="checkbox"…><span
   class="switch-track" aria-hidden="true"></span><span class="switch-label">…</span></label>. ── */
.switch { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  flex: none; width: 36px; height: 20px; margin-top: 1px; border-radius: 10px; position: relative;
  background: var(--surface-2); border: 1px solid var(--border); transition: background .12s ease;
}
.switch-track::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--muted); transition: transform .12s ease, background .12s ease;
}
.switch input:checked + .switch-track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .switch-track::after { transform: translateX(16px); background: #fff; }
/* Opt-in rows (C3): description left, switch right — the classes existed unstyled, which is why
   the old chip+button merely happened to read okay. */
.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); }
.toggle-row:first-of-type { border-top: 0; }
.toggle-info { display: flex; flex-direction: column; gap: 2px; max-width: 70ch; }
.toggle-ctl { flex-shrink: 0; }
/* Button-form switch (C3, the automation opt-ins): same track, state carried on aria-checked —
   keyboard + click come from the button, the confirm-POST reload keeps it SSR-true. */
button.switch { background: none; border: 0; padding: 0; cursor: pointer; display: inline-flex; align-items: center; }
.switch[aria-checked="true"] .switch-track { background: var(--accent); border-color: var(--accent); }
.switch[aria-checked="true"] .switch-track::after { transform: translateX(16px); background: #fff; }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch input:disabled + .switch-track { opacity: .55; cursor: not-allowed; }
.switch-label { line-height: 1.4; }

/* ── Context mode: the rail body while inside an object (H2, 2026-08-18). ── */
.rail-ctx { padding: 4px 4px 6px; }
.rail-ctx-back { display: block; padding: 2px 6px 6px; font-size: var(--fs-sm); color: var(--muted); text-decoration: none; }
.rail-ctx-back:hover { color: var(--text); text-decoration: none; }
.rail-ctx-who {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 6px 6px; border-radius: var(--r-sm);
  color: var(--text); text-decoration: none; font-size: var(--fs-md); line-height: 1.25;
}
.rail-ctx-who .owner { color: var(--muted); }
.rail-ctx-who strong { font-weight: 700; word-break: break-word; }
.rail-ctx-who:hover { background: var(--surface-2); text-decoration: none; }
.rail-ctx-who.on { background: var(--accent-wash); box-shadow: inset 2px 0 0 var(--accent); }
.rail-ctx-group { margin-top: 6px; }
.rail-ctx-group > summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; gap: 6px; }
.rail-ctx-group > summary::-webkit-details-marker { display: none; }
/* Expand/collapse caret — the affordance the plain <details> lacked (owner feedback 2026-08-18):
   a group HEADER opens/closes; a caret that rotates is how the eye tells that from a link. */
.rail-ctx-group > summary::before {
  content: "\25B8"; font-size: 9px; line-height: 1; flex: none;
  transition: transform .12s ease; transform-origin: 45% 50%;
}
.rail-ctx-group[open] > summary::before { transform: rotate(90deg); }
.rail-ctx-group > summary:hover { opacity: 1; color: var(--text); }
.rail-ctx-count { margin-left: auto; font-weight: 500; letter-spacing: 0; text-transform: none; }
/* Items read as LINKS (full text colour, like the approved mock), never as more headers. */
.rail-ctx-item { padding: 6px 10px 6px 14px; font-size: var(--fs-md); color: var(--text); font-weight: 500; }
.rail-ctx-item:hover { color: var(--text); }

/* Content shifts right when the rail is present. */
body.has-rail { padding-left: 212px; }

@media (max-width: 980px) {
  .side-rail { width: 58px; padding: 14px 7px; }
  .side-rail .rail-text, .side-rail .rail-label { display: none; }
  .rail-ctx, .rail-ctx-group { display: none; }   /* the icon rail has no room for the context tree */
  .rail-org { display: none; }   /* the collapsed icon rail has no room for the org select */
  .rail-brand { justify-content: center; padding: 4px 0 14px; }
  .rail-item { justify-content: center; padding: 9px 0; }
  .rail-badge { position: absolute; top: 2px; right: 6px; margin: 0; min-width: 15px; height: 15px; padding: 0 3px; font-size: 9px; }
  .rail-user { flex-direction: column; gap: 2px; }
  .rail-user .rail-item { width: 100%; flex: none; }
  body.has-rail { padding-left: 58px; }
}

/* ── Chassis auth surfaces (new — the only non-Fjord rules in this file) ── */
/* The unmissable dev-identity banner: fixed, high-contrast, non-dismissable (§4.2). */
.dev-auth-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 100; height: 34px;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 8px 16px; background: #B45309; color: #FFF7ED;
  font: 700 var(--fs-sm)/1.2 var(--font-ui); letter-spacing: .4px; text-transform: uppercase;
  border-top: 2px solid #7C2D12;
}
.dev-auth-banner .icon { width: 15px; height: 15px; }
/* The fixed banner must never hide the rail foot or a page's last row — lift both above it. */
body:has(.dev-auth-banner) .side-rail { bottom: 34px; }
body:has(.dev-auth-banner) main { padding-bottom: 58px; }
/* The centered auth cards (sign-in / honest refusal) rendered by the layout guard. */
.auth-card { max-width: 32rem; margin: 3rem auto; }

/* ── W3 scan-history timeline + from→to delta + changelog (ported .run-timeline / .delta-* / .wd-changelog) ── */
.run-history { margin: 18px 0 8px; }
.run-timeline {
  position: relative; height: 62px; margin: 26px 6px 30px;
}
.tl-track {
  position: absolute; top: 30px; left: 0; right: 0; height: 3px; border-radius: 2px;
  background: var(--border);
}
.tl-select {
  position: absolute; top: 27px; height: 9px; border-radius: 5px;
  background: var(--accent-wash); border: 1px solid var(--accent); pointer-events: none;
}
.tl-dot {
  position: absolute; top: 22px; width: 20px; height: 20px; margin-left: -10px;
  border-radius: 50%; border: 2px solid var(--surface); cursor: pointer; padding: 0;
  background: var(--band-fair); box-shadow: 0 0 0 1px var(--border);
  display: flex; align-items: center; justify-content: center; transition: transform .1s;
}
.tl-dot:hover { transform: scale(1.25); z-index: 3; }
.tl-dot.band-exemplary { background: var(--band-exemplary); }
.tl-dot.band-healthy   { background: var(--band-healthy); }
.tl-dot.band-fair      { background: var(--band-fair); }
.tl-dot.band-poor      { background: var(--band-poor); }
.tl-dot.band-critical  { background: var(--band-critical); }
.tl-val {
  font-size: 9px; font-weight: 700; color: #14181D; pointer-events: none; line-height: 1;
}
.tl-handle {
  position: absolute; top: 18px; width: 12px; height: 28px; margin-left: -6px;
  border-radius: 4px; background: var(--accent-strong); border: 2px solid var(--surface);
  cursor: ew-resize; z-index: 4; box-shadow: 0 1px 3px rgba(0,0,0,.35);
}
.tl-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tl-date { position: absolute; top: 48px; transform: translateX(-50%); white-space: nowrap; }
.tl-date-from { left: 4%; }
.tl-date-to { left: 96%; }
/* A scan that wrote narrated changelog entries. A ring rather than a colour: the dot's fill already
   carries the health band, and overloading it would trade one signal for another. */
.tl-dot-changelog { box-shadow: 0 0 0 1px var(--border), 0 0 0 4px var(--accent); }
.tl-legend { position: absolute; top: 48px; left: 50%; transform: translateX(-50%); white-space: nowrap;
  display: flex; align-items: center; gap: 6px; }
.tl-legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  background: var(--band-fair); border: 1px solid var(--surface); }

#delta-panel h3.delta-title { margin: 0 0 2px; font-size: var(--fs-lg); }
.delta-subline { margin: 0 0 14px; display: flex; align-items: baseline; gap: 10px; }
/* 2-column card body: Lens movement (left) | New / Reappeared / Resolved stacked (right). */
.delta-2col { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; margin: 8px 0 4px; }
.delta-col-findings { display: flex; flex-direction: column; gap: 14px; }
.delta-finding-group h4 { margin: 0 0 6px; font-size: var(--fs-sm); }
.delta-finding-list { list-style: none; margin: 0; padding: 0; }
.delta-finding { padding: 5px 0; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); }
.delta-finding:last-child { border-bottom: none; }
.delta-findings-unavailable { padding: 12px; border: 1px dashed var(--border); border-radius: var(--r-sm); }
.delta-findings-unavailable h4 { margin: 0 0 4px; font-size: var(--fs-sm); }
.delta-persist { margin: 10px 0 0; }
.delta-card {
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 10px 12px;
  background: var(--surface-2);
}
.delta-card-warn { margin-bottom: 14px; border-color: var(--band-fair); background: var(--band-fair-wash); }
.delta-card-ok { margin-bottom: 14px; border-color: var(--band-healthy); background: var(--band-healthy-wash); }
.delta-card-k { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .4px; color: var(--muted); font-weight: 700; }
.delta-card-v { display: block; margin-top: 3px; }
.delta-lens-table { width: 100%; border-collapse: collapse; margin-top: 6px; font-size: var(--fs-sm); }
.delta-lens-table th, .delta-lens-table td { padding: 3px 6px; text-align: left; border-bottom: 1px solid var(--border); }
.delta-lens-table td.num, .delta-lens-table th:not(:first-child) { text-align: right; }
.ink-healthy { color: var(--band-healthy-text); }
.ink-fair { color: var(--band-fair-text); }
.ink-poor { color: var(--band-poor-text); }
.ink-critical { color: var(--band-critical-text); }
.wd-mono { font-family: var(--font-mono, ui-monospace, monospace); font-size: .92em; }

/* Lowest-health files: the per-file drill-down under the file-quality mix. */
.slop-files { list-style: none; margin: 8px 0 0; padding: 0; }
.slop-file { display: flex; align-items: baseline; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--border); min-width: 0; }
.slop-file:last-child { border-bottom: none; }
.slop-file-score { flex: 0 0 auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.slop-file-score .hd-unit { font-weight: 400; color: var(--muted); }
.slop-file-path { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slop-file-why { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Delivery signals: advisory git-only delivery-health stat tiles (never a grade). */
.delivery-signals { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0 0; }
.delivery-tile { flex: 1 1 120px; min-width: 0; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 12px 14px; }
.delivery-value { display: block; font-size: 1.5em; font-weight: 700; font-variant-numeric: tabular-nums; }
.delivery-value .hd-unit { font-size: .6em; font-weight: 400; color: var(--muted); }
.delivery-label { display: block; margin-top: 2px; font-size: .85em; }
.delivery-caveat { margin-top: 8px; }

.wd-changelog { margin-top: 14px; }
.changelog-subtabs { margin-bottom: 4px; }
.changelog-panel { border: 1px solid var(--border); border-top: none; border-radius: 0 0 var(--r-sm) var(--r-sm); padding: 14px 16px; }
.changelog-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.changelog-body h3 { margin: 0 0 8px; font-size: var(--fs-md); }
.changelog-body h4 { margin: 12px 0 4px; font-size: var(--fs-sm); color: var(--muted); }
.changelog-body .cl-list { margin: 0 0 8px; padding-left: 18px; }
.changelog-body .cl-list li { padding: 1px 0; }

/* W5 — report sub-tab strip (Executive/Engineering/Security/Audit) + threat-model wizard. */
.subtabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin: 8px 0 6px; flex-wrap: wrap; }
.subtab { padding: 6px 12px; border: 1px solid transparent; border-bottom: none; border-radius: var(--r-sm) var(--r-sm) 0 0; color: var(--muted); text-decoration: none; font-size: var(--fs-sm); }
.subtab:hover { color: var(--text); background: var(--panel); }
.subtab.on { color: var(--text); background: var(--panel); border-color: var(--border); font-weight: 600; margin-bottom: -1px; }
.wizard-steps { display: flex; gap: 8px; list-style: none; padding: 0; margin: 10px 0 16px; flex-wrap: wrap; counter-reset: step; }
.wizard-steps li { position: relative; padding: 4px 12px 4px 30px; border: 1px solid var(--border); border-radius: 999px; color: var(--muted); font-size: var(--fs-sm); counter-increment: step; }
.wizard-steps li::before { content: counter(step); position: absolute; left: 8px; top: 50%; transform: translateY(-50%); width: 18px; height: 18px; line-height: 18px; text-align: center; border-radius: 50%; background: var(--border); color: var(--text); font-size: 11px; font-weight: 700; }
.wizard-steps li.on { color: var(--text); border-color: var(--band-healthy-text); }
.wizard-steps li.on::before { background: var(--band-healthy-text); color: #fff; }
dl.kv { display: grid; grid-template-columns: max-content 1fr; gap: 4px 18px; margin: 8px 0; }
dl.kv dt { color: var(--muted); font-size: var(--fs-sm); }
dl.kv dd { margin: 0; }

@media (max-width: 760px) {
  .delta-2col { grid-template-columns: 1fr; }
}
.auth-card h1 { margin-top: 0; }

/* ── C4 architecture navigator (W4, ported from old-SaaS app.css). The server-rendered SVG is self-contained; the
   wrapper scrolls a wide diagram; a detail panel is filled on click (kennel-ui.js C4 island). ── */
.c4-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--panel); padding: 12px; }
.c4-wrap svg { max-width: 100%; height: auto; }
/* Theme-paired inline images (the dependency matrix ships a light + a dark SVG): exactly ONE
   variant renders, matching the active data-theme (theme.js always stamps it; dark is default).
   C1 (2026-08-20): these classes were referenced by the page but styled nowhere — both variants
   rendered stacked, the light one glaring on the dark UI. */
:root[data-theme="dark"] .wd-img-light { display: none; }
:root[data-theme="light"] .wd-img-dark { display: none; }
/* Pinned acting-scope (T1c): one scope needs no control — say where you are, in the switcher's
   own visual slot so the rail's rhythm is unchanged. */
.rail-scope-pinned { display: flex; flex-direction: column; gap: 2px; padding: 6px 8px; border: 1px solid var(--rule); border-radius: var(--r-md, 6px); font-weight: 600; }
.rail-scope-hint { font-weight: 400; font-size: .72rem; color: var(--muted); }
/* Findings ledger (C2): dimension group header rows + the count riding each filter chip. */
tr.group-row td { background: var(--bg-2, rgba(127,127,127,.06)); border-top: 1px solid var(--border); padding-top: 10px; }
.chip .chip-count { opacity: .65; font-variant-numeric: tabular-nums; margin-left: 2px; }
/* Side-by-side (diagram + panel) on wide screens, stacked on narrow. */
.c4-stage { display: flex; gap: 12px; align-items: flex-start; margin-top: 8px; }
.c4-main { flex: 1 1 auto; min-width: 0; }
.c4-main .c4-wrap { margin-top: 0; }
.c4-stage .c4-wrap { flex: 1 1 auto; min-width: 0; margin-top: 0; }
/* Level breadcrumb: "Containers › {container}" — shows which level you're at; click to zoom out. */
.c4-crumbs { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 13px; min-height: 26px; }
button.c4-crumb { background: none; border: none; padding: 2px 6px; color: var(--accent-ink, #2f5d85); cursor: pointer; font: inherit; border-radius: 4px; }
button.c4-crumb:hover { background: var(--accent-wash); }
button.c4-crumb.c4-crumb-cur { color: var(--ink); cursor: default; font-weight: 600; }
button.c4-crumb.c4-crumb-cur:hover { background: none; }
.c4-crumb-sep { color: var(--muted); }
.c4-crumb-cur { color: var(--ink); font-weight: 600; }
.c4-panel { flex: 0 0 320px; max-height: 70vh; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--panel); padding: 12px; font-size: 13px; }
.c4-panel[hidden] { display: none; }
.c4-panel-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.c4-panel-head strong { font-size: 14px; }
.c4-panel-x { margin-left: auto; background: none; border: none; color: var(--muted); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 4px; }
.c4-panel-x:hover { color: var(--ink); }
.c4-coupling-tag { font-size: 11px; color: var(--band-critical, #d4574b); border: 1px solid var(--band-critical, #d4574b); border-radius: 999px; padding: 1px 8px; }
.c4-findings { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.c4-findings li { line-height: 1.4; padding-bottom: 7px; border-bottom: 1px solid var(--border); }
.c4-findings li:last-child { border-bottom: none; }
.c4-findings code { background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
.c4-dim { display: inline-block; font-size: 11px; font-weight: 600; color: var(--accent-ink, #2f5d85); background: var(--accent-wash); border-radius: 4px; padding: 0 5px; margin-right: 2px; }
@media (max-width: 760px) { .c4-stage { flex-direction: column; } .c4-panel { flex-basis: auto; width: 100%; } }

/* ── W9: live run-progress banner + run-now tracker (ported wd-run-eta.js surfaces) ─────────────
   Rendered by kennel-ui.js off /api/queue/{entryId}/progress; hidden until a run is active. */
.run-banner { background: var(--accent-wash); border: 1px solid var(--accent); border-radius: var(--r-md);
  padding: 14px 16px; display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.run-banner[hidden] { display: none; }
.run-banner .run-spinner { width: 18px; height: 18px; border: 3px solid var(--border-strong);
  border-top-color: var(--accent); border-radius: 50%; animation: wd-spin 1s linear infinite; flex: none; }
.run-banner .run-body { flex: 1; }
.run-banner .run-title { font-weight: 700; color: var(--accent-ink); }
.run-banner .run-meta { font-size: var(--fs-sm); color: var(--muted); font-variant-numeric: tabular-nums; }
.run-now-msg { display: none; margin-top: 10px; font-size: var(--fs-sm); padding: 8px 12px;
  border-radius: var(--r-sm); line-height: 1.4; }
.run-now-msg.ok { display: block; background: var(--accent-wash); color: var(--accent-ink); border: 1px solid var(--accent); }
.run-now-msg.err { display: block; background: var(--band-critical-wash); color: var(--band-critical-ink); border: 1px solid var(--band-critical); }

/* ── W9: customer scan-queue console — the per-row ETA cell recedes; 'estimating' reads honest. ── */
.queue-eta { color: var(--muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.queue-eta.estimating { font-style: italic; }
/* Two states an ETA cannot express, so they must not read like one. Paused-for-a-deploy is reassurance and stays
   calm; may-be-stuck names an action and must not recede into the muted default the way "taking longer than
   expected" did. Both use band tokens, so both follow the theme. */
.queue-eta-paused { color: var(--band-fair-ink); font-style: italic; }
.queue-eta-stuck  { color: var(--band-critical-ink); font-weight: 600; }

/* ════════════════════════════════════════════════════════════════════════════════════════════════
   W2 — repo hub trends & slop-vs-brilliant (ported from old-SaaS app.css verbatim, retokenised)
   Per-lens trend grid, the slop/brilliant file-quality strip, the Assurance-Depth bar, first-scan
   framing, the top-level overview flag chips, and the per-lens (i).
   ════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Per-lens trend card. The (i) is the product-wide .info-hint (see above) — the card only sets the
   header row's layout and where the tip anchors; the disclosure itself has no card-local styling. */
.dim-trend .hd-top-right { display: inline-flex; align-items: center; gap: 6px; }

/* ★ The CAI card is the HEADLINE, not a lens: it spans the row, so the two anatomies read as
   hierarchy rather than as a card someone forgot to update. */
.dim-trend { position: relative; }   /* the containing block a .hint-card tip anchors to */
.dim-trends { grid-auto-flow: row dense; }
.dim-trend-headline { grid-column: 1 / -1; }
.dim-trend-headline .hd-top { align-items: baseline; }
/* The headline card spans the row, so a card-width tip would stretch the blend rows across the page.
   It is full width, so anchoring right cannot overflow — cap it to a readable measure instead. */
.dim-trend-headline .info-hint-tip { left: auto; right: 14px; width: 380px; max-width: calc(100% - 28px); }

/* A lens card is a link into its own findings — it must not pick up link colouring. */
a.dim-trend { display: block; text-decoration: none; color: inherit; }
a.dim-trend:hover { border-color: var(--accent); text-decoration: none; }

/* The one honest sentence: why this lens reads what it reads. Absent when there is nothing to say. */
.why-line { margin: 10px 0 0; font-size: var(--fs-sm); color: var(--muted); line-height: 1.45; }
.why-gate { margin-top: 4px; font-size: var(--fs-xs); }

/* The evidence rows inside a card's (i): two lines each, so a 280px card's tip never needs 440px. */
.ev-list { list-style: none; margin: 8px 0 0; padding: 8px 0 0; border-top: 1px solid var(--border); }
.ev-list li { display: flex; flex-direction: column; gap: 1px; padding: 4px 0; }
.ev-list li + li { border-top: 1px solid var(--border); }
.ev-list .ev-k { color: var(--heading); font-weight: 600; font-size: var(--fs-xs); }
.ev-list .ev-v { font-size: var(--fs-xs); color: var(--muted); }
.ev-list .ev-total { border-top: 1px solid var(--border-strong); margin-top: 2px; }
.info-hint-tip .cai-ladder { margin: 8px 0 2px; }

/* Size & economics key/value rows live in a .settings-section (not a .wd-card), so the flex layout
   the card-scoped .hd-row provides must also apply here (label left, value right, gapped). */
.settings-section .hd-rows { margin-top: 6px; }
.settings-section .hd-row { display: flex; justify-content: space-between; gap: 16px; font-size: var(--fs-sm);
  padding: 6px 0; border-bottom: 1px solid var(--border); }
.settings-section .hd-row:last-child { border-bottom: 0; }
.settings-section .hd-row .num { font-weight: 600; }

/* First-scan framing — "this is a position, not a grade" + the weakest-lens pointer. */
.first-scan-frame { display: flex; flex-direction: column; gap: 4px; margin: 12px 0 2px; font-size: var(--fs-sm); }
.first-scan-frame > strong { font-size: var(--fs-md); }
.first-scan-floor { line-height: 1.5; }

/* Sprints tab — the rendered sprint plan (read-and-work path), beside the CSV/markdown exports. */
.sprint-exports { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; }
.sprint-readiness { display: flex; align-items: center; gap: 12px; }
.sprint-readiness-score { font-size: var(--fs-lg); font-weight: 600; font-variant-numeric: tabular-nums; }
.sprint-flags { list-style: none; padding: 0; margin: 10px 0 0; display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-sm); }
.sprint-epics { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.sprint-epics > li { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; }
.sprint-tickets { display: flex; flex-direction: column; gap: 10px; }
.sprint-ticket { border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; }
.sprint-ticket-head { display: flex; flex-direction: column; gap: 2px; }
.sprint-ticket-title { font-size: var(--fs-md); }
.sprint-ticket-meta { font-size: 11px; }
.sprint-dod { margin-top: 8px; }
.sprint-dod > ul { margin: 4px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; font-size: var(--fs-sm); }

/* Corpus-relative benchmark — a COMPLEMENTARY signal under the fixed bar ("top X% of N repos").
   Deliberately quiet: it is a peer position, never a grade, so it reads as a footnote to the ladder. */
.corpus-benchmark { display: flex; flex-direction: column; gap: 2px; margin: 10px 0 2px; padding-left: 10px; border-left: 2px solid var(--border); }
.corpus-benchmark-lead { font-size: var(--fs-sm); }
.corpus-benchmark-lead strong { font-weight: 600; }
.corpus-benchmark-note { font-size: 11px; }

/* Overview action-flag chips — critical-toned, TOP-LEVEL (not inside a card, so not .wd-card-scoped). */
.alerts { display: flex; flex-wrap: wrap; gap: 6px; }
.alerts > .alert { font-size: 11px; color: var(--band-critical-text); border: 1px solid var(--band-critical);
  border-radius: var(--r-sm); padding: 1px 6px; white-space: nowrap; }

/* Assurance Depth bar — an enforcement composition (Prevented ▸ Verified ▸ Documented-only). Uses the
   accent ramp (a completeness axis, deliberately NOT the band palette — it is never a quality grade). */
.assurance-depth { margin: 6px 0 4px; }
.ad-bar { display: flex; width: 100%; height: 22px; border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.ad-bar > .ad-seg { display: flex; align-items: center; justify-content: center; min-width: 0; overflow: hidden;
  font-size: 11px; font-weight: 600; white-space: nowrap; }
.ad-seg.ad-prevented  { background: var(--accent-strong); color: var(--on-accent); }
.ad-seg.ad-verified   { background: var(--accent); color: var(--on-accent); }
.ad-seg.ad-documented { background: var(--accent-wash); color: var(--accent-ink); }
.ad-legend { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; font-size: var(--fs-xs); color: var(--muted); }
.ad-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.ad-legend .ad-swatch { width: 11px; height: 11px; border-radius: 3px; flex: none; border: 1px solid var(--border); }
.ad-swatch.ad-prevented  { background: var(--accent-strong); }
.ad-swatch.ad-verified   { background: var(--accent); }
.ad-swatch.ad-documented { background: var(--accent-wash); }
/* Gate coverage — which classes of automated check the pipeline enforces, and the ranked list of what to add
   first. The card's colour is driven by the EVIDENCE (a gap on a concern already measuring badly), never by the
   gap COUNT, so it uses the band palette: this one IS a "how bad is it" signal, unlike the assurance bar above. */
.gc-card { border-left: 3px solid var(--border-strong); }
.gc-card.gc-none     { border-left-color: var(--band-exemplary); }
.gc-card.gc-moderate { border-left-color: var(--band-fair-text); }
.gc-card.gc-high     { border-left-color: var(--band-critical); }

.gatecov { margin: 4px 0 20px; }
.gc-note { font-size: var(--fs-xs); color: var(--muted); margin: 0 0 10px; }

/* The answer, before the list. A ranked list without a stated recommendation was read as five equal
   items, and the reader could not tell which one the product was actually pointing at. */
.gc-head { display: flex; align-items: flex-start; gap: 12px; margin: 0 0 12px; }
.gc-lead { margin: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: 3px; font-size: var(--fs-sm); }
.gc-lead-sub { color: var(--muted); font-size: var(--fs-xs); }


.gc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.gc-row { display: flex; align-items: flex-start; gap: 12px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); }
/* State is carried by the WORDED chip, not by the border — an amber edge was read as "recommended next"
   when it meant "advisory only". The border now marks the recommendation, which is what rank 1 is. */
.gc-row.gc-top { border-color: var(--accent); box-shadow: inset 3px 0 0 var(--accent); }
.gc-rank { flex: none; width: 22px; height: 22px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; font-size: 11px; font-weight: 700;
  background: var(--accent-wash); color: var(--accent-ink); }
.gc-row.gc-top > .gc-rank { background: var(--accent); color: var(--on-accent, #fff); }
.gc-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
.gc-nameline { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.gc-name { font-weight: 600; }
.gc-chip { font-size: 11px; line-height: 1.6; padding: 0 8px; border-radius: var(--r-full);
  border: 1px solid var(--border-strong); color: var(--muted); white-space: nowrap; }
.gc-chip-advisory { color: var(--band-fair-text); border-color: var(--band-fair-text); }
.gc-chip-next { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); font-weight: 600; }
.gc-why { font-size: var(--fs-xs); color: var(--muted); }
.gc-scorecell { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
  align-self: center; max-width: 190px; }
.gc-score { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 15px; color: var(--ink); }
.gc-score .gc-outof { font-size: 11px; font-weight: 500; color: var(--muted); }
.gc-score.gc-bad { color: var(--band-critical-text); }
.gc-scorecap { font-size: 10.5px; color: var(--muted); text-align: right; line-height: 1.35; }
.gc-ok, .gc-foot { font-size: var(--fs-xs); color: var(--muted); margin: 10px 0 0; }
@media (max-width: 560px) {
  .gc-row { flex-wrap: wrap; }
  .gc-scorecell { align-items: flex-start; text-align: left; max-width: none; padding-left: 34px; }
  .gc-scorecap { text-align: left; }
}

@media (forced-colors: active) {
  .ad-bar > .ad-seg { forced-color-adjust: none; }
  .ad-seg.ad-prevented  { background: CanvasText; color: Canvas; }
  .ad-seg.ad-verified   { background: GrayText;   color: Canvas; }
  .ad-seg.ad-documented { background: Canvas;     color: CanvasText; border-left: 1px solid CanvasText; }
}

/* Governance altitude ladder — the FIXED four rungs (Organisation → Customer → Product → Repository),
   empty rungs included. A left rail + rung-rank badge reads top-to-bottom as an altitude ladder. */
.gov-ladder { list-style: none; margin: 12px 0; padding: 0; display: flex; flex-direction: column; gap: 10px; position: relative; }
.gov-ladder .gov-rung { margin: 0; position: relative; }
.gov-rung .gov-rung-alt { display: inline-flex; align-items: center; gap: 8px; }
.gov-rung-rank { font-variant-numeric: tabular-nums; min-width: 1.4em; text-align: center; }
.gov-rung-empty { opacity: 0.72; border-style: dashed; }
.gov-rung-body { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-top: 6px; }
.gov-rung-bind { font-size: var(--fs-xs); white-space: nowrap; }

/* Bind wizard altitude tiles — the founder-named tile picker (cards, not radios). */
.gov-alt-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px; }
.gov-alt-tile { cursor: pointer; }
.gov-alt-tile-off { opacity: 0.6; cursor: not-allowed; }
.gov-alt-tile:has(input:checked) { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* Engagement phase tab strip — the monotonic Tender → Contract → Delivery journey, current highlighted. */
.gov-phase-strip { list-style: none; display: flex; gap: 0; margin: 8px 0; padding: 0; flex-wrap: wrap; }
.gov-phase { display: inline-flex; align-items: center; gap: 6px; padding: 4px 14px 4px 10px; font-size: var(--fs-sm); color: var(--muted); position: relative; }
.gov-phase:not(:last-child)::after { content: "→"; margin-left: 10px; color: var(--border); }
.gov-phase-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--border); flex: none; }
.gov-phase-done .gov-phase-dot { background: var(--band-exemplary); }
.gov-phase-current { color: var(--ink); font-weight: 600; }
.gov-phase-current .gov-phase-dot { background: var(--accent); box-shadow: 0 0 0 3px var(--accent-wash); }
.gov-phase-ahead { opacity: 0.6; }

/* Delivery handover board — status pills + the mint/sign/share/revoke lifecycle row. */
.gov-handover-status.hs-minted    { background: var(--surface-2); color: var(--muted); }
.gov-handover-status.hs-signed    { background: var(--band-exemplary); color: var(--ink); }
.gov-handover-status.hs-published { background: var(--accent-wash); color: var(--accent-ink); }
.gov-handover-status.hs-revoked   { background: var(--band-critical); color: var(--ink); }
.gov-handover-status.hs-superseded { background: var(--surface-2); color: var(--muted); text-decoration: line-through; }

/* File-quality mix strip (brilliant ▸ fine ▸ slop) — one stacked column per scan, pure CSS. */
.band-mix { display: flex; align-items: flex-end; gap: 2px; height: 72px; margin: 6px 0 2px; min-width: 0; overflow: hidden; }
.band-mix-col { flex: 1 1 0; display: flex; flex-direction: column-reverse; height: 100%; border-radius: 2px; overflow: hidden; min-width: 0; }
.band-mix-col > span { display: block; width: 100%; }
.quality-mix .q-brilliant { background: var(--band-exemplary); }
.quality-mix .q-fine      { background: var(--surface-2); }
.quality-mix .q-slop      { background: var(--band-critical); }

/* F-2 — compact LoC-scan consumption meter (QuotaMeterCard) for the dashboard/wall header */
.quota-mini{display:inline-flex;flex-direction:column;gap:5px;min-width:190px;max-width:230px;
  padding:9px 12px;border:1px solid var(--border);border-radius:10px;background:var(--surface);
  text-decoration:none;color:inherit;transition:border-color .15s}
.quota-mini:hover{border-color:var(--accent, #b7862d)}
.quota-mini-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.quota-mini-label{font-size:11px;letter-spacing:.02em;color:var(--muted)}
.quota-mini-status{font-size:11px;font-weight:600}
.quota-mini-bar{position:relative;height:8px;border-radius:999px;background:var(--surface-2);overflow:hidden}
.quota-mini-bar > div{position:absolute;inset:0;height:100%;border-radius:999px}
.quota-mini-today{position:absolute;top:-2px;bottom:-2px;width:2px;background:var(--ink);opacity:.5}
.quota-mini-foot{display:flex;justify-content:space-between;gap:8px;font-size:10.5px;color:var(--muted);
  font-variant-numeric:tabular-nums}

/* F-9 — first-run getting-started onboarding (repositories wall empty state) */
.onboarding{max-width:720px;margin:8px auto;padding:28px 30px}
.onboarding-lead h2{margin:0 0 6px;font-size:1.5rem}
.onboarding-lead p{margin:0 0 4px;max-width:60ch}
.onboarding-steps{list-style:none;margin:22px 0 24px;padding:0;display:flex;flex-direction:column;gap:16px}
.onboarding-steps li{display:flex;gap:14px;align-items:flex-start}
.onboarding-steps .step-n{flex:0 0 auto;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  font-size:13px;font-weight:700;color:var(--accent, #b7862d);
  background:color-mix(in oklab, var(--accent, #b7862d) 15%, transparent);
  border:1px solid color-mix(in oklab, var(--accent, #b7862d) 40%, transparent)}
.onboarding-steps li > div{display:flex;flex-direction:column;gap:2px}
.onboarding-steps strong{color:var(--ink)}
.onboarding-steps p{margin:0;max-width:56ch}
.onboarding-actions{display:flex;flex-wrap:wrap;gap:10px}

/* ── In-context feedback widget (floating button + native <dialog>) ── */
.feedback-fab{position:fixed;right:18px;bottom:18px;z-index:60;padding:9px 16px;border:none;border-radius:var(--r-full);background:var(--accent);color:#fff;font-weight:600;font-size:var(--fs-sm);cursor:pointer;box-shadow:0 2px 12px rgba(0,0,0,.28)}
.feedback-fab:hover{filter:brightness(1.07)}
.feedback-dialog{border:1px solid var(--line,rgba(128,128,128,.25));border-radius:12px;padding:0;max-width:460px;width:calc(100% - 32px);background:var(--surface-2);color:var(--ink)}
.feedback-dialog::backdrop{background:rgba(0,0,0,.45)}
.feedback-form{display:flex;flex-direction:column;gap:10px;padding:20px}
.feedback-form h2{margin:0}
.feedback-form label{display:flex;flex-direction:column;gap:4px;font-size:var(--fs-sm)}
.feedback-form textarea,.feedback-form select{width:100%;font:inherit}
.feedback-check{flex-direction:row!important;align-items:center;gap:8px}
.feedback-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}

/* ── the live scan progress anatomy (ScanProgressBar.razor; plan live-scan-progress-sse) ─────────
   One anatomy for queue row / repo-hub Latest-run cell / admin queue. Fill and track use the
   band-healthy pair (the same family as the Running chip), so the bar reads as the chip's own
   progress in both themes; the terminal snap borrows the exemplary tone the Completed chip uses. */
.scan-progress { margin-top: 4px; max-width: 340px; }
.scan-progress-track { height: 6px; border-radius: 3px; background: var(--band-healthy-wash); overflow: hidden; }
.scan-progress-fill { height: 100%; border-radius: 3px; background: var(--band-healthy); width: 0; transition: width .6s ease; }
.scan-progress.is-terminal .scan-progress-fill { background: var(--band-exemplary); }
.scan-progress-now { margin-top: 3px; }
.scan-progress-note { margin-top: 3px; font-size: var(--fs-sm); color: var(--band-fair-text); opacity: 0; transition: opacity .4s ease; }
.scan-progress-note.show { opacity: 1; }

/* Toasts for run lifecycle events (kennel-ui.js live island; opt-in per repo). */
.toast-stack { position: fixed; right: 16px; bottom: 16px; display: flex; flex-direction: column; gap: 8px; z-index: 50; }
.toast { background: var(--bg); border: 1px solid var(--line); border-left: 4px solid var(--band-healthy);
  border-radius: 6px; padding: 10px 14px; box-shadow: 0 4px 14px rgba(0,0,0,.15); font-size: var(--fs-sm);
  min-width: 240px; animation: toast-in .25s ease; }
.toast.toast-failed { border-left-color: var(--band-critical); }
.toast .muted { display: block; margin-top: 2px; }
@keyframes toast-in { from { transform: translateY(8px); opacity: 0; } }

/* ── Findings: cause clusters (2026-08-24) ────────────────────────────────────────────────────────
   The page rendered one row per finding INSTANCE, so a real scan opened on 243 rows of which the two
   biggest piles were 76% and worth ~0.2 grade points. It now opens on the CAUSE — the unit you decide
   about — with the instances one click away. */
.decision-strip { display: flex; flex-wrap: wrap; gap: 0; border: 1px solid var(--border);
  border-radius: var(--r-md); overflow: hidden; margin: 0 0 14px; }
.decision-strip .ds { flex: 1 1 150px; padding: 10px 14px; background: var(--panel);
  border-right: 1px solid var(--border); }
.decision-strip .ds:last-child { border-right: 0; }
.decision-strip .ds-n { font-size: 1.6rem; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.decision-strip .ds-k { font-size: var(--fs-sm); color: var(--muted); }

/* Expand a cause in place: its instances are today's table, unchanged. */
td > details > summary { cursor: pointer; list-style: none; }
td > details > summary::-webkit-details-marker { display: none; }
td > details > summary::before { content: "\25B8\00a0"; color: var(--muted); }
td > details[open] > summary::before { content: "\25BE\00a0"; }
.cluster-body { margin: 10px 0 4px; padding: 10px 12px; background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--r-sm); }
.cluster-body > table { margin-top: 8px; }
.cluster-body .msg-banner p { margin: 6px 0 0; }

/* Triage lanes — the findings page's landing. Grouped by what you DO about a cause, so the reader
   lands on a decision rather than on data. The engine-defect lane comes first on purpose: a cause
   blocked on a detector bug makes every number below it provisional. */
.lane-title { font-size: var(--fs-md); margin: 18px 0 8px; padding-bottom: 6px;
  border-bottom: 1px solid var(--border); }
.lane-title:first-of-type { margin-top: 6px; }
.lane-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 8px; }
.lane-card { border: 1px solid var(--border); border-left: 3px solid var(--border-strong);
  border-radius: var(--r-sm); padding: 10px 12px; background: var(--panel); }
.lane-card > details { margin-top: 6px; }
.lane-card > details > summary { cursor: pointer; }
.lane-card-head { display: flex; gap: 8px; align-items: baseline; }
.lane-card-n { margin-left: auto; color: var(--muted); }
.lane-enginedefect { border-left-color: var(--accent); }
.lane-ourstofix { border-left-color: var(--band-critical, #d1656f); }
.lane-fixedawaitingscan { border-left-color: var(--band-healthy, #6f9d63); }
.lane-accepted { border-left-color: var(--border-strong); }
.lane-needsdecision { border-left-color: var(--band-fair, #c9973f); }

/* The per-cause disposition control: a decision a person types, never one the engine infers. */
.disp-form { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.disp-form select { max-width: 190px; }
.disp-form input { max-width: 170px; }

