/* The console's stylesheet.

   ONE file, deliberately. The section banners below already misdescribe their contents in three
   places — `masthead` also carries Metrics, Toast and Button rules; `history table` also carries
   the canvas breadcrumbs, the drawer's ArgoCD rows and the Metrics bars — so splitting along them
   would file things where nobody will look for them.

   And three `@keyframes` are used outside the section that declares them: `spin` is declared under
   `tickets` but drives the Refresh buttons in Environments and History; `pulse` is declared under
   `the flow` but used by `.lamp.run` above it; `dash` under `canvas`. Splitting into per-view
   stylesheets would mean a view whose animation lives in a file it does not load.

   Lifted verbatim out of index.html. Nothing here was changed in the move — the dead selectors and
   the duplication are known and are their own separate pass. */

/* ─────────────────────────────────────────────────────────────────────────────────────────
   shadcn/ui design system, ported. The tokens below are shadcn's own oklch values and radius
   scale, not an approximation — same neutral ramp, same card/muted/border relationships, same
   0.625rem radius. What is NOT ported is React, Tailwind and Radix: this page is lanes and a
   poll, and pulling in a node toolchain to render it would cost a build step in CI and in the
   image for no behaviour the page needs.

   Additions on top of shadcn: a semantic ramp (ok/run/fail) in the same oklch idiom, because
   shadcn ships only `destructive` and a pipeline board has three states that must be
   distinguishable at a glance.
   ───────────────────────────────────────────────────────────────────────────────────────── */
:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.55 0.24 264);
  /* Komodor blue, #1247FE. */
  --brand: oklch(0.48 0.26 264);
  --destructive: oklch(0.577 0.245 27.325);
  /* semantic ramp — shadcn ships only destructive; a pipeline needs three legible states */
  --ok: oklch(0.52 0.13 155); --ok-bg: oklch(0.95 0.03 155);
  --run: oklch(0.56 0.12 75);  --run-bg: oklch(0.96 0.04 85);
  --fail: oklch(0.577 0.245 27.325); --fail-bg: oklch(0.95 0.03 25);
  --idle: oklch(0.556 0 0); --idle-bg: oklch(0.97 0 0);
  --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.05);
  --shadow: 0 1px 3px 0 oklch(0 0 0 / 0.1), 0 1px 2px -1px oklch(0 0 0 / 0.1);
}
@media (prefers-color-scheme: dark) { :root:not([data-theme=light]) {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.708 0 0);
  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.62 0.20 264);
  --brand: oklch(0.70 0.19 264);
  --destructive: oklch(0.704 0.191 22.216);
  --ok: oklch(0.75 0.16 155); --ok-bg: oklch(0.28 0.05 155);
  --run: oklch(0.80 0.14 80); --run-bg: oklch(0.30 0.05 80);
  --fail: oklch(0.704 0.191 22.216); --fail-bg: oklch(0.30 0.07 25);
  --idle: oklch(0.708 0 0); --idle-bg: oklch(0.269 0 0);
  --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.3);
  --shadow: 0 1px 3px 0 oklch(0 0 0 / 0.5), 0 1px 2px -1px oklch(0 0 0 / 0.5);
}}
:root[data-theme=dark] {
  --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0);
  --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0);
  --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.62 0.20 264); --brand: oklch(0.70 0.19 264);
  --destructive: oklch(0.704 0.191 22.216);
  --ok: oklch(0.75 0.16 155); --ok-bg: oklch(0.28 0.05 155);
  --run: oklch(0.80 0.14 80); --run-bg: oklch(0.30 0.05 80);
  --fail: oklch(0.704 0.191 22.216); --fail-bg: oklch(0.30 0.07 25);
  --idle: oklch(0.708 0 0); --idle-bg: oklch(0.269 0 0);
  --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.3);
  --shadow: 0 1px 3px 0 oklch(0 0 0 / 0.5), 0 1px 2px -1px oklch(0 0 0 / 0.5);
}

* { box-sizing: border-box }
html { color-scheme: light }
@media (prefers-color-scheme: dark) { html:not([data-theme=light]) { color-scheme: dark } }
html[data-theme=dark] { color-scheme: dark }
body {
  margin:0; background:var(--background); color:var(--foreground);
  font:14px/1.45 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
  padding:20px 24px 24px; -webkit-font-smoothing:antialiased;
}
.mono, .n, code { font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace }
.sans { font-family:inherit }
.wrap { max-width:1600px; margin:0 auto; display:flex; flex-direction:column; gap:16px }
a { color:inherit; text-underline-offset:3px }

/* ── masthead ── */
header { display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap }
/* Wraps. The brand holds the logo plus two tab groups — six buttons — and unwrapped it measured
   739px inside a 720px viewport, so the whole PAGE scrolled sideways and the tab strip drifted off
   the right edge. This, not the metrics tables, was the page-level overflow. */
.brand { display:flex; align-items:center; gap:12px; flex-wrap:wrap }
/* The Komodor mark, inlined rather than linked. The page's own CSP is
   `img-src 'self' https://avatars.githubusercontent.com data:`, so a logo served from a CDN
   would be blocked outright. Inline also means it inherits currentColor and therefore themes
   itself, which a raster favicon copy would not. */
.logo { display:block; text-decoration:none; color:var(--brand); padding:2px 0 }
.logo:hover { opacity:.85 }
/* Full logo — shown when sidebar is expanded. */
.logo-full { display:block; width:100%; height:auto; border-radius:10px;
             transition:width 0.22s cubic-bezier(0.4,0,0.2,1) }
@media (prefers-color-scheme: dark) { :root:not([data-theme=light]) .logo-full {
  background:oklch(0.92 0.02 264);
} }
[data-theme=dark] .logo-full { background:oklch(0.92 0.02 264) }
/* Small logo — hidden when expanded, shown when collapsed. */
.logo-small { display:none }
:root.mini .logo { padding:4px 0; display:flex; justify-content:center; align-items:center }
:root.mini .logo-full { display:none }
:root.mini .logo-small { display:block; width:32px; height:32px;
                         object-fit:cover; object-position:center center; border-radius:8px }
.mark { width:24px; height:auto; flex:none }
.logo h1 { font-size:15px; font-weight:650; letter-spacing:.14em; color:var(--foreground); margin:0 }
.trend { font-size:12px; margin-left:6px; vertical-align:middle; cursor:help }
.gates tr.click { cursor:pointer }
.gates tr.click:hover td { background:var(--muted) }
.gates tr.open .chev { transform:rotate(90deg) }
.gates tr.jobs > td { background:var(--muted); padding:12px 14px }
table.sub { width:100%; border-collapse:collapse; font-size:12px }
table.sub th { text-align:left; font-weight:600; color:var(--muted-foreground); padding:4px 8px }
table.sub td { padding:4px 8px; border-top:1px solid var(--border) }
.trend.better { color:var(--ok) } .trend.worse { color:var(--destructive) }
.was { color:var(--muted-foreground); margin-left:4px }
.btn.act { border-color:var(--brand); color:var(--brand) }
.btn.ghost { opacity:.6 }
/* Announcements that must be visible from ANY view — flash() used to write into #locate,
   which lives inside the CI section and is hidden from Metrics or when CI is collapsed. */
.toast { position:fixed; left:50%; bottom:26px; transform:translateX(-50%) translateY(8px);
         background:var(--card); border:1px solid var(--border); border-radius:999px;
         padding:9px 16px; font-size:12.5px; box-shadow:var(--shadow-sm);
         opacity:0; pointer-events:none; transition:opacity .18s, transform .18s; z-index:60 }
.toast.on { opacity:1; transform:translateX(-50%) translateY(0) }
.histtable tr:focus-visible { outline:2px solid var(--ring); outline-offset:-2px }
/* ── tickets ─────────────────────────────────────────────────────────────────────────── */
#tickets { display:flex; flex-direction:column; gap:14px }
.ipanel { border:1px solid var(--border); border-radius:var(--radius); background:var(--card);
          overflow:hidden }
.ipanel > h2 { font-size:13px; font-weight:600; margin:0; padding:11px 14px;
               border-bottom:1px solid var(--border); display:flex; align-items:center; gap:10px }
.ipanel > h2 .hint { font-weight:400 }
.igroup-head { display:flex; align-items:center; gap:10px; padding:9px 14px;
               background:var(--muted); border-top:1px solid var(--border) }
.igroup-head h3 { font-size:12px; font-weight:600; margin:0; text-transform:uppercase;
                  letter-spacing:.04em; color:var(--muted-foreground) }
.igroup-head .n { margin-left:auto; font-variant-numeric:tabular-nums; font-size:12px }
.irow { display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:12px; align-items:start;
        padding:9px 14px; border-top:1px solid var(--border); font-size:12.5px }
.irow .num { color:var(--muted-foreground); font-variant-numeric:tabular-nums }
.irow .title { overflow:hidden; text-overflow:ellipsis }
.irow .meta { display:flex; gap:6px; align-items:center; flex-wrap:wrap; margin-top:4px }
.tag { font-size:10.5px; padding:1px 7px; border-radius:999px; border:1px solid var(--border);
       color:var(--muted-foreground); white-space:nowrap }
.tag.p0, .tag.p1 { border-color:var(--destructive); color:var(--destructive) }
.tag.inferred { border-style:dashed }
.prchip { font-size:11px; padding:1px 7px; border-radius:999px; border:1px solid var(--border);
          cursor:pointer; white-space:nowrap; background:transparent; color:inherit;
          font-family:inherit }
.prchip:hover { background:var(--muted) }
.prchip .where { color:var(--muted-foreground) }
.card-issue { font-size:11px; color:var(--muted-foreground); text-decoration:none;
              border-top:1px dashed var(--border); padding-top:5px; margin-top:1px }
.card-issue:hover { color:var(--foreground); text-decoration:underline }
.refresh { border:1px solid var(--border); background:transparent; color:var(--muted-foreground);
           border-radius:8px; padding:0 9px; font:inherit; font-size:11.5px; cursor:pointer;
           display:inline-flex; align-items:center; gap:5px; height:34px; box-sizing:border-box }
.refresh:hover { color:var(--foreground); background:var(--muted) }
.refresh[aria-busy=true] { opacity:.6; pointer-events:none }
.refresh .spin { display:inline-block }
.refresh[aria-busy=true] .spin { animation:spin .7s linear infinite }
@keyframes spin { to { transform:rotate(360deg) } }
.picker { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:11px 14px;
          font-size:12.5px }
select.sel, input.sel { background:var(--card); color:inherit; border:1px solid var(--border);
                        border-radius:8px; padding:4px 8px; font:inherit; font-size:12px;
                        height:34px; box-sizing:border-box }
select.sel:disabled { opacity:.5 }
.iempty { padding:22px 14px; text-align:center; color:var(--muted-foreground); font-size:13px }
.tix { width:100%; border-collapse:collapse; font-size:12.5px }
.tix th { text-align:left; font-weight:600; font-size:11px; text-transform:uppercase;
          letter-spacing:.04em; color:var(--muted-foreground); padding:8px 12px;
          border-bottom:1px solid var(--border); background:var(--muted); white-space:nowrap;
          position:sticky; top:0; z-index:1 }
.tix td { padding:8px 12px; border-bottom:1px solid var(--border); vertical-align:top }
.tix tr:hover td { background:var(--muted) }
.tix .num { color:var(--muted-foreground); font-variant-numeric:tabular-nums; white-space:nowrap }
.tix .t { min-width:220px }
.tix .t a { display:block }
.tix .who, .tix .when { white-space:nowrap; color:var(--muted-foreground) }
.tix .solves { min-width:150px }
.tix .mine td:first-child { box-shadow:inset 2px 0 0 var(--ok) }
/* Tickets and the metrics tables. Their cells are `nowrap`, so without a scrolling box around
   them a narrow window makes the whole DOCUMENT scroll sideways instead of the table. */
.tixwrap, .xscroll { overflow-x:auto }
/* The same shape as the R&D board's own team views: a column per workflow status, so the
   question "where is this work" is answered by position rather than by reading a cell. */
.kan { display:flex; gap:12px; overflow-x:auto; padding:12px; align-items:flex-start }
.kcol { flex:0 0 300px; display:flex; flex-direction:column; gap:8px }
.kcol-head { display:flex; align-items:center; gap:8px; font-size:12.5px; font-weight:600;
             padding:2px 2px 6px }
.kcol-head .dot { width:9px; height:9px; border-radius:9999px; border:2px solid currentColor;
                  flex:none }
.kcol-head .n { margin-left:auto; color:var(--muted-foreground); font-weight:500;
                font-variant-numeric:tabular-nums }
.kcard { border:1px solid var(--border); border-radius:10px; background:var(--card);
         padding:10px 11px; display:flex; flex-direction:column; gap:7px; font-size:12.5px }
.kcard:hover { border-color:var(--ring) }
.kcard.mine { box-shadow:inset 3px 0 0 var(--ok) }
.kcard .top { display:flex; align-items:center; gap:6px; color:var(--muted-foreground);
              font-size:11.5px }
.kcard .top .who { margin-left:auto }
.kcard a.kt { color:inherit; text-decoration:none; line-height:1.35 }
.kcard a.kt:hover { text-decoration:underline }
.kcard .foot { display:flex; align-items:center; gap:6px; flex-wrap:wrap }
.kcard select.sel { padding:2px 6px; font-size:11px }
.kempty { border:1px dashed var(--border); border-radius:10px; padding:14px; text-align:center;
          color:var(--muted-foreground); font-size:12px }
.kcard[draggable="true"] { cursor:grab }
.kcard.dragging { opacity:.45; cursor:grabbing }
.kcard.saving { opacity:.6; pointer-events:none }
/* The drop target is the COLUMN, not the gap between cards: this board has no ordering within
   a status, so asking someone to aim at a 4px seam would be precision for nothing. */
.kcol.over .kdrop { border-color:var(--ring); background:var(--muted) }
.kdrop { border:1px dashed transparent; border-radius:10px; display:flex; flex-direction:column;
         gap:8px; min-height:56px; padding:2px; transition:background .12s, border-color .12s;
         overflow-y:auto; max-height:min(52vh,440px) }
.overdue { color:var(--destructive) }
.cov { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:11px 14px;
       font-size:12.5px }
.cov .bar { flex:1; min-width:120px; max-width:320px; height:6px; border-radius:999px; background:var(--muted);
            overflow:hidden }
.cov .bar span { display:block; height:100%; background:var(--ok) }
/* premium issue-links panel */
.cov-premium { display:grid; grid-template-columns:auto 1fr auto; align-items:center;
               gap:0 24px; padding:18px 18px 16px }
.covp-hero { display:flex; align-items:baseline; gap:0; flex-shrink:0 }
.covp-count { font-size:26px; font-weight:700; font-variant-numeric:tabular-nums;
              line-height:1; color:var(--foreground) }
.covp-denom { font-size:13px; color:var(--muted-foreground); margin-right:10px }
.covp-pct { font-size:11.5px; font-weight:600; color:var(--ok);
            background:var(--ok-bg); padding:2px 8px; border-radius:999px;
            font-variant-numeric:tabular-nums }
.covp-track { display:flex; align-items:center }
.covp-bar { height:8px; border-radius:999px; background:var(--muted); overflow:hidden;
            display:flex; width:100% }
.covp-seg { height:100%; transition:width .3s ease }
.covp-official { background:var(--ok) }
.covp-inferred { background:var(--brand); opacity:.65 }
.covp-stats { display:flex; flex-direction:column; gap:5px; flex-shrink:0 }
.covp-stat { display:flex; align-items:center; gap:6px; font-size:11.5px;
             color:var(--muted-foreground) }
.covp-dot { width:7px; height:7px; border-radius:50%; flex-shrink:0 }
.covp-dot.covp-official { background:var(--ok) }
.covp-dot.covp-inferred { background:var(--brand); opacity:.65 }
.covp-dot.covp-none { background:var(--muted-foreground); opacity:.4 }
.covp-stat-n { font-weight:600; font-variant-numeric:tabular-nums;
               color:var(--foreground); min-width:20px }
.relnotes { white-space:pre-wrap; font-family:ui-monospace,Menlo,monospace; font-size:12px;
            background:var(--muted); padding:12px; border-radius:8px; overflow:auto }

/* ── the three sections ───────────────────────────────────────────────────────────────── */
.sec { border:1px solid var(--border); border-radius:var(--radius); background:var(--card);
       margin-bottom:14px; overflow:hidden }
.sec-head { display:flex; align-items:center; gap:12px; padding:11px 14px;
            border-bottom:1px solid var(--border); flex-wrap:wrap }
.sec-toggle { display:flex; align-items:center; gap:8px; background:none; border:none;
              padding:0; cursor:pointer; color:var(--foreground); font:inherit }
.sec-toggle h2 { font-size:14px; font-weight:600; margin:0; letter-spacing:-.01em }
.sec-toggle[aria-expanded="true"] .chev { transform:rotate(90deg) }
.sec-sub { font-size:12px; color:var(--muted-foreground) }
.sec-body { padding:14px }
.sec-body.hide { display:none }
/* A collapsed section keeps its header border off, so it reads as one bar rather than a
   box with nothing in it. */
.sec:has(.sec-body.hide) .sec-head { border-bottom:none }
.search.sm { max-width:210px; height:28px; font-size:12px }
.search.sm input { font-size:12px; height:28px }

/* ── history table ───────────────────────────────────────────────────────────────────── */
.histtable { width:100%; border-collapse:collapse; font-size:12.5px }
.histtable th { text-align:left; font-weight:500; color:var(--muted-foreground);
                padding:6px 10px; border-bottom:1px solid var(--border); font-size:11.5px }
.histtable td { padding:7px 10px; border-bottom:1px solid var(--border) }
.histtable tbody tr:hover { background:var(--muted) }
.histtable tr.expandable { cursor:pointer }
.histtable .mono { font-family:ui-monospace,Menlo,monospace }
.histtable .prcell { color:var(--brand) }
.histrow-prs td { background:var(--muted); padding:0 10px 10px 28px }
.histfoot { display:flex; align-items:center; gap:12px; padding-top:12px }
.histfoot .hint { margin:0 }
.env-pill { font-size:11px; padding:1px 7px; border-radius:999px; border:1px solid var(--border);
            color:var(--muted-foreground) }
.crumbs { display:flex; align-items:center; gap:8px; font-size:12px }
.crumb { background:none; border:none; padding:0; color:var(--brand); cursor:pointer;
         font:inherit }
.crumb:hover { text-decoration:underline }
.crumb-sep { color:var(--muted-foreground) }
.crumb-now { font-weight:600 }
.crumb-hint { color:var(--muted-foreground) }
/* Top level: one card per pipeline, big enough to read at a glance. */
.pipe { position:absolute; box-sizing:border-box; border:1px solid var(--border);
        border-left-width:4px; border-radius:var(--radius); background:var(--card);
        padding:14px 16px; cursor:pointer; transition:border-color .12s, transform .12s }
.pipe:hover { border-color:var(--muted-foreground); transform:translateY(-2px) }
.pipe:focus-visible { outline:2px solid var(--ring); outline-offset:2px }
.pipe.s-fail{border-left-color:var(--destructive)} .pipe.s-run{border-left-color:var(--run)}
.pipe.s-ok{border-left-color:var(--ok)} .pipe.s-idle{border-left-color:var(--idle)}
.pipe-name { font-size:16px; font-weight:600; letter-spacing:-.01em }
.pipe-meta { font-size:12px; color:var(--muted-foreground); margin-top:6px;
             display:flex; align-items:center; gap:7px }
.pipe-bar { height:5px; border-radius:999px; background:var(--muted); margin-top:12px;
            overflow:hidden }
.pipe-bar span { display:block; height:100%; background:var(--idle) }
.pipe-bar span.s-ok{background:var(--ok)} .pipe-bar span.s-fail{background:var(--destructive)}
.pipe-bar span.s-run{background:var(--run)}
.pipe-open { font-size:11.5px; color:var(--brand); margin-top:10px }
.approws { display:flex; flex-direction:column; gap:2px }
.approw { display:grid; grid-template-columns:1fr auto auto; gap:12px; align-items:center;
          padding:7px 8px; border-radius:7px; font-size:12.5px }
.approw:hover { background:var(--muted) }
.approw.bad { background:var(--fail-bg);
              box-shadow:inset 2px 0 0 var(--destructive) }
.app-name { font-family:ui-monospace,Menlo,monospace; overflow:hidden;
            text-overflow:ellipsis; white-space:nowrap }
.app-state { display:flex; gap:5px; flex:none }
.app-act { display:flex; gap:5px; flex:none }
.btn.act:disabled { opacity:.6; cursor:progress }
.env-act { margin-top:8px }
.bar-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
             color:var(--muted-foreground); font-size:12.5px }
.bar-label.peak { font-weight:650; color:var(--foreground) }
.bar-n { font-variant-numeric:tabular-nums; color:var(--muted-foreground); font-size:11.5px }
footer { display:flex; align-items:center; justify-content:center; gap:10px;
         padding:16px 0; font-size:11.5px; color:var(--muted-foreground);
         padding-left:var(--rail);
         transition:padding-left 0.22s cubic-bezier(0.4,0,0.2,1) }
footer .dot { opacity:.5 }
footer code { font-family:ui-monospace,Menlo,monospace }
h1 { margin:0; font-size:16px; font-weight:600; letter-spacing:-.01em }
.live { display:flex; align-items:center; gap:10px; font-size:12px; color:var(--muted-foreground) }
.pulse { width:7px; height:7px; border-radius:9999px; background:var(--ok) }
.pulse.stale { background:var(--destructive) }
#who { display:flex; align-items:center; gap:8px }
#who img { width:22px; height:22px; border-radius:9999px; border:1px solid var(--border) }
#who a { font-size:12px; color:var(--muted-foreground); text-decoration:none }
#who a:hover { color:var(--foreground); text-decoration:underline }

/* ── shadcn: Tabs ── */
.repotabs { display:inline-flex; align-items:center; gap:4px; background:var(--muted);
            padding:3px; border-radius:calc(var(--radius) - 2px) }
.repotab { border:0; background:transparent; color:var(--muted-foreground); cursor:pointer;
           font:inherit; font-size:12.5px; font-weight:500; padding:5px 11px;
           border-radius:calc(var(--radius) - 4px); display:inline-flex; align-items:center; gap:6px }
.repotab:hover { color:var(--foreground) }
.repotab[aria-selected=true] { background:var(--card); color:var(--foreground); box-shadow:var(--shadow-sm) }
.repotab .n { font-size:11px; color:var(--muted-foreground) }
/* A bare "2✕" read as "times 2" rather than as "2 failing" — the person who commissioned this
   board had to ask what it meant, which settles it. The count now carries the word. */
.repotab .bad { font-size:11px; color:var(--destructive); font-weight:600 }

/* ── shadcn: Button ── */
.btn, .theme, .chip, .x {
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  border:1px solid var(--border); background:var(--card); color:var(--foreground);
  border-radius:calc(var(--radius) - 2px); padding:0 12px; height:34px;
  font:inherit; font-size:13px; font-weight:500; cursor:pointer; text-decoration:none;
  transition:background-color .12s, border-color .12s, color .12s;
}
.btn:hover, .theme:hover, .chip:hover, .x:hover { background:var(--muted) }
.btn:focus-visible, .chip:focus-visible, .theme:focus-visible, .x:focus-visible,
.repotab:focus-visible, .card:focus-visible, input:focus-visible {
  outline:none; box-shadow:0 0 0 1px var(--ring); border-color:var(--ring);
}
.theme, .x { padding:0; width:34px }
.chip[aria-pressed=true] { background:var(--primary); color:var(--primary-foreground);
                           border-color:var(--primary) }
.chip.danger[aria-pressed=true] { background:var(--destructive); border-color:var(--destructive);
                                  color:oklch(0.985 0 0) }
.chip:disabled { opacity:.5; cursor:not-allowed }

/* ── shadcn: Card ── */
.card, .env, .lane, .alert, details.hist, .filters, .locate {
  background:var(--card); color:var(--card-foreground);
  border:1px solid var(--border); border-radius:var(--radius);
}

/* ── shadcn: Input ── */
.filters { display:flex; align-items:center; gap:8px; flex-wrap:wrap; padding:10px 12px;
           box-shadow:var(--shadow-sm) }
.search { position:relative; flex:1 1 280px; min-width:220px }
.search input {
  width:100%; height:34px; background:var(--background); border:1px solid var(--input);
  border-radius:calc(var(--radius) - 2px); color:var(--foreground); font:inherit; font-size:13px;
  padding:0 34px; box-shadow:var(--shadow-sm);
}
.search input::placeholder { color:var(--muted-foreground) }
.search .mag { position:absolute; left:12px; top:50%; transform:translateY(-50%);
               color:var(--muted-foreground); font-size:13px }
.search kbd { position:absolute; right:10px; top:50%; transform:translateY(-50%); font-size:10px;
              color:var(--muted-foreground); border:1px solid var(--border); border-radius:4px;
              padding:1px 5px; background:var(--muted); font-family:inherit }

/* ── locator ── */
.locate { display:flex; align-items:center; gap:12px; flex-wrap:wrap; padding:12px 14px;
          font-size:13px; box-shadow:var(--shadow-sm) }
.locate b { font-weight:600 }
.locate.miss { color:var(--muted-foreground) }

/* ── environments ── */
.envs { display:grid; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); gap:12px }
.env { padding:16px; display:flex; flex-direction:column; gap:10px; box-shadow:var(--shadow-sm) }
.env.warn { border-color:var(--run) } .env.bad { border-color:var(--destructive) }
.env-top { display:flex; align-items:center; justify-content:space-between; gap:10px }
.env-name { font-size:14px; font-weight:600; letter-spacing:-.01em }
.gap { display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin-top:10px;
       padding:9px 12px; border:1px solid var(--border); border-radius:var(--radius);
       font-size:12.5px; background:var(--card) }
.gap.ready { border-color:color-mix(in srgb, var(--run) 45%, var(--border)) }
.gap code { font-size:11.5px }
.env-ver { font-size:12.5px; color:var(--muted-foreground); text-decoration:none;
           font-family:ui-monospace,Menlo,monospace }
.env-ver:hover { color:var(--foreground); text-decoration:underline }
/* One line for the steady state. The old three-row <dl> plus two verdict sentences said the
   same thing every five seconds whether or not anything had changed. */
.env-line { display:flex; align-items:center; gap:8px; font-size:12.5px;
            color:var(--muted-foreground); flex-wrap:wrap }
.env-line code { font-family:ui-monospace,Menlo,monospace; color:var(--foreground) }
.env-ok { color:var(--ok); font-weight:500; cursor:help }
.verdict { display:flex; align-items:center; gap:8px; font-size:12.5px; color:var(--muted-foreground) }
.lamp { width:8px; height:8px; border-radius:9999px; flex:none }
.lamp.ok{background:var(--ok)} .lamp.warn{background:var(--run)}
.lamp.bad{background:var(--destructive)} .lamp.unk{background:var(--idle)}
.lamp.run{background:var(--run); animation:pulse 2s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){ .lamp.run{animation:none} }
.env.rolling { border-color:var(--run) }

/* ── shadcn: Alert (destructive) ── */
.alert { border-color:var(--destructive); overflow:hidden; box-shadow:var(--shadow-sm) }
.alert-head { display:flex; align-items:center; gap:8px; padding:12px 16px 10px;
              color:var(--destructive); font-size:13px; font-weight:600; letter-spacing:-.01em }
.alert-body { display:flex; flex-direction:column }
.alert-row { display:flex; align-items:center; gap:12px; padding:10px 16px;
             border-top:1px solid var(--border); font-size:13px; cursor:pointer }
.alert-row:hover { background:var(--muted) }
.alert-row .what { color:var(--destructive); white-space:nowrap; font-weight:500 }
.alert-row .who { color:var(--muted-foreground); margin-left:auto; white-space:nowrap; font-size:12px }

/* ── the flow ── */
.rail { display:grid; grid-auto-flow:column; grid-auto-columns:minmax(200px,1fr);
        gap:12px; overflow-x:auto; padding-bottom:4px; align-items:start }
.lane { display:flex; flex-direction:column; box-shadow:var(--shadow-sm); overflow:hidden }
.lane.dim { opacity:.45 }
.lane.hit { border-color:var(--ring); box-shadow:0 0 0 3px var(--ring) }
.lane-head { padding:14px 14px 12px; display:flex; align-items:flex-start;
             justify-content:space-between; gap:8px; border-bottom:1px solid var(--border) }
.lane-step { font-size:11px; color:var(--muted-foreground); font-variant-numeric:tabular-nums }
.lane-name { font-size:14px; font-weight:600; letter-spacing:-.01em; margin-top:2px }
.lane-sub { font-size:12px; color:var(--muted-foreground); margin-top:2px }
/* Only drawn when a rollout is genuinely in flight — the lane name alone used to imply motion
   that was not happening. */
.lane-live { font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:.06em;
             color:var(--ok); border:1px solid var(--ok); border-radius:999px;
             padding:1px 6px; vertical-align:middle; margin-left:6px;
             animation:pulse 2s ease-in-out infinite }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.45} }
@media (prefers-reduced-motion:reduce) { .lane-live { animation:none } }
.count { font-size:20px; font-weight:600; font-variant-numeric:tabular-nums; line-height:1 }
.count.zero { color:var(--muted-foreground); font-weight:400 }
.lane-body { padding:10px; display:flex; flex-direction:column; gap:8px;
             overflow-y:auto; max-height:min(52vh,440px) }

.card { padding:11px 12px; display:flex; flex-direction:column; gap:6px; cursor:pointer;
        box-shadow:none; transition:background-color .12s, border-color .12s }
.card:hover { background:var(--muted) }
.card.s-fail { border-left:3px solid var(--destructive) }
.card.s-run  { border-left:3px solid var(--run) }
.card.s-ok   { border-left:3px solid var(--ok) }
.card.match  { border-color:var(--ring) }
.card-top { display:flex; align-items:center; justify-content:space-between; gap:8px }
.pr { font-size:12.5px; font-weight:600; font-family:ui-monospace,Menlo,monospace;
      text-decoration:none }
.card a.pr:hover { text-decoration:underline }
.card-title { font-size:13px; line-height:1.4;
              display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
.card-sub { font-size:11.5px; color:var(--muted-foreground);
            font-family:ui-monospace,Menlo,monospace }
.lane-empty { color:var(--muted-foreground); font-size:12.5px; padding:20px 4px; text-align:center }

/* ── shadcn: Badge ── */
.tag { display:inline-flex; align-items:center; border-radius:9999px; padding:2px 9px;
       font-size:11px; font-weight:500; white-space:nowrap; border:1px solid transparent }
.t-ok{background:var(--ok-bg);color:var(--ok)} .t-run{background:var(--run-bg);color:var(--run)}
.t-fail{background:var(--fail-bg);color:var(--fail)} .t-idle{background:var(--idle-bg);color:var(--muted-foreground)}

/* ── shadcn: Sheet ── */
.scrim { position:fixed; inset:0; background:oklch(0 0 0 / 0.5); opacity:0; pointer-events:none;
         transition:opacity .2s; z-index:40 }
.scrim.on { opacity:1; pointer-events:auto }
.drawer { position:fixed; inset:0 0 0 auto; width:min(520px,100%); background:var(--background);
          border-left:1px solid var(--border); z-index:50; transform:translateX(100%);
          transition:transform .3s cubic-bezier(.32,.72,0,1); display:flex; flex-direction:column;
          box-shadow:var(--shadow) }
.drawer.on { transform:none }
@media (prefers-reduced-motion:reduce){ .drawer,.scrim,.card{transition:none} }
.d-head { padding:22px 24px 16px; border-bottom:1px solid var(--border); display:flex;
          justify-content:space-between; align-items:flex-start; gap:14px }
.d-head h3 { margin:0 0 4px; font-size:17px; font-weight:600; letter-spacing:-.015em }
.d-sub { font-size:13px; color:var(--muted-foreground) }
.d-body { padding:20px 24px 40px; overflow-y:auto; display:flex; flex-direction:column; gap:22px }
.d-body h4 { margin:0 0 10px; font-size:12px; font-weight:600; color:var(--muted-foreground);
             letter-spacing:.02em }
dl.kv { display:grid; grid-template-columns:auto 1fr; gap:8px 16px; font-size:13px; margin:0 }
dl.kv dt { color:var(--muted-foreground) }
dl.kv dd { margin:0; font-family:ui-monospace,Menlo,monospace }
.drawer-actions { display:flex; flex-wrap:wrap; gap:8px }
.item { border:1px solid var(--border); border-radius:calc(var(--radius) - 2px); padding:10px 12px;
        display:flex; flex-direction:column; gap:4px; font-size:13px; margin-bottom:8px }

/* ── journey ── */
.trip { display:flex; flex-direction:column }
.leg { display:grid; grid-template-columns:14px 1fr auto; gap:12px; align-items:start;
       padding:11px 0; position:relative }
.leg + .leg::before { content:""; position:absolute; left:6px; top:-11px; height:22px; width:2px;
                      background:var(--border); border-radius:9999px }
.leg .bullet { width:10px; height:10px; border-radius:9999px; margin-top:4px;
               background:var(--idle); box-shadow:0 0 0 3px var(--background) }
.leg.ok .bullet{background:var(--ok)} .leg.run .bullet{background:var(--run)}
.leg.fail .bullet{background:var(--destructive)}
.leg .stage { font-size:11px; color:var(--muted-foreground); font-weight:500 }
.leg .what { font-size:13px; margin-top:3px; display:flex; align-items:center; gap:8px; flex-wrap:wrap }
.leg .when { font-size:11.5px; color:var(--muted-foreground); white-space:nowrap; text-align:right }
.leg a.go { font-size:11.5px; color:var(--muted-foreground) }
.leg a.go:hover { color:var(--foreground) }

/* ── jobs and steps ── */
.jobsum { font-size:12.5px; color:var(--muted-foreground); margin-bottom:10px }
.job { border:1px solid var(--border); border-radius:calc(var(--radius) - 2px);
       margin-bottom:8px; overflow:hidden }
.job-head { display:flex; align-items:center; justify-content:space-between; gap:8px;
            padding:9px 12px; background:var(--muted); font-size:12.5px; cursor:pointer;
            list-style:none; font-weight:500 }
.job-head::-webkit-details-marker { display:none }
details[open] > .job-head .chev { transform:rotate(90deg) }
.steps { display:flex; flex-direction:column }
.leg.click { cursor:pointer }
.leg.click:hover { background:var(--muted) }
.leg.open .chev { transform:rotate(90deg) }
.legsteps { padding:0 0 8px 26px }
.legsteps .job-head { font-size:12px }
.step { display:flex; align-items:center; gap:10px; padding:6px 12px; font-size:12px;
        border-top:1px solid var(--border) }
.step .ic { width:14px; flex:none; text-align:center; color:var(--muted-foreground) }
.step .nm { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.step.f .ic, .step.f .nm { color:var(--destructive) }
.step.r .ic, .step.r .nm { color:var(--run) }
.step.s .nm { color:var(--muted-foreground) }
.loading { color:var(--muted-foreground); font-size:12.5px; padding:8px 0 }
.tix-spinner { display:flex; justify-content:center; padding:48px 0 }
.spinner { width:22px; height:22px; border-radius:50%;
           border:2px solid var(--border); border-top-color:var(--muted-foreground);
           animation:spin .7s linear infinite }

/* ── canvas ──────────────────────────────────────────────────────────────────────────────
   A pipeline graph rather than a list: stages as nodes, the flow between them as edges, and
   the work sitting at each stage drawn inside it. Same data as the lanes — this is a second
   way to read it, not a second source. */
.canvas-bar { display:flex; align-items:center; gap:8px; margin-bottom:10px }
.spacer { flex:1 }
.canvas-hint { font-size:12px; color:var(--muted-foreground) }
.btn.sm { height:30px; font-size:12px; padding:0 10px }
.btn kbd { font:inherit; font-size:10px; border:1px solid var(--border); border-radius:4px;
           padding:0 4px; color:var(--muted-foreground); background:var(--muted) }
.canvas { position:relative; overflow:hidden; height:min(66vh,620px); cursor:grab;
          background:var(--card); border:1px solid var(--border); border-radius:var(--radius);
          background-image:radial-gradient(var(--border) 1px, transparent 1px);
          background-size:22px 22px }
.canvas.grabbing { cursor:grabbing }
.canvas-stage { position:absolute; inset:0; transform-origin:0 0 }
/* The pipeline graph. One box per JOB, columns are dependency depth, so boxes sharing a
   column genuinely run at the same time. */
.gnode { position:absolute; box-sizing:border-box; border:1px solid var(--border); border-left-width:3px;
         border-radius:var(--radius); background:var(--card); padding:8px 10px; cursor:pointer;
         transition:border-color .12s, transform .12s }
.gnode:hover { border-color:var(--muted-foreground); transform:translateY(-1px) }
.gnode:focus-visible { outline:2px solid var(--ring); outline-offset:2px }
.gnode.dim { opacity:.28 }
.gnode.spot { box-shadow:0 0 0 2px var(--ring) }
.gnode.s-fail{border-left-color:var(--destructive)} .gnode.s-run{border-left-color:var(--run)}
.gnode.s-ok{border-left-color:var(--ok)} .gnode.s-idle{border-left-color:var(--idle)}
.gnode-name { font-size:12.5px; font-weight:550; line-height:1.25; overflow:hidden;
              text-overflow:ellipsis; white-space:nowrap }
.gnode-meta { font-size:11px; color:var(--muted-foreground); margin-top:3px;
              display:flex; align-items:center; gap:6px }
.gdot { width:7px; height:7px; border-radius:9999px; flex:none; background:var(--idle) }
.gdot.s-ok{background:var(--ok)} .gdot.s-fail{background:var(--destructive)}
.gdot.s-run{background:var(--run)}
/* A `needs:` edge is free; a workflow_run hop is minutes of waiting. Draw them differently. */
.e-needs { fill:none; stroke:var(--border); stroke-width:1.5; color:var(--border) }
.e-needs.live { stroke:var(--run); color:var(--run); stroke-dasharray:5 4; animation:dash 1s linear infinite }
.e-trigger { fill:none; stroke:var(--muted-foreground); stroke-width:2; stroke-dasharray:2 5;
             color:var(--muted-foreground) }
.e-label { fill:var(--muted-foreground); font-size:10px; font-family:ui-monospace,Menlo,monospace }
@media (prefers-reduced-motion:reduce){ .e-needs.live{animation:none} }
.prlist { display:flex; flex-direction:column; gap:2px }
.prrow { display:grid; grid-template-columns:auto 1fr auto; gap:10px; align-items:center;
         padding:5px 6px; border-radius:6px; font-size:12.5px }
.prrow:hover { background:var(--muted) }
.prrow .who { color:var(--muted-foreground); font-size:11.5px }
.edges { position:absolute; inset:0; pointer-events:none; overflow:visible }
.edges path { fill:none; stroke:var(--border); stroke-width:2 }
.edges path.live { stroke:var(--run); stroke-dasharray:5 5; animation:dash 1s linear infinite }
@keyframes dash { to { stroke-dashoffset:-10 } }
@media (prefers-reduced-motion:reduce){ .edges path.live{animation:none} }

/* ── command palette ── */
.palette { position:fixed; inset:0; z-index:60; display:none; padding-top:12vh;
           background:oklch(0 0 0 / 0.5) }
.palette.on { display:block }
.palette-box { max-width:560px; margin:0 auto; background:var(--background);
               border:1px solid var(--border); border-radius:var(--radius);
               box-shadow:var(--shadow); overflow:hidden }
.palette input { width:100%; height:48px; border:0; border-bottom:1px solid var(--border);
                 background:transparent; color:var(--foreground); font:inherit; font-size:15px;
                 padding:0 16px; outline:none }
.palette ul { list-style:none; margin:0; padding:6px; max-height:52vh; overflow-y:auto }
.palette li { padding:9px 12px; border-radius:calc(var(--radius) - 4px); font-size:13.5px;
              display:flex; align-items:center; gap:10px; cursor:pointer }
.palette li[aria-selected=true] { background:var(--muted) }
.palette li .kind { font-size:11px; color:var(--muted-foreground); margin-left:auto }
.palette .none { padding:18px 14px; color:var(--muted-foreground); font-size:13px }

/* ── metrics ── */
.stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:12px }
.stat { background:var(--card); border:1px solid var(--border); border-radius:var(--radius);
        padding:16px; box-shadow:var(--shadow-sm) }
.stat .label { font-size:12.5px; color:var(--muted-foreground) }
.stat .value { font-size:26px; font-weight:600; letter-spacing:-.02em; margin-top:6px;
               font-variant-numeric:tabular-nums }
.stat .sub { font-size:12px; color:var(--muted-foreground); margin-top:4px }
.panel { background:var(--card); border:1px solid var(--border); border-radius:var(--radius);
         padding:16px 18px; box-shadow:var(--shadow-sm) }
.panel h3 { margin:0 0 2px; font-size:14px; font-weight:600; letter-spacing:-.01em }
.hint, .panel .hint { font-size:12.5px; color:var(--muted-foreground); margin-bottom:14px }
.bars { display:flex; flex-direction:column; gap:9px }
.bar-row { display:grid; grid-template-columns:130px 1fr auto; gap:12px; align-items:center;
           font-size:12.5px }
.bar-row .who { overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
                font-family:ui-monospace,Menlo,monospace }
.bar-track { height:20px; background:var(--muted); border-radius:6px; overflow:hidden; display:flex }
.bar-seg { height:100% }
.bar-seg.merged { background:var(--idle) }
.bar-seg.stg { background:var(--run) }
.bar-seg.prod { background:var(--ok) }
.num, .bar-row .num { font-variant-numeric:tabular-nums; color:var(--muted-foreground) }
.legend { display:flex; gap:14px; flex-wrap:wrap; font-size:12px; color:var(--muted-foreground);
          margin-top:14px }
.legend i { width:10px; height:10px; border-radius:3px; display:inline-block; margin-right:6px }
.metgrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(340px,1fr)); gap:12px }

/* ── shadcn: Table ── */
table { border-collapse:collapse; width:100%; font-size:13px }
th, td { text-align:left; padding:10px 16px; border-top:1px solid var(--border); white-space:nowrap }
th { font-size:12px; font-weight:500; color:var(--muted-foreground); background:var(--muted) }
tr.click { cursor:pointer } tr.click:hover td { background:var(--muted) }
.n { font-variant-numeric:tabular-nums }
.hide { display:none !important }

@media (max-width:900px) { .rail { grid-auto-flow:row; grid-auto-columns:auto } }

/* ── the metrics headline strip ──────────────────────────────────────────────────────────────
   Six figures at a size nothing else on the page competes with. The view used to open with
   fourteen panels of equal weight, which reads the same as having no headline at all. */
/* auto-FILL, not auto-fit, and a smaller floor: with six tiles and a 190px minimum a 1500px
   viewport fitted five and orphaned the sixth on a row of its own. */
.heroes { display:grid; grid-template-columns:repeat(auto-fill, minmax(165px, 1fr)); gap:10px }
.hero { background:var(--card); border:1px solid var(--border); border-radius:10px; padding:12px 14px }
.hero.click { cursor:pointer }
.hero.click:hover { border-color:var(--ring) }
.hlabel { font-size:11.5px; letter-spacing:.03em; text-transform:uppercase; color:var(--muted-foreground) }
.hvalue { font:600 26px/1.15 var(--sans); margin:4px 0 2px; display:flex; align-items:center; gap:6px }
.hnote { font-size:11.5px; color:var(--muted-foreground); line-height:1.45 }

/* ── charts ──────────────────────────────────────────────────────────────────────────────────
   Inline SVG. No library: the CSP blocks a CDN outright and vendoring one would put a node
   toolchain in CI for four small charts. */
/* ── expandable sections ─────────────────────────────────────────────────────────────────────
   The Metrics view was one nine-panel scroll where every panel had the same weight, which is the
   same as having no structure at all. These are native <details>, so keyboard and find-in-page
   work without any JS. */
.sec { border:1px solid var(--border); border-radius:10px; background:var(--card); overflow:hidden }
.sec + .sec { margin-top:2px }
.sec > summary {
  display:flex; align-items:baseline; gap:10px; padding:9px 14px; cursor:pointer;
  list-style:none; user-select:none;
}
.sec > summary .hint { margin-bottom:0 }
.sec > summary::-webkit-details-marker { display:none }
/* Unified chevron — shared by all accordions */
.chev { width:11px; height:11px; flex-shrink:0; color:var(--muted-foreground);
        transition:transform .15s ease; display:inline-block; vertical-align:middle }
.sec[open] .chev { transform:rotate(90deg) }
.sec > summary:hover { background:var(--accent) }
.sec > summary:focus-visible { outline:2px solid var(--ring); outline-offset:-2px }
.sectitle { font-size:13.5px; font-weight:650 }
.secbody { padding:0 14px 14px; border-top:1px solid var(--border) }
.secbody > .hint:first-child { margin-top:10px }
/* Panels nested inside a section: no second border, or every chart sits in a box in a box. */
.subpanel { padding-top:14px; min-width:0 }
/* A block inside the session drawer: same rhythm as the drawer's own <h4> sections. */
.dsec { margin-top:4px }
.dsec h4 { margin:0 0 6px; font-size:12.5px; font-weight:650 }
.subpanel h4 { margin:0 0 4px; font-size:12.5px; font-weight:650 }

.charts { display:grid; grid-template-columns:repeat(auto-fit, minmax(280px, 1fr)); gap:16px; margin-top:10px }
.cwrap { min-width:0 }                     /* or a wide chart pushes the grid instead of scaling */
/* One line, ALWAYS. These sit in a three-column grid and the qualifier used to live on the same
   flex row as the title — so the widest heading wrapped to two lines, shortening its chart and
   knocking it out of vertical alignment with the two beside it. The qualifier gets its own row. */
.chead { font-size:12px; font-weight:600; margin-bottom:2px; display:flex; gap:8px;
         align-items:baseline; white-space:nowrap }
.chead > .hint { overflow:hidden; text-overflow:ellipsis }
.csub { font-size:11px; color:var(--muted-foreground); margin-bottom:4px; min-height:15px }
.chart { width:100%; height:auto; display:block; overflow:visible }
.cbar { fill:var(--primary); opacity:.75 }
/* Weekend bands. Sits under the data — a Saturday with no deploys reads as a regression without
   this, and every reader has to count days from the axis to rule it out. */
.cwknd { fill:var(--muted-foreground); opacity:.07 }
.cgrid { stroke:var(--border); stroke-width:1; stroke-dasharray:2 3; vector-effect:non-scaling-stroke }
.cgrid.base { stroke-dasharray:none }
.cvlabel { fill:var(--muted-foreground); font-size:9.5px; text-anchor:end }
.cdlabel { fill:var(--muted-foreground); font-size:9.5px; text-anchor:middle }
.cdlabel.wknd { opacity:.55 }
.cbarn { fill:var(--foreground); font-size:9.5px; text-anchor:middle; font-weight:600 }
/* The chart's headline number, so it says something before you hover it. */
.cnow { font-size:12px; font-weight:700; color:var(--foreground) }
/* The unit rides with the number but must not shout: "4.9/day" reads as one figure. */
.cunit { font-weight:500; font-size:10.5px; color:var(--muted-foreground) }
.cbar.bad { fill:var(--destructive); opacity:.9 }
/* "Opened", drawn as an outline behind the merged bar: present enough to compare against, quiet
   enough that the solid bar is still the thing you read first. */
.cout { fill:none; stroke:var(--muted-foreground); stroke-width:1; opacity:.7;
        vector-effect:non-scaling-stroke }
.chit { fill:transparent }                 /* a full-height target, so hovering a 2px bar works */
.cwrap g:hover .cbar { opacity:1 }
.caxis { stroke:var(--border); stroke-width:1 }
.cline { fill:none; stroke:var(--primary); stroke-width:2; stroke-linejoin:round; stroke-linecap:round;
         vector-effect:non-scaling-stroke }
.cline.stg { stroke:var(--primary); opacity:.45 }
.cline.prd { stroke:var(--primary) }
.cdot { fill:var(--primary) }
/* A day whose median rests on one or two PRs is drawn smaller and paler — visible, but not
   claiming the same confidence as a day built on twenty. */
.cdot.thin { fill:var(--muted-foreground); opacity:.55 }

/* ── the shell: a left rail and a top bar ────────────────────────────────────────────────────
   The layout every observability console has settled on, because it is the one that survives six
   destinations. The COLOURS stay ours — the tokens above already do light and dark, and adopting
   another vendor's palette would break that for the sake of a resemblance. */
:root { --rail:224px }
/* NO GRID. The rail is fixed and the content is simply padded past it.
   A 2-column grid on `.wrap` looked right and was not: `grid-row: 1 / -1` collapses to row 1 when
   the explicit grid has one row, so the rail's `100vh` stretched that row and pushed every section
   below the fold. Taking the rail out of flow entirely means the number of sections cannot affect
   the layout at all. */
/* `.sidebar`, NOT `.rail` — the board has owned `class="rail"` for its lane container since long
   before this existed (see the grid rule further up). Appending a `.rail` rule here won on order
   and turned the board's lanes into a fixed sidebar sitting on top of the navigation. */
.sidebar { position:fixed; left:0; top:0; width:var(--rail); height:100vh; z-index:5;
         background:var(--card); border-right:1px solid var(--border);
         display:flex; flex-direction:column; gap:10px; padding:8px 10px; overflow-y:auto;
         overflow-x:hidden;
         transition:width 0.22s cubic-bezier(0.4,0,0.2,1) }
.wrap  { padding-left:var(--rail); max-width:none;
         transition:padding-left 0.22s cubic-bezier(0.4,0,0.2,1) }
.topbar{ display:flex; align-items:center; justify-content:space-between; gap:16px;
         padding:12px 20px; border-bottom:1px solid var(--border) }
.wrap > section, .wrap > footer { padding-left:20px; padding-right:20px }

.crumbs { display:flex; align-items:baseline; gap:10px }
.crumbs #crumb { font:600 15px/1.2 var(--sans) }

.railnav { display:flex; flex-direction:column; gap:2px }
.navitem { display:flex; align-items:center; gap:10px; width:100%; padding:8px 10px; border:0;
           border-radius:0 8px 8px 0; background:transparent; color:var(--muted-foreground);
           font:500 13px/1.2 var(--sans); cursor:pointer; text-align:left;
           /* The accent bar is what makes the active view findable at a glance. Transparent when
              inactive so the label does not shift by 3px on selection. */
           border-left:3px solid transparent }
.navitem:hover { background:var(--muted); color:var(--foreground) }
.navitem[aria-selected="true"] { background:var(--muted); color:var(--foreground);
                                 border-left-color:var(--primary) }
.navicon { width:16px; text-align:center; opacity:.85 }
.navlabel { flex:1; white-space:nowrap; overflow:hidden; max-width:200px; opacity:1;
            transition:max-width 0.22s cubic-bezier(0.4,0,0.2,1), opacity 0.15s ease }

.railfoot { margin-top:auto; display:flex; flex-direction:column; gap:8px }
.railsec  { font-size:10.5px; letter-spacing:.06em; text-transform:uppercase;
            color:var(--muted-foreground); padding:0 10px }
.repotabs.vertical { display:flex; flex-direction:column; gap:2px }
.repotabs.vertical .repotab { text-align:left; width:100% }
.railme { display:flex; align-items:center; justify-content:space-between; gap:8px;
          padding:8px 10px; border-top:1px solid var(--border); min-width:0 }
#who { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
       font-size:12px; display:flex; align-items:center; gap:6px }
#who > span, #who > a { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0 }
#who img { width:20px; height:20px; border-radius:50%; flex-shrink:0 }

/* Collapsed, either because the viewport is narrow or because the reader asked for it. ONE rule
   set for both: a second copy for the manual toggle is how the two states drift apart, and the
   `title` on every nav item — already there — is what keeps icons usable. */
:root.mini { --rail:56px }
:root.mini .navlabel { max-width:0; opacity:0 }
:root.mini .railsec, :root.mini .repotabs.vertical,
:root.mini .sidebar h1 { display:none }
:root.mini .navitem { justify-content:center }
/* Collapsed footer: hide the user label, center just the theme toggle — no border. */
:root.mini .railme { justify-content:center }
:root.mini #who { display:none }
:root.mini #theme { border-color:transparent; background:transparent }
/* The toggle stays visible when collapsed — hiding the way back out is a trap. */
.minitoggle { color:var(--muted-foreground) }

/* The tickets search box, sized to sit in the filter row with the selects. */
.tixq { min-width:180px }
/* The card title is a button now, not a link — the card opens the summary and the drawer carries
   the link out. Keeps the link's affordance without the navigation. */
.kt[role="button"] { cursor:pointer }
.kt[role="button"]:hover { text-decoration:underline }

@media (max-width: 900px) {
  :root { --rail:56px }
  .navlabel, .railsec, .repotabs.vertical, .sidebar h1 { display:none }
  .navitem { justify-content:center }
  /* Below 900px the rail is collapsed anyway, so the toggle has nothing to do. */
  .minitoggle { display:none }
}

/* ── sessions ────────────────────────────────────────────────────────────────────────────── */
/* Where the time went, in proportion. One flex row, no chart library. */
.pstrip { display:flex; height:10px; border-radius:5px; overflow:hidden; margin:8px 0 6px }
.pseg   { min-width:2px }
.plegend{ display:flex; flex-wrap:wrap; gap:10px; font-size:11px; color:var(--muted-foreground) }
.pdot   { display:inline-block; width:8px; height:8px; border-radius:2px; margin-right:4px }
.p-explore  { background:var(--primary); opacity:.45 }
.p-edit     { background:var(--primary) }
.p-verify   { background:#0d7d74 }
.p-operate  { background:var(--muted-foreground); opacity:.55 }
.p-ship     { background:#d97757 }
.p-delegate { background:var(--primary); opacity:.7 }
.p-browse   { background:#6a787c }
.p-integrate{ background:#8a6fb0 }
.p-human    { background:#d4a72c }
.p-other    { background:var(--border) }
.s-run  { background:color-mix(in srgb, var(--primary) 18%, transparent); color:var(--primary) }
/* Shown once and never again, so it has to look like something to copy rather than something to
   read past. */
.tok { background:var(--muted); border:1px solid var(--border); border-radius:8px; padding:10px;
       font:12px/1.6 var(--mono); white-space:pre-wrap; word-break:break-all; user-select:all }

/* A per-view control bar. The repo picker sits here rather than in the sidebar: only CI/CD and
   Metrics are about one repository, and a global picker implied it also changed Tickets (org-wide),
   Sessions (per person) and Home (yours). */
.viewbar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:14px 20px 0 }
.viewbarlabel { font-size:10.5px; letter-spacing:.06em; text-transform:uppercase;
                color:var(--muted-foreground) }

/* ── the session flow spine ───────────────────────────────────────────────────────────────────
   A state machine, not a picture. A step is filled when it was OBSERVED and hollow when it was
   not — and a hollow step between two filled ones is the interesting case, so it stays visible
   rather than being skipped over. */
.fgraph { display:flex; align-items:stretch; gap:4px; flex-wrap:wrap; margin:8px 0 }
.fnode  { display:flex; flex-direction:column; gap:2px; padding:8px 10px; min-width:104px;
          border:1px solid var(--border); border-radius:8px; background:var(--card) }
.fnode.off { opacity:.5; border-style:dashed }
.fdot   { font-size:11px; color:var(--muted-foreground) }
.fnode.on .fdot { color:var(--primary) }
.flabel { font-size:11.5px; font-weight:500; line-height:1.3 }
.fwhen  { font-size:10.5px; color:var(--muted-foreground) }
.farrow { align-self:center; color:var(--border); font-size:13px }
.farrow.on { color:var(--primary) }

/* ── the spine, banded ───────────────────────────────────────────────────────────────────────
   Three bands, each carrying the invariant it enforces, after the diagram in
   sdlc-graph-engineering. The bands are the argument, so they are visible structure rather than
   whitespace. */
.fband     { border:1px solid var(--border); border-radius:10px; padding:8px 10px; margin:8px 0 }
.fband.done{ border-color:color-mix(in srgb, var(--primary) 35%, var(--border)) }
.fbandhead { display:flex; align-items:baseline; gap:8px; font-size:10.5px; letter-spacing:.06em;
             text-transform:uppercase; color:var(--muted-foreground); margin-bottom:6px }
.fbandhead b { color:var(--foreground); letter-spacing:.08em }
/* The guard rides ON the edge, because the condition that fired is the informative half. */
.fedge     { display:inline-flex; flex-direction:column; align-items:center; justify-content:center;
             min-width:64px; padding:0 2px }
.fedge.off { opacity:.4 }
.fguard    { font-size:9.5px; line-height:1.2; text-align:center; color:var(--muted-foreground) }
.fedge.on .fguard { color:var(--primary) }
/* A bounded cycle is annotated, never drawn — a retry edge across the middle is what makes these
   diagrams unreadable. */
.fcycle    { position:absolute; top:4px; right:6px; font-size:10px; color:var(--destructive) }
.fnode     { position:relative }
.fterminal { margin-top:6px; padding:6px 10px; border-radius:8px; font-size:11.5px;
             background:var(--muted); color:var(--muted-foreground) }
.fterminal.running { color:var(--primary) }
.fterminal.blocked { color:var(--destructive) }

/* ── the drawer, widened ─────────────────────────────────────────────────────────────────────
   520px was sized for a run's job list. It now carries a four-band spine, a phase table and a
   ledger, and at that width the branch name alone wrapped over three lines. Wider, and with the
   long identifiers allowed to sit on one line. */
.drawer { width:min(860px, 94vw) }
.d-body { padding:20px 24px 40px; font-size:13.5px; line-height:1.55 }
.d-body h4 { margin:22px 0 8px; font-size:13px; letter-spacing:.01em }
.d-body h4:first-child { margin-top:0 }
/* Key/value: a fixed label column, so the values line up and a long branch stops re-wrapping the
   whole block. */
.d-body dl.kv { display:grid; grid-template-columns:88px 1fr; gap:4px 14px; margin:0 0 14px }
.d-body dl.kv dt { color:var(--muted-foreground); font-size:12px }
.d-body dl.kv dd { margin:0; overflow-wrap:anywhere }
.d-body .hint { font-size:12px; line-height:1.5 }
/* Tables in here are reference material, not the headline — smaller, and roomier per row. */
.d-body table { font-size:12.5px }
.d-body table td, .d-body table th { padding:6px 10px }
.d-body .drawer-actions { margin:14px 0 4px }

/* The spine gets room at this width: nodes wider, and the guard text legible rather than squeezed
   into 64px. */
.fband   { padding:10px 12px; margin:10px 0 }
.fnode   { min-width:124px; padding:9px 11px }
.flabel  { font-size:12px }
.fwhen   { font-size:11px }
.fedge   { min-width:78px }
.fguard  { font-size:10px }
.fterminal { font-size:12px; padding:8px 12px }
