:root {
  color-scheme: dark;
  --bg: #0a0c11; --panel: #10141c; --panel-2: #151a24; --line: #1e2531; --line-2: #2a3444;
  --text: #d8dee9; --dim: #6b7688; --faint: #4a5364; --accent: #a78bfa; --accent-2: #7c5cff;
  --green: #4ade80; --amber: #fbbf24; --red: #f87171; --blue: #60a5fa; --cyan: #22d3ee; --orange: #fb923c;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;

  /* Material Design loading tokens -- see mockup/dashboard-loading.html for
     the four rules these implement (skeleton on first paint, linear bar on
     refresh, circular for a busy section or control, nothing under 400ms). */
  --md-track: #232b3b;              /* progress track  (M3 secondaryContainer) */
  --md-indicator: var(--accent-2);  /* active indicator (M3 primary) */
  --md-skel: #171d29;               /* skeleton base   (M3 surfaceContainer) */
  --md-skel-hi: #232c3d;            /* shimmer highlight */
  --ease-emph-decel: cubic-bezier(.05, .7, .1, 1);
  --ease-standard: cubic-bezier(.2, 0, 0, 1);

  /* --- surfaces ------------------------------------------------------ */
  --sunken: #0c1017;            /* code, diffs, cost bars, detail rows */
  --sunken-2: #0b0e15;          /* inset search field */
  --row-hover: #0e121a;         /* table row hover (opaque) */
  --row-hover-soft: rgba(255,255,255,.02);
  --wash-violet: #1a1330;       /* body radial wash, top left */
  --wash-teal: #0d1f2e;         /* body radial wash, top right */
  --scrim: rgba(4, 6, 10, .55); /* behind the drawer */

  /* --- scrollbars ----------------------------------------------------- */
  /* Three steps, not one: --idle is where the sidebar rests, one notch up
     from the --line it runs beside; --scroll-thumb is every other scroll
     area, and the sidebar once the pointer is in it; --hover is the thumb
     itself under the pointer. */
  --scroll-thumb-idle: #212a39;
  --scroll-thumb: #313d51;
  --scroll-thumb-hover: #46546c;

  /* --- text ---------------------------------------------------------- */
  --text-2: #b9c2d0;            /* body prose */
  --code-text: #cbd5e1;

  /* --- accent -------------------------------------------------------- */
  /* --accent / --accent-2 above are text, borders AND the button fill.
     --on-accent is the label on that fill; it is not --wash-violet, even
     though the two share a value in this theme. */
  --on-accent: #1a1330;
  --accent-deep: #6d4df0;       /* second, deeper button gradient */
  --on-accent-deep: #ffffff;
  --accent-muted: #8b7bd8;
  --accent-soft: #1d1533;
  --accent-soft-line: #33265c;
  --accent-soft-text: #c4b5fd;
  --accent-wash: rgba(124, 92, 255, .06);
  --accent-wash-2: rgba(167, 139, 250, .05);
  --focus-ring-color: rgba(124, 92, 255, .18);

  /* --- brand gradient stops ------------------------------------------ */
  --brand-1: #c4b5fd; --brand-2: #7c5cff; --brand-3: #22d3ee;

  /* --- status tints: one border + one background per state ------------ */
  --tint-ok-bg: #0d2118;      --tint-ok-line: #1e4d33;
  --tint-warn-bg: #1f1a0a;    --tint-warn-line: #4d3d16;
  --tint-bad-bg: #1f0d0d;     --tint-bad-line: #4d2020;
  --tint-info-bg: #0a1e22;    --tint-info-line: #164a52;
  --tint-accent-bg: #17132a;  --tint-accent-line: #3a2f66;
  --tint-run-bg: #0d1a2e;     --tint-run-line: #1f3a66;
  --tint-halt-bg: #241505;    --tint-halt-line: #5c3517;
  --tint-stop-bg: #1a1e26;
  /* the two `.panel` variants are a shade off the pill tints; kept apart
     rather than collapsed, because the panel is a much larger area */
  --panel-warn-bg: #16130a;   --panel-win-bg: #0c1a13;
  /* segmented control, selected states */
  --seg-warn-bg: #2b2110;     --seg-info-bg: #0b2a2e;
  /* agent chip: a stronger info tint than the pill */
  --tint-info-bg-strong: #0a2530; --tint-info-line-strong: #114252;
  --tint-info-line-soft: #1d3b45;

  /* --- status text on a dark chip: lighter than the base ramp --------- */
  --green-soft: #86e5a5;  --amber-soft: #fcd34d;  --red-soft: #fca5a5;
  --cyan-soft: #67e0f0;   --blue-soft: #8ec2fb;   --orange-soft: #fdba74;
  --rose-soft: #fda4af;   --rose: #fb7185;        --red-pale: #f4c9c9;
  --amber-muted: #b08a2e; --amber-hi: #d9a83a;

  /* --- diff + run row washes ----------------------------------------- */
  --diff-add-bg: rgba(74, 222, 128, .06);
  --diff-del-bg: rgba(248, 113, 113, .06);
  --run-row-bg: rgba(74, 222, 128, .035);

  /* --- ticks --------------------------------------------------------- */
  --tick-ok-bg: #1d3a2a;   --tick-ok-line: #2c5e40;
  --tick-bad-bg: #3a1d1d;  --tick-bad-line: #6e2727;
  --tick-now-bg: #3a2f14;  --tick-now-line: #6e5a1f;

  /* --- elevation ----------------------------------------------------- */
  --shadow-color: rgba(0, 0, 0, .45);
}

/* White mode. Same rules, different token values -- see
   docs/superpowers/plans/2026-09-04-white-mode.md and mockup/white-mode.html.
   Every colour token above is redeclared here; a token added to one block and
   forgotten in the other leaks its dark value, so tests/test_theme_tokens.py
   enforces parity. Ratios below were measured against the composited
   background, not the swatch. */
[data-theme="light"] {
  color-scheme: light;

  --bg: #f7f8fa; --panel: #ffffff; --panel-2: #f2f4f7;
  --line: #e2e6ec; --line-2: #cbd2dc;
  --sunken: #eef1f5; --sunken-2: #f2f4f7;
  --row-hover: #f2f4f7; --row-hover-soft: rgba(15, 23, 42, .03);
  /* The washes are a text surface: the sidebar micro-labels sit on them, and
     they are darker than --bg. Kept very pale for that reason. */
  --wash-violet: #f3f0ff; --wash-teal: #eef8fb;
  --scrim: rgba(15, 23, 42, .30);

  /* On white the thumb is the darkest thing in an otherwise empty gutter,
     so all three steps land lighter than the dark ramp inverts to. */
  --scroll-thumb-idle: #dfe4ea;
  --scroll-thumb: #c3cbd7;
  --scroll-thumb-hover: #99a4b4;

  /* four steps, all >= 4.5:1 on every surface including the washes */
  --text: #1c212b; --text-2: #3c4453; --dim: #555f70; --faint: #626c77;
  --code-text: #334155;

  /* Green and amber sit a step darker than the usual 700 pick so they also
     clear 4.5:1 on --sunken, where the chips and diff rows live. */
  --green: #14762f; --amber: #a94f08; --red: #c81e1e;
  --blue: #1d4ed8; --cyan: #0e7490; --orange: #c2410c;
  --accent: #6d28d9; --accent-2: #5b21b6;

  /* --on-accent is NOT a cross-theme constant: against the light fill the
     dark label measures 2.51:1. Both gradient stops are checked, not just
     the dark end -- white on #7c5cff is only 4.35:1. */
  --on-accent: #ffffff;
  --accent-deep: #5b21b6; --on-accent-deep: #ffffff;
  --accent-muted: #6d28d9;
  --accent-soft: #f1ebfd; --accent-soft-line: #d9c9f7; --accent-soft-text: #5b21b6;
  --accent-wash: rgba(109, 40, 217, .06);
  --accent-wash-2: rgba(109, 40, 217, .05);
  --focus-ring-color: rgba(109, 40, 217, .20);

  /* all three stops must survive white; #c4b5fd and #22d3ee do not */
  --brand-1: #7c5cff; --brand-2: #5b21b6; --brand-3: #0e7490;

  --tint-ok-bg: #eaf6ee;      --tint-ok-line: #b7dfc4;
  --tint-warn-bg: #fdf3e7;    --tint-warn-line: #f0d9b0;
  --tint-bad-bg: #fdecec;     --tint-bad-line: #f3c2c2;
  --tint-info-bg: #e6f4f8;    --tint-info-line: #b3dbe6;
  --tint-accent-bg: #f1ebfd;  --tint-accent-line: #d9c9f7;
  --tint-run-bg: #eaf0fd;     --tint-run-line: #c2d5f8;
  --tint-halt-bg: #fdefe6;    --tint-halt-line: #f5cdb4;
  --tint-stop-bg: #f2f4f7;
  --panel-warn-bg: #fdf6ec;   --panel-win-bg: #eef8f1;
  --seg-warn-bg: #fdf3e7;     --seg-info-bg: #e6f4f8;
  --tint-info-bg-strong: #dcedf4; --tint-info-line-strong: #9ccbdb;
  --tint-info-line-soft: #cbe4ec;

  /* on a light chip the "soft" variants cannot be lighter than the base
     ramp -- they collapse onto it, and the chip tint carries the meaning */
  --green-soft: #14762f;  --amber-soft: #a94f08;  --red-soft: #c81e1e;
  --cyan-soft: #0e7490;   --blue-soft: #1d4ed8;   --orange-soft: #c2410c;
  --rose-soft: #be123c;   --rose: #be123c;        --red-pale: #c81e1e;
  --amber-muted: #a94f08; --amber-hi: #8a4007;

  --diff-add-bg: rgba(20, 118, 47, .08);
  --diff-del-bg: rgba(200, 30, 30, .07);
  --run-row-bg: rgba(20, 118, 47, .05);

  --tick-ok-bg: #cfeeda;   --tick-ok-line: #8fc9a5;
  --tick-bad-bg: #fbd5d5;  --tick-bad-line: #e59a9a;
  --tick-now-bg: #fbe6c4;  --tick-now-line: #ddb974;

  --md-track: #e2e6ec; --md-skel: #e9edf2; --md-skel-hi: #f6f8fb;

  /* same offsets, far less alpha -- .45 black reads as dirt on white */
  --shadow-color: rgba(15, 23, 42, .12);
}
* { box-sizing: border-box; }

/* --- scrollbars -------------------------------------------------------
   Every scroll area here is a bounded one -- the sidebar, the drawer body,
   a diagnostics table, a peeked log -- so the native bar always paints on
   top of a surface that already has a border, and its opaque 15px track
   reads as a second one. This is that bar as an overlay instead: no track,
   a pill thumb inset from the gutter by its own transparent border, and a
   single hover step. Firefox takes the two-property form; WebKit needs the
   pseudo-elements, and each `background` there has to restate
   `background-clip` or the inset border fills in. */
* { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb); background-clip: padding-box;
  border: 3px solid transparent; border-radius: 99px;
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: none; border-color: var(--accent-2); box-shadow: 0 0 0 3px var(--focus-ring-color);
}
button:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
body {
  margin: 0; color: var(--text);
  background:
    radial-gradient(1200px 600px at 15% -10%, var(--wash-violet) 0%, transparent 60%),
    radial-gradient(900px 500px at 95% 0%, var(--wash-teal) 0%, transparent 55%),
    var(--bg);
  background-attachment: fixed;
  font: 13.5px/1.65 var(--mono);
}
[v-cloak] { display: none; }
a { color: var(--cyan); }
button, input, textarea, select { font-family: var(--mono); }
code { background: var(--panel-2); padding: 1px 5px; border-radius: 4px; font: 12.5px var(--mono); color: var(--code-text); }
.shell { display: grid; grid-template-columns: 260px 1fr; min-height: 100vh; max-width: 1440px; margin: 0 auto; }
.shell.nav-hidden { grid-template-columns: 1fr; }
.shell.nav-hidden nav.side { display: none; }
.shell.nav-hidden main { padding-left: 62px; }
nav.side {
  border-right: 1px solid var(--line); padding: 26px 16px; display: flex; flex-direction: column;
  min-width: 0;
  position: sticky; top: 0; align-self: start; height: 100vh; overflow-y: auto;
  /* The nav is chrome, not content: reaching its end must not start
     scrolling the page underneath, and opening a nav group must not shift
     the items sideways as the bar appears -- hence the reserved gutter. */
  overscroll-behavior: contain; scrollbar-gutter: stable;
  /* At rest the nav's thumb is dimmer than the app default, so it does not
     compete with the nav items; pointing into the nav (or tabbing into it)
     brings it up to the house colour. It is never hidden outright -- it is
     the only signal that the list continues past the fold. */
  scrollbar-color: var(--scroll-thumb-idle) transparent;
}
nav.side:hover, nav.side:focus-within { scrollbar-color: var(--scroll-thumb) transparent; }
nav.side::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb-idle); background-clip: padding-box;
  transition: background-color .18s var(--ease-standard);
}
nav.side:hover::-webkit-scrollbar-thumb, nav.side:focus-within::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb); background-clip: padding-box;
}
nav.side::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }
.side-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 2px; }
.nav-toggle, .nav-reveal {
  background: transparent; color: var(--dim); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 2px 8px; line-height: 1.6; cursor: pointer; font-size: 12px;
}
.nav-toggle:hover, .nav-reveal:hover { color: var(--text); border-color: var(--accent); }
.nav-reveal { position: fixed; top: 18px; left: 14px; z-index: 20; background: var(--panel); padding: 5px 10px; }
/* The theme toggle rides beside the nav collapse, and keeps its own fixed
   position when the nav is hidden so it stays reachable there too. */
.side-head-btns { display: flex; align-items: center; gap: 6px; }
.theme-reveal { left: 62px; }
.theme-toggle, .theme-reveal { line-height: 1.5; }
.side-group {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  background: transparent; border: 0; padding: 0 8px; cursor: pointer; color: var(--dim);
}
.side-group .side-label { margin-bottom: 0; padding: 0; }
.side-group-chevron { font-size: 10px; transition: transform .15s; transform: rotate(-90deg); }
.side-group-chevron.open { transform: rotate(0deg); }
.brand {
  font-size: 15px; font-weight: 700; letter-spacing: .2em;
  background: linear-gradient(92deg, var(--brand-1), var(--brand-2) 60%, var(--brand-3));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.moon { width: 14px; height: 14px; fill: var(--amber); flex-shrink: 0; }
/* The brand mark doubles as a link home, so it opts out of the nav-item
   box the generic `nav.side a` rule would otherwise give it. Qualified with
   `nav.side` to outrank that rule rather than tie with it. */
nav.side a.brand-link {
  display: inline-flex; align-items: center; gap: 6px; padding: 0;
  border-left: 0; text-decoration: none;
}
nav.side a.brand-link:hover { background: transparent; }
nav.side a.brand-link:hover .moon { filter: brightness(1.3); }
.tag {
  display: block; color: var(--faint); font-size: 10.5px; letter-spacing: .12em;
  text-transform: uppercase; margin: 0 0 20px;
}
.side-label {
  display: block; color: var(--faint); font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .12em; padding: 0 8px; margin-bottom: 6px;
}
nav.side ol { list-style: none; padding: 0; margin: 22px 0 0; }
nav.side a {
  display: flex; align-items: center; gap: 8px; padding: 7px 9px; border-radius: 6px;
  color: var(--dim); text-decoration: none; font-size: 12px; border-left: 2px solid transparent;
}
nav.side a:hover { background: var(--panel); color: var(--text); }
nav.side a.active { background: var(--panel); color: var(--text); border-left-color: var(--accent-2); }
.side-sep { border-top: 1px solid var(--line); margin: 16px 0; }
main { padding: 34px 40px 90px; min-width: 0; }
h1 { font-size: 22px; letter-spacing: .04em; margin: 0 0 6px; }
/* Section heading, as on the docs pages; headings that label a card or a
   panel rather than a page section are overridden below. */
h2 {
  font-size: 15px; letter-spacing: .1em; text-transform: uppercase; color: var(--accent);
  margin: 46px 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
/* `.md-linear` is always main's first child, so a view that opens on a
   section heading is matched through it rather than by :first-child alone. */
main > h2:first-child, main > .md-linear + h2 { margin-top: 0; }
.panel > h2 {
  font-size: 12.5px; letter-spacing: .06em; color: var(--dim);
  margin: 0 0 10px; padding: 0; border: 0;
}
h3 { font-size: 13.5px; margin: 26px 0 10px; color: var(--text); }
p { color: var(--text-2); max-width: 78ch; }
p.lede { color: var(--dim); margin: 0 0 20px; max-width: 82ch; }
.dash-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  flex-wrap: wrap; margin: 0 0 22px;
}
.dash-header .pickerbar { margin: 0; }
.live { display: inline-flex; align-items: center; gap: 7px; color: var(--green); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; }
.dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.live .dot { animation: pulse 1.6s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes icon-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .live .dot, .live-dot { animation: none !important; }
}
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(168px, 100%), 1fr)); gap: 12px; margin: 22px 0 24px; }
.stat-card {
  border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px;
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
}
.stat-card .stat-value { font-size: 26px; font-weight: 700; letter-spacing: -.02em; line-height: 1.15; color: var(--text); }
.stat-card .stat-label {
  color: var(--faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .12em; margin: 2px 0 0;
}
.stat-card.ok .stat-value { color: var(--green); }
.stat-card.part .stat-value { color: var(--amber); }
.stat-card.no .stat-value { color: var(--red); }
.stat-card.accent .stat-value { color: var(--accent); }
.stat-card.halt .stat-value { color: var(--orange); }
.stat-card.stop .stat-value { color: var(--dim); }
.dash-grid-2 {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: 16px; align-items: start;
  margin: 0 0 26px;
}
.dash-grid-2 .panel { margin: 0; }
.items-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr)); align-items: stretch; gap: 12px; margin: 0 0 26px; }
.items-grid.stacked { grid-template-columns: 1fr; }
.item-card {
  display: flex; flex-direction: column; height: 100%; box-sizing: border-box;
  border: 1px solid var(--line); border-left: 2px solid var(--accent-2); border-radius: 10px; padding: 14px 16px;
  background: var(--panel); cursor: pointer; transition: border-color .15s, transform .15s;
}
.item-card:hover { border-color: var(--line-2); transform: translateX(2px); }
.item-card.active { border-color: var(--accent-2); background: var(--panel-2); }
.item-card .meta { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin: 0 0 8px; }
.item-card .title { margin: 0; font-weight: 600; }
.item-card .prog-row { display: flex; align-items: center; gap: 8px; margin: 8px 0 0; font-size: 11px; color: var(--dim); }
.item-card .prog-row .bar { flex: 1; margin-top: 0; }
.item-card .prog-row .pct { min-width: 30px; text-align: right; color: var(--text); font-variant-numeric: tabular-nums; }
/* pinned to the bottom so cards padded taller by a stretched grid row still line up */
.item-card .key { display: block; margin-top: auto; padding-top: 8px; color: var(--faint); font: 11px var(--mono); }
.item-card .key .guid { opacity: .6; }
.item-card .key .creator { opacity: .75; }
.dash-item { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.dash-item .item-card { flex: 1; }
.crumb {
  display: flex; align-items: center; gap: 6px; align-self: flex-start;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em; color: var(--dim);
}
.crumb-sep { color: var(--faint); }
.crumb-link { color: var(--accent); text-decoration: none; }
.crumb-link:hover { text-decoration: underline; }
select {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--line-2);
  border-radius: 6px; padding: 6px 8px; font: 11.5px var(--mono); max-width: 100%;
}
.pickerbar { display: flex; align-items: center; gap: 10px; margin: 0 0 20px; flex-wrap: wrap; }
.pickerbar span { color: var(--faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .12em; }
.pill {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px; border-radius: 999px;
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; border: 1px solid; white-space: nowrap;
}
.pill.ok { color: var(--green); border-color: var(--tint-ok-line); background: var(--tint-ok-bg); }
/* A pill that is also a link. Inherits its own colour so the ok/no tint
   still governs, unlike the default anchor colour. */
.pill.pr-link { text-decoration: none; }
.pill.pr-link:hover { filter: brightness(1.25); }
.pill.part { color: var(--amber); border-color: var(--tint-warn-line); background: var(--tint-warn-bg); }
.pill.no { color: var(--red); border-color: var(--tint-bad-line); background: var(--tint-bad-bg); }
.pill.run { color: var(--blue); border-color: var(--tint-run-line); background: var(--tint-run-bg); }
.pill.kind { color: var(--accent); border-color: var(--tint-accent-line); background: var(--tint-accent-bg); }
.pill.must { color: var(--red); border-color: var(--tint-bad-line); background: var(--tint-bad-bg); }
.pill.should { color: var(--amber); border-color: var(--tint-warn-line); background: var(--tint-warn-bg); }
.pill.could { color: var(--green); border-color: var(--tint-ok-line); background: var(--tint-ok-bg); }
.pill.agent { color: var(--cyan); border-color: var(--tint-info-line); background: var(--tint-info-bg); font-family: var(--mono); }
.pill.halt { color: var(--orange); border-color: var(--tint-halt-line); background: var(--tint-halt-bg); }
.pill.stop { color: var(--dim); border-color: var(--faint); background: var(--tint-stop-bg); }
.pill.dim { color: var(--dim); border-color: var(--line-2); background: var(--panel-2); }
/* icon riding alongside a pill's colour + text, so state is never colour-only */
.pill svg { width: 11px; height: 11px; flex: none; }

/* accessible utility: visually hidden but still announced by screen readers --
   used for table header cells whose column is icon-only (row disclosure toggles) */
.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;
}
.item-card .meta-left { display: flex; align-items: flex-start; gap: 8px; }
.item-card .select-box { margin-top: 3px; accent-color: var(--accent-2); width: 14px; height: 14px; cursor: pointer; }
.item-card .stop-btn {
  border: 1px solid var(--red); color: var(--red); background: transparent; border-radius: 6px;
  padding: 2px 9px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; cursor: pointer;
}
.item-card .stop-btn:hover { background: var(--tint-bad-bg); }
.batch-actions { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; flex-wrap: wrap; }
.batch-actions .hint { margin: 0; }
.panel {
  border: 1px solid var(--line); border-radius: 10px; padding: 16px 18px; background: var(--panel);
  margin: 16px 0;
}
.panel.warn { border-color: var(--tint-warn-line); background: var(--panel-warn-bg); }
.panel.win { border-color: var(--tint-ok-line); background: var(--panel-win-bg); }
.panel h4 { margin: 0 0 8px; font-size: 12.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--dim); }
.panel p:last-child { margin-bottom: 0; }
.note { border-left: 2px solid var(--line-2); padding: 2px 0 2px 12px; margin: 12px 0; color: var(--text-2); }
.quote { border-left: 2px solid var(--accent-2); padding: 4px 0 4px 14px; margin: 14px 0; color: var(--code-text); }
ul.tight { margin: 8px 0; padding-left: 18px; color: var(--text-2); }
ul.tight li { margin: 4px 0; }
.bar { height: 6px; background: var(--panel-2); border-radius: 3px; overflow: hidden; margin-top: 8px; }
.bar > i { display: block; height: 100%; background: linear-gradient(90deg, var(--accent-2), var(--cyan)); }

/* per-item / per-run phase pill strip -- state comes only from real
   RunState/artifact data (portal/services/items.py::_phase_state), never invented */
.phases { display: flex; flex-wrap: wrap; gap: 5px; }
.ph {
  font-size: 10px; letter-spacing: .05em; padding: 2px 8px; border-radius: 5px; text-transform: uppercase;
  border: 1px solid var(--line); color: var(--dim); background: var(--panel-2);
}
.ph.done { color: var(--green); border-color: var(--tint-ok-line); background: var(--tint-ok-bg); }
.ph.now {
  color: var(--on-accent); background: linear-gradient(90deg, var(--accent), var(--accent-2));
  border-color: transparent; font-weight: 700;
}
.ph.fail { color: var(--red); border-color: var(--tint-bad-line); background: var(--tint-bad-bg); }
.ph.na { color: var(--faint); border-style: dashed; opacity: .7; }

/* Phase-state icon, alongside the pill text -- shape carries the signal too,
   so a red/green colour-vision deficiency does not erase the state. Used by
   the rail segments and the console head; the gate-* variants stay for
   PhasePills and the feature board, which still speak that vocabulary. */
.status-icon { width: 16px; height: 16px; flex: none; color: var(--faint); }
.status-icon.gate-ok { color: var(--green); }
.status-icon.gate-no { color: var(--red); }
.status-icon.gate-part { color: var(--amber); }
.status-icon.gate-now { color: var(--accent); }
.status-icon.gate-now svg { animation: icon-spin 1.1s linear infinite; transform-origin: center; }
/* Spinner track: a fixed neutral ring, not currentColor at low opacity, so the
   moving arc has something to travel around at 16px (see ICON_SPIN, utils.js).
   --faint, not the --line-2 the mockup used: line-2 is a *border* token and
   lands at 1.5:1 on --panel, i.e. the same invisible ring the .25-opacity
   accent gave. --faint is this sheet's recessive-icon ink -- it is already
   .status-icon's own resting colour, and what the pending phase's dashed ring
   draws in -- so the track sits at the same weight as its sibling icons. */
.status-icon .spin-track { stroke: var(--faint); }
/* Small pulsing indicator for "this is the active one right now" -- reused
   verbatim (same class, same keyframe) between the timeline's current phase
   and the live run panel's latest transcript group, so both surfaces say
   "in progress" the same way. */
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; animation: pulse 1.6s ease-in-out infinite; }
pre.artifact {
  white-space: pre-wrap; word-break: break-word; font: 12px/1.6 var(--mono); background: var(--sunken);
  border: 1px solid var(--line); border-radius: 8px; padding: 14px 16px; margin: 10px 0 0;
  max-height: 340px; overflow: auto; color: var(--text-2);
}
/* formatted markdown view of agent prompts/outputs and artifacts
   (components/MarkdownBlock.js) -- same frame as pre.artifact, but rendered.
   The "raw" toggle swaps back to the untouched text, because what the next
   phase actually read has to stay inspectable byte for byte (ADR-0001). */
.md-block {
  position: relative; background: var(--sunken); border: 1px solid var(--line); border-radius: 8px;
  padding: 14px 16px; margin: 10px 0 0; max-height: 340px; overflow: auto;
}
/* `flat`: drop the frame and, crucially, the scroll box -- whoever sets it
   owns the frame instead. PeekBlock clamps rather than scrolls, and the side
   drawer is full height, so in both cases the 340px `overflow: auto` above
   would put a scroll region inside a scroll region for no reason. */
.md-block.md-flat {
  background: none; border: 0; border-radius: 0; padding: 0; margin: 0;
  max-height: none; overflow: visible;
}
.md-block pre.artifact.md-raw { border: 0; padding: 0; margin: 0; max-height: none; background: transparent; }
.md-raw-toggle {
  position: sticky; top: 0; float: right; z-index: 2; margin: -4px -6px 6px 10px;
  background: var(--panel); color: var(--dim); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 1px 8px; font-size: 10.5px; letter-spacing: .04em; cursor: pointer;
}
.md-raw-toggle:hover { color: var(--text); border-color: var(--accent); }
.md-body { font: 12px/1.7 var(--mono); color: var(--text-2); word-break: break-word; }
.md-body > :first-child { margin-top: 0; }
.md-body > :last-child { margin-bottom: 0; }
.md-body p { margin: 8px 0; }
.md-body h2, .md-body h3, .md-body h4, .md-body h5, .md-body h6 {
  margin: 14px 0 6px; color: var(--text); font-weight: 700; letter-spacing: .05em;
}
.md-body h2 { font-size: 12.5px; text-transform: uppercase; color: var(--accent); }
.md-body h3 { font-size: 12px; text-transform: uppercase; }
.md-body h4, .md-body h5, .md-body h6 { font-size: 12px; }
.md-body ul, .md-body ol { margin: 8px 0; padding-left: 20px; }
.md-body li { margin: 3px 0; }
.md-body hr { border: 0; border-top: 1px solid var(--line-2); margin: 12px 0; }
.md-body blockquote {
  border-left: 2px solid var(--accent-2); margin: 8px 0; padding: 2px 0 2px 12px; color: var(--code-text);
}
.md-body pre.md-code {
  white-space: pre-wrap; word-break: break-word; font: 11.5px/1.6 var(--mono);
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px;
  padding: 10px 12px; margin: 8px 0; overflow: auto;
}
.md-body table { border-collapse: collapse; margin: 8px 0; font-size: 11.5px; }
.md-body th {
  text-align: left; color: var(--faint); font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; font-size: 10px; padding: 4px 10px; border-bottom: 1px solid var(--line-2);
}
.md-body td { padding: 4px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.md-body tr:last-child td { border-bottom: none; }
.md-body a { color: var(--cyan); }
/* Frontmatter as a labelled spec strip, not a row of identical pills --
   every field keeps its own always-visible label (was packed into the pill
   text, e.g. "PIPELINE: FULL"), and metaPillClass() (MarkdownBlock.js) gives
   known enum fields like risk/priority their own semantic colour instead of
   every field defaulting to the same purple "kind" pill. */
.meta-strip { display: flex; flex-wrap: wrap; gap: 10px 18px; margin: 0 0 10px; }
.meta-item { display: flex; flex-direction: column; gap: 3px; }
.meta-label { color: var(--faint); font-size: 9.5px; text-transform: uppercase; letter-spacing: .1em; }
.md-artifact { border: 1px solid var(--line-2); border-radius: 8px; padding: 10px 12px; margin: 10px 0; }
.md-artifact-label {
  margin: 0 0 8px; font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--cyan);
}
.md-tools { position: sticky; top: 0; float: right; z-index: 2; display: flex; gap: 6px; margin: -4px -6px 6px 10px; }
.md-tools .md-raw-toggle { position: static; float: none; margin: 0; }

/* the one big side drawer (components/SidePanel.js) -- a full-height reading
   pane for a prompt/output/artifact, over the page like Claude's side panel */
.side-panel-backdrop {
  position: fixed; inset: 0; background: var(--scrim); z-index: 40;
  animation: panel-fade .18s var(--ease-standard);
}
.side-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(760px, 78vw); z-index: 41;
  background: var(--panel); border-left: 1px solid var(--line-2);
  box-shadow: -24px 0 60px var(--shadow-color);
  display: flex; flex-direction: column;
  transform: translateX(102%); transition: transform .22s var(--ease-emph-decel);
  visibility: hidden;
}
.side-panel.open { transform: translateX(0); visibility: visible; }
.side-panel-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 18px;
  border-bottom: 1px solid var(--line); flex: none;
}
.side-panel-title {
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.side-panel-close {
  margin-left: auto; background: transparent; color: var(--dim); border: 1px solid var(--line-2);
  border-radius: 6px; padding: 0 9px; font-size: 16px; line-height: 1.5; cursor: pointer;
}
.side-panel-close:hover { color: var(--text); border-color: var(--accent); }
.side-panel-body { flex: 1; overflow-y: auto; padding: 8px 18px 18px; }
.side-panel-body .md-block { max-height: none; margin: 0; border: 0; background: transparent; padding: 4px 0 0; overflow: visible; }
.side-panel-body .md-body { font-size: 12.5px; }
@keyframes panel-fade { from { opacity: 0; } to { opacity: 1; } }
table.diag-table { width: 100%; border-collapse: collapse; font-size: 11.5px; margin: 0; }
table.diag-table th {
  position: sticky; top: 0; z-index: 1;
  text-align: left; color: var(--faint); font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; font-size: 10px; padding: 4px 8px; background: var(--panel);
  border-bottom: 1px solid var(--line);
}
table.diag-table td { padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
table.diag-table tr:last-child td { border-bottom: none; }
table.diag-table td.diag-agent { color: var(--dim); font-family: var(--mono); white-space: nowrap; }
table.diag-table td.diag-when { color: var(--dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
table.diag-table .pill { margin: 0 4px 4px 0; }
table.diag-table tr.diag-row { cursor: pointer; }
table.diag-table tr.diag-row:hover td { background: var(--panel-2); }
/* reason/shadow-reasons live here instead of as their own columns -- shown
   only for the row the user clicked open */
tr.diag-detail-row td.diag-detail { background: var(--sunken); padding: 8px 10px 10px; }
.diag-detail-agent { font-family: var(--mono); color: var(--dim); margin-right: 10px; }
/* Where the phase's duration went: calls, agent time, judge time and share. */
.diag-detail-calls { font-family: var(--mono); color: var(--dim); margin-right: 10px; }
.diag-detail-reason { display: block; color: var(--dim); margin: 4px 0; }
/* Explicit disclosure button per row -- the row's own onclick (kept, for
   mouse users) is mouse-only, so this is the real keyboard/screen-reader
   affordance: reachable by Tab, announced via aria-expanded/aria-controls. */
td.diag-toggle-cell { width: 28px; padding-left: 10px; padding-right: 0; }
button.row-toggle {
  background: transparent; border: 1px solid var(--line-2); color: var(--dim); border-radius: 5px;
  width: 20px; height: 20px; display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
button.row-toggle:hover { color: var(--text); border-color: var(--accent); }
button.row-toggle svg { width: 9px; height: 9px; transition: transform .15s; }
button.row-toggle[aria-expanded="true"] svg { transform: rotate(90deg); }
.diag-panel-head {
  display: flex; align-items: center; justify-content: space-between; cursor: pointer; user-select: none;
  /* diag-panel-head is a real <button> now (was a <div @click>). */
  width: 100%; background: none; border: none; color: inherit; font: inherit; padding: 0; text-align: left;
}
.diag-panel-head h2 { margin: 0; }
.diag-panel-head .chev { margin-left: 12px; }
/* bounded + sticky header so a full-pipeline diagnostics table scrolls
   in place instead of pushing the rest of the item page down */
.diag-table-wrap {
  overflow: auto; max-height: 320px; margin: 0 0 10px;
  border: 1px solid var(--line); border-radius: 8px;
  /* scrollbar styling used to be repeated here; it is the app-wide default now */
}
p.live-status { font-weight: 600; color: var(--accent); }
form.addform {
  display: flex; flex-direction: column; gap: 12px; max-width: 460px; margin: 0 0 20px;
  padding: 18px 20px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
}
form.addform .field { display: flex; flex-direction: column; gap: 6px; }
form.addform .field > span:first-child {
  color: var(--dim); font-size: 11.5px; text-transform: uppercase; letter-spacing: .08em;
}
form.addform input, form.addform textarea {
  background: var(--panel); color: var(--text); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 8px 10px; font: 13px var(--mono);
}
form.addform textarea { min-height: 70px; resize: vertical; }
/* Selects were never styled here, so they rendered as raw OS controls in
   every .addform that has one (Users, and now Workers). */
form.addform select {
  background: var(--panel); color: var(--text); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 8px 10px; font: 13px var(--mono);
}
/* The filter bar is a wide wrapping row, not .addform's narrow column: seven
   controls stacked vertically would push the table off the first screen. */
form.addform.worker-filters {
  flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px;
  max-width: none; padding: 12px 14px;
}
form.addform.worker-filters input[type="date"] { font: 12px var(--mono); }
form.addform.worker-filters .hint {
  display: flex; align-items: center; gap: 6px; margin: 0;
}
/* 9 columns will not fit a narrow viewport; scroll the table, never the page. */
.worker-table-wrap { overflow-x: auto; min-width: 0; }
form.addform button, form.importform button, .run-panel button {
  align-self: flex-start; background: var(--accent); color: var(--on-accent); border: none; border-radius: 6px;
  padding: 7px 16px; font-weight: 600; cursor: pointer;
}
form.addform button:disabled, form.importform button:disabled, .run-panel button:disabled {
  opacity: .5; cursor: not-allowed;
}
form.importform { display: flex; flex-direction: column; gap: 8px; max-width: 640px; margin: 0; }
form.importform textarea {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 8px 10px; font: 12px var(--mono); min-height: 120px; resize: vertical;
}
.hint { color: var(--dim); font-size: 11.5px; margin: -2px 0 0; }
.importresult { font-size: 12.5px; color: var(--dim); }
/* `pre-wrap` because a 500's message is now the exception plus its traceback
   (`portal.server._crash_body`); without it every frame collapses onto one
   line. `overflow-x` keeps a long path from widening the panel it sits in. */
.err { color: var(--red); font-size: 12.5px; white-space: pre-wrap;
       overflow-wrap: anywhere; overflow-x: auto; max-height: 320px; overflow-y: auto; }
.storysearch {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 6px 8px; font: 12px var(--mono); min-width: 220px;
}
.storycard {
  border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; margin-bottom: 8px; background: var(--panel);
  transition: border-color .15s, background .15s;
}
.storycard.sel { border-color: var(--accent-2); background: var(--tint-accent-bg); }
.storycard-head { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.storycard-head .title { flex: 1; font-weight: 600; }
.storycard-head input[type=checkbox] { accent-color: var(--accent-2); width: 15px; height: 15px; cursor: pointer; }
.storycard .storysentence { margin: 8px 0 0; font-style: italic; color: var(--text); }
.storycard .hint { margin-top: 6px; }
ol.criteria { margin: 8px 0 0; padding-left: 20px; color: var(--dim); font-size: 12.5px; }
ol.criteria li { margin-bottom: 3px; }
.run-panel { border-color: var(--line-2); }
.run-panel .hint.warn { color: var(--amber); }
/* Item-detail header's own pipeline-overview strip, same chips ItemCard
   already shows -- a quick "where in the pipeline is this" read that doesn't
   require scrolling down to the full timeline below. */
.item-head-phases { margin: 10px 0 2px; }
.run-cta { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin: 0 0 10px; }
.run-cta-info { display: flex; flex-direction: column; gap: 2px; }
.run-cta-label { color: var(--faint); font-size: 10px; text-transform: uppercase; letter-spacing: .1em; }
.run-cta-phase { font-size: 14px; font-weight: 700; color: var(--text); }
/* Stopping a real, running agent is irreversible, so the ghost Stop button
   only arms this inline confirmation rather than calling the API directly. */
.stop-confirm { display: flex; align-items: center; gap: 8px; margin: 6px 0 0; flex-wrap: wrap; }
button.ghost.danger { color: var(--red); border-color: var(--tint-bad-line); }
button.ghost.danger:hover { background: var(--tint-bad-bg); border-color: var(--red); }
.linklike { background: none; border: none; color: var(--accent); font-size: 11px; cursor: pointer; padding: 0; }
.linklike:hover { text-decoration: underline; }
.run-confirm { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--dim); margin: 8px 0; cursor: pointer; }
.storycount { color: var(--faint); font-size: 11.5px; }
.empty { color: var(--faint); font-style: italic; padding: 20px 0; }
.empty-state {
  border: 1px dashed var(--line-2); border-radius: 10px; padding: 30px 20px; margin: 4px 0 20px;
  text-align: center; background: var(--panel);
}
.empty-state p { margin: 0; max-width: none; color: var(--dim); }
.empty-state p + p { margin-top: 4px; }
.empty-state-title { color: var(--text); font-weight: 600; font-size: 13.5px; }
.foot {
  margin-top: 46px; color: var(--faint); font-size: 11.5px;
  border-top: 1px solid var(--line); padding-top: 14px;
}
.foot code { font: 11px var(--mono); }

.agents-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 12px; margin: 0 0 26px; }
.agent-card {
  border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px;
  background: var(--panel); transition: border-color .15s;
}
.agent-card:hover { border-color: var(--line-2); }
.agent-card .title { margin: 0 0 6px; font-weight: 600; font: 13px var(--mono); }
.agent-meta { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }

/* Narrow viewports (including the ~440px embedded VS Code browser panel):
   the sidebar becomes a horizontal topbar instead of squeezing `main` below
   its content's min-content width, which is what caused the whole page to
   overflow sideways rather than the card grids simply wrapping to 1 column. */
@media (max-width: 760px) {
  .shell { grid-template-columns: 1fr; }
  .shell.nav-hidden { grid-template-columns: 1fr; }
  .shell.nav-hidden main { padding-left: 16px; padding-top: 56px; }
  nav.side {
    border-right: none; border-bottom: 1px solid var(--line);
    flex-direction: row; align-items: center; flex-wrap: wrap; gap: 10px 18px; padding: 14px 16px;
    position: static; height: auto; overflow: visible;
  }
  .side-head { width: 100%; margin-bottom: 0; }
  nav.side ol { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
  .side-group { width: auto; }
  .side-sep { display: none; }
  main { padding: 18px 16px; }
  /* phase-meta is the newest addition to this row and the first thing tight
     enough to justify letting it wrap -- chev still ends up at the right of
     whichever line it lands on, since margin-left:auto works per flex line. */
}

.checklist { gap: 6px; }
.checklist-actions { display: flex; gap: 8px; }
button.ghost {
  align-self: flex-start; background: none; color: var(--dim); border: 1px solid var(--line-2);
  border-radius: 6px; padding: 7px 16px; cursor: pointer; font: 11.5px var(--mono);
}
button.ghost:hover { color: var(--text); border-color: var(--accent-2); }
.new-ws-link {
  display: inline-flex; align-items: center; gap: 6px; padding: 9px 16px; margin: 0 0 20px;
  color: var(--accent); text-decoration: none; font-size: 12.5px; font-weight: 600;
  background: var(--panel); border: 1px dashed var(--line-2); border-radius: 8px; cursor: pointer; text-align: left;
}
.new-ws-link:hover { color: var(--text); border-color: var(--accent-2); background: var(--panel-2); }

.ws-block { margin-bottom: 18px; }
.ws-block-header {
  display: flex; align-items: baseline; gap: 10px;
  margin: 46px 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
.panel > .ws-block-header { margin-top: 0; }
.ws-block-header h2 { margin: 0; padding: 0; border: 0; }
.ws-features-tree { list-style: none; margin: 14px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.ws-feature-row {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--panel); cursor: pointer;
}
.ws-feature-row:hover { border-color: var(--line-2); background: var(--panel-2); }
.ws-feature-row a { color: var(--text); text-decoration: none; flex: 1; }
.ws-feature-row a:hover { text-decoration: underline; }
.feature-row-label { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.disclosure { color: var(--dim); width: 12px; text-align: center; }

/* Features page rows: name + workspace chip on top, status rollup + repo
   below -- every field links to its own page (mockup/features-page-workspace.html). */
.feature-row { padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); }
.feature-row:hover { border-color: var(--line-2); background: var(--panel-2); }
.feature-row-top { display: flex; align-items: center; gap: 8px 10px; flex-wrap: wrap; }
.feature-row-sub { display: flex; align-items: center; gap: 10px; margin-top: 5px; flex-wrap: wrap; }
.row-spacer { flex: 1; }
.feature-name { color: var(--text); font-size: 13px; text-decoration: none; overflow-wrap: anywhere; flex: none; max-width: 100%; }
.feature-name:hover { color: var(--accent); text-decoration: underline; }
.ws-chip {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font-size: 11px; padding: 1.5px 10px; border-radius: 20px; text-decoration: none;
  background: var(--accent-soft); border: 1px solid var(--accent-soft-line); color: var(--accent-soft-text);
}
.ws-chip:hover { border-color: var(--accent-2); }
.ws-chip .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.ws-chip.unassigned { background: var(--panel-2); border-color: var(--line-2); color: var(--dim); }
.ws-chip.unassigned .dot { background: var(--faint); }
.stat-pills { display: inline-flex; gap: 5px; flex-wrap: wrap; }
.stat-pill {
  display: inline-flex; align-items: center; gap: 5px; text-decoration: none;
  font-size: 10.5px; padding: 1px 8px; border-radius: 20px;
  background: var(--panel-2); border: 1px solid var(--line-2); color: var(--dim);
}
a.stat-pill:hover { border-color: var(--faint); color: var(--text); }
.stat-pill i { font-style: normal; width: 7px; height: 7px; border-radius: 50%; display: inline-block; background: var(--faint); }
.stat-pill.st-done { color: var(--green-soft); }    .stat-pill.st-done i { background: var(--green); }
.stat-pill.st-running { color: var(--cyan-soft); } .stat-pill.st-running i { background: var(--cyan); }
.stat-pill.st-queued { color: var(--blue-soft); }  .stat-pill.st-queued i { background: var(--blue); }
.stat-pill.st-blocked { color: var(--amber-soft); } .stat-pill.st-blocked i { background: var(--amber); }
.stat-pill.st-failed { color: var(--red-soft); }  .stat-pill.st-failed i { background: var(--red); }
.stat-pill.st-interrupted { color: var(--orange-soft); } .stat-pill.st-interrupted i { background: var(--orange); }
.stat-pill.st-stopped, .stat-pill.st-none { color: var(--dim); }
.feature-repo {
  color: var(--faint); font-size: 11px; text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46%;
}
.feature-repo:hover { color: var(--blue); text-decoration: underline; }
.ws-items-tree { list-style: none; margin: 6px 0 0; padding: 0 0 0 30px; display: flex; flex-direction: column; gap: 4px; }
.ws-items-tree a {
  display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 6px;
  color: var(--text); text-decoration: none;
}
.ws-items-tree a:hover { background: var(--panel-2); }

.back-link {
  display: inline-block; margin: 0 0 14px; color: var(--dim); text-decoration: none; font-size: 12.5px;
}
.back-link:hover { color: var(--text); text-decoration: underline; }

.ws-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: 12px; }
.ws-card {
  display: block; border: 1px solid var(--line); border-radius: 10px; padding: 16px 18px; background: var(--panel);
  text-decoration: none; color: var(--text); transition: border-color .15s;
}
.ws-card:hover { border-color: var(--accent-2); }
.ws-card-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.ws-card-header h2 {
  font-size: 15px; letter-spacing: .02em; text-transform: none; color: var(--text);
  margin: 0; padding: 0; border: 0;
}
.ws-card .lede { margin: 6px 0 12px; }
.ws-card .stats-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(84px, 100%), 1fr)); gap: 8px; margin: 0;
}
.ws-card .stat-card { padding: 10px 12px; }
.ws-card .stat-value { font-size: 19px; }

.view-toggle { display: inline-flex; border: 1px solid var(--line-2); border-radius: 8px; overflow: hidden; }
.view-toggle button {
  background: transparent; color: var(--dim); border: none; padding: 6px 14px; cursor: pointer;
  font: 11px var(--mono); text-transform: uppercase; letter-spacing: .08em;
}
.view-toggle button + button { border-left: 1px solid var(--line-2); }
.view-toggle button:hover { color: var(--text); background: var(--panel-2); }
.view-toggle button.on { color: var(--accent); background: var(--panel-2); }

.ws-table { width: 100%; border-collapse: collapse; font-size: 12.5px; margin: 14px 0; }
.ws-table th {
  text-align: right; color: var(--faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em;
  font-weight: 500; padding: 7px 10px; border-bottom: 1px solid var(--line-2);
}
.ws-table th:first-child, .ws-table td:first-child { text-align: left; }
.ws-table td { text-align: right; padding: 7px 10px; border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
.ws-table tr:hover td { background: var(--row-hover); }
.ws-table td a { color: var(--text); text-decoration: none; font-weight: 600; }
.ws-table td a:hover { color: var(--accent); text-decoration: underline; }
.ws-table-desc { display: block; color: var(--dim); font-size: 11.5px; }
.ws-table td.ok { color: var(--green); }
.ws-table td.part { color: var(--amber); }
.ws-table td.no { color: var(--red); }

.repo-row {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--panel);
}
.repo-row:hover { border-color: var(--line-2); }
.repo-row-main { flex: 1; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.repo-name { font-weight: 600; }
.repo-location { color: var(--dim); word-break: break-all; }
.repo-row-main .hint { flex-basis: 100%; margin: 0; }

form.addform select {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 8px 10px; font: 13px var(--mono);
}

.side-spacer { flex: 1; }
.side-account { position: relative; border-bottom: 1px solid var(--line); padding-bottom: 12px; margin: 10px 0 12px; }
.side-account-info { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.side-account-name { font: 12.5px var(--mono); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.side-account-logout { width: 100%; text-align: center; margin-top: 6px; }
.side-account-switch { background: none; border: none; padding: 0; cursor: pointer; }
.side-account-switch:hover { color: var(--accent); }
.side-account-caret { color: var(--dim); font-size: 10px; }
.user-switch-menu {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 30; margin-top: 6px;
  display: flex; flex-direction: column; gap: 2px; padding: 4px;
  border: 1px solid var(--line-2); border-radius: 6px; background: var(--panel-2);
  max-height: 220px; overflow-y: auto; box-shadow: 0 10px 24px var(--shadow-color);
}
.user-switch-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: none; border: none; color: var(--text); font: 12.5px var(--mono);
  padding: 6px 8px; border-radius: 4px; cursor: pointer; text-align: left;
}
.user-switch-item:hover:not(:disabled) { background: var(--panel); color: var(--accent); }
.user-switch-item:disabled { opacity: .5; cursor: default; }
/* In the mobile topbar the account block is one flex item in the row, so the
   full-width divider from the sidebar layout doesn't apply. Must come after the
   base .side-account rules above -- same specificity, so source order decides. */
@media (max-width: 760px) {
  .side-account { border-bottom: none; padding-bottom: 0; margin: 0; }
  .side-account-logout { width: auto; margin-top: 0; }
}

.impersonation-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 0 0 18px; padding: 8px 14px; border: 1px solid var(--tint-warn-line); border-radius: 6px;
  background: var(--tint-warn-bg); color: var(--amber); font-size: 12.5px;
}

.login-shell {
  min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px;
}
.login-card {
  width: 100%; max-width: 380px; border: 1px solid var(--line); border-radius: 12px; padding: 32px 28px;
  background: var(--panel);
}
.login-brand { display: flex; align-items: baseline; gap: 8px; margin-bottom: 22px; }
.login-title { font-size: 19px; margin: 0 0 6px; }
.login-card .lede { margin-bottom: 22px; }
.login-form { display: flex; flex-direction: column; gap: 14px; }
.login-label { display: flex; flex-direction: column; gap: 6px; font-size: 12.5px; color: var(--dim); }
.login-label input {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--line-2); border-radius: 6px;
  padding: 9px 11px; font: 13.5px var(--mono);
}
.login-label input:focus { outline: none; border-color: var(--accent-2); }
.login-submit {
  background: linear-gradient(90deg, var(--accent), var(--accent-2)); color: var(--on-accent); border: none;
  border-radius: 6px; padding: 10px 16px; font-weight: 700; cursor: pointer; margin-top: 4px;
}
.login-submit:disabled { opacity: .6; cursor: not-allowed; }

table.datatable { width: 100%; border-collapse: collapse; margin: 0.5rem 0 1.5rem; }
table.datatable th, table.datatable td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--line); }
table.datatable td .status.healthy, table.datatable td .status.done { color: var(--green); }
table.datatable td .status.at-risk, table.datatable td .status.queued { color: var(--amber); }
table.datatable td .status.stale, table.datatable td .status.failed { color: var(--red); }
table.datatable td .status.running, table.datatable td .status.leased { color: var(--blue); }
table.datatable td .status.blocked { color: var(--red); }
table.datatable td .status.idle, table.datatable td .status.stopped { color: var(--dim); }
/* The per-item rollup column: "2 done · 1 failed" as separately coloured
   segments, kept on one line so a busy queue table still scans. */
table.datatable td.item-status-cell { white-space: nowrap; }
table.datatable td.item-status-cell .status + .status { margin-left: 0.6em; }

.scope-toggle { display: flex; gap: 0.25rem; }
.scope-toggle button { padding: 0.25rem 0.75rem; border: 1px solid var(--line); background: transparent; color: var(--dim); border-radius: 4px; cursor: pointer; }
.scope-toggle button.active { color: var(--text); border-color: var(--accent-2); }

/* ====================================================================
   Material Design loading layer
   Rendered by components/ProgressBar.js, components/Spinner.js and
   components/Skeleton.js, driven by mixins/loadable.js. The reference
   mockup is mockup/dashboard-loading.html.
   ==================================================================== */

/* --- Linear progress indicator (M3 indeterminate) -------------------
   One per page, App.js's first child inside <main>. Signals a load of a
   view that is already on screen -- a refresh, not a first paint. */
.md-linear {
  position: sticky; top: 0; z-index: 5;
  height: 4px; margin: 0 0 22px; overflow: hidden;
  background: var(--md-track);
  opacity: 0; transition: opacity .2s var(--ease-standard);
}
.md-linear[data-active="true"] { opacity: 1; }
.md-linear .md-bar {
  position: absolute; inset: 0 auto 0 0; width: 100%; height: 100%;
  transform-origin: left center; background: var(--md-indicator); border-radius: 2px;
  animation-play-state: paused;
}
.md-linear[data-active="true"] .md-bar { animation-play-state: running; }
.md-linear .md-bar-primary { animation: md-primary-translate 2s infinite linear; }
.md-linear .md-bar > span {
  display: block; height: 100%; width: 100%; transform-origin: left center;
  background: inherit; border-radius: 2px; animation-play-state: inherit;
}
.md-linear .md-bar-primary > span { animation: md-primary-scale 2s infinite linear; }
.md-linear .md-bar-secondary { animation: md-secondary-translate 2s infinite linear; }
.md-linear .md-bar-secondary > span { animation: md-secondary-scale 2s infinite linear; }
@keyframes md-primary-translate {
  0%     { transform: translateX(0); }
  20%    { animation-timing-function: cubic-bezier(.5,0,.701732,.495819); transform: translateX(0); }
  59.15% { animation-timing-function: cubic-bezier(.302435,.381352,.55,.956352); transform: translateX(83.67142%); }
  100%   { transform: translateX(200.611057%); }
}
@keyframes md-primary-scale {
  0%     { transform: scaleX(.08); }
  36.65% { animation-timing-function: cubic-bezier(.334731,.12482,.785844,1); transform: scaleX(.08); }
  69.15% { animation-timing-function: cubic-bezier(.06,.11,.6,1); transform: scaleX(.661479); }
  100%   { transform: scaleX(.08); }
}
@keyframes md-secondary-translate {
  0%     { animation-timing-function: cubic-bezier(.15,0,.515058,.409685); transform: translateX(0); }
  25%    { animation-timing-function: cubic-bezier(.31033,.284058,.8,.733712); transform: translateX(37.651913%); }
  48.35% { animation-timing-function: cubic-bezier(.4,.627035,.6,.902026); transform: translateX(84.386165%); }
  100%   { transform: translateX(160.277782%); }
}
@keyframes md-secondary-scale {
  0%     { animation-timing-function: cubic-bezier(.205028,.057051,.57661,.453971); transform: scaleX(.08); }
  19.15% { animation-timing-function: cubic-bezier(.152313,.196432,.648374,1.004315); transform: scaleX(.457104); }
  44.15% { animation-timing-function: cubic-bezier(.257759,.228483,.351762,1); transform: scaleX(.72796); }
  100%   { transform: scaleX(.08); }
}

/* Content already on screen is never blanked back to placeholders while it
   refreshes -- it dims and goes inert. Applied per child rather than to
   `main` so the indicator itself stays at full strength. */
main > * { transition: opacity .2s var(--ease-standard); }
main.is-busy > *:not(.md-linear) { opacity: .62; pointer-events: none; }

/* --- Circular progress indicator (M3 indeterminate) -----------------
   For a control that is itself busy, or a section too small to skeleton.
   Never for a whole page. */
.md-circular { width: 16px; height: 16px; display: inline-block; flex: none; animation: md-circ-rotate 1.4s linear infinite; }
.md-circular.lg { width: 22px; height: 22px; }
.md-circular circle {
  fill: none; stroke: var(--md-indicator); stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 80px, 200px; stroke-dashoffset: 0;
  animation: md-circ-dash 1.4s var(--ease-standard) infinite;
}
/* Inside a filled button (dark ink on the accent fill) the indicator has to
   follow the label's colour, not the accent it sits on. */
.md-circular.on-accent circle { stroke: currentColor; }
@keyframes md-circ-rotate { to { transform: rotate(360deg); } }
@keyframes md-circ-dash {
  0%   { stroke-dasharray: 1px, 200px; stroke-dashoffset: 0; }
  50%  { stroke-dasharray: 100px, 200px; stroke-dashoffset: -15px; }
  100% { stroke-dasharray: 100px, 200px; stroke-dashoffset: -125px; }
}
/* Buttons keep their box when a spinner appears next to the label. */
button.ghost, form.addform button, form.importform button, .run-panel button, .login-submit {
  display: inline-flex; align-items: center; gap: 8px;
}
/* A section heading owns the indicator for its own list. */
h2 > .md-circular, .ws-block-header > .md-circular { margin-left: 10px; vertical-align: middle; }
/* Full-width button: the spinner joins the label rather than pinning left. */
.login-submit { justify-content: center; }

/* --- Skeleton placeholders ------------------------------------------
   First paint only. Each block occupies the real element's box, so the
   swap to data moves nothing. */
.skel { position: relative; overflow: hidden; background: var(--md-skel); border-radius: 4px; }
.skel::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--md-skel-hi) 55%, transparent);
  animation: md-shimmer 1.6s var(--ease-standard) infinite;
}
@keyframes md-shimmer { 100% { transform: translateX(100%); } }
.skel-line { height: 11px; width: 100%; }
.skel-line.sm { height: 9px; }
.skel-pill { height: 19px; width: 74px; border-radius: 999px; }
.skel-chip { height: 23px; width: 62px; border-radius: 5px; }
.skel-num { height: 30px; width: 52px; border-radius: 6px; }
.skel-bar { height: 6px; flex: 1; border-radius: 3px; }
/* A placeholder stands in for a *line box*, not just the ink inside it.
   `.skel-text` is that line box, measured off the real element; the bar
   inside is the ink. Without it a skeleton card comes out ~26px short of
   the real one and the swap shifts the page. */
.skel-text { display: flex; align-items: center; }
.skel-text.t-h1 { height: 36px; }         /* h1, 22px/1.65 */
.skel-text.t-h2 { height: 25px; }         /* h2, 15px/1.65 */
.skel-text.t-lede { height: 22px; }       /* p.lede, 13.5px/1.65 */
.skel-text.t-crumb { height: 17px; }      /* .crumb, 10.5px/1.65 */
.skel-text.t-title { height: 23px; }      /* .item-card .title, 13.5px/1.65 */
.skel-text.t-hint { height: 18px; }       /* .hint / .pct, 11px/1.65 */
.skel-text.t-key { height: 13px; }        /* .key -- `font:` shorthand resets line-height */
.skel-text.t-label { height: 19px; margin-top: 2px; }  /* .stat-label + its margin */
.skel-text.t-cell { height: 19px; }       /* .datatable td, 13.5px/1.4 */
/* Skeleton cards keep the real card's frame -- only the contents are
   placeholders, because the frame is already truthful. */
.stat-card.is-skel { background: var(--panel); }
.item-card.is-skel, .ws-card.is-skel, .agent-card.is-skel { cursor: default; }
.item-card.is-skel { border-left-color: var(--line-2); }
.skel-page-head { margin: 0 0 22px; }
.skel-section-head { margin: 46px 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
main > .md-linear + .skel-section-head { margin-top: 0; }

/* --- Reveal: M3 fade-through, staggered ----------------------------- */
.reveal { animation: md-fade-through .35s var(--ease-emph-decel) both; }
.reveal-2 { animation-delay: .05s; }
.reveal-3 { animation-delay: .1s; }
.reveal-4 { animation-delay: .15s; }
@keyframes md-fade-through { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .skel::after, .md-circular, .md-circular circle,
  .md-linear .md-bar, .md-linear .md-bar > span { animation: none; }
  .skel::after { opacity: .35; transform: none; }
  .md-linear .md-bar-primary { width: 40%; }
  .md-linear .md-bar-secondary { display: none; }
  .reveal { animation: none; }
  .live-dot { animation: none; }
}


/* ============ feature page redesign: tabs, isolation, order, filters ============
   (mockup/feature-page-redesign.html) */

.page-tabs { display: flex; gap: 4px; margin: 18px 0 0; border-bottom: 1px solid var(--line); }
.page-tabs button {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  font: 12px var(--mono); color: var(--dim); padding: 9px 16px 10px;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.page-tabs button:hover { color: var(--text); }
.page-tabs button.on { color: var(--accent); border-bottom-color: var(--accent-2); }
.page-tabs .count {
  display: inline-block; margin-left: 6px; font-size: 10px; min-width: 18px;
  padding: 0 5px; border-radius: 10px; background: var(--panel-2);
  border: 1px solid var(--line-2); color: var(--dim);
}
.page-tabs button.on .count { color: var(--accent); border-color: var(--accent-2); }

/* segmented isolation control */
.seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: 7px; overflow: hidden; }
.seg button {
  appearance: none; border: 0; background: transparent; color: var(--dim);
  font: 11px var(--mono); padding: 4px 10px; cursor: pointer; border-right: 1px solid var(--line);
}
.seg button:last-child { border-right: 0; }
.seg button:hover:not(:disabled) { color: var(--text); }
.seg button:disabled { cursor: not-allowed; opacity: .55; }
.seg button.on.wt { background: var(--accent-soft); color: var(--accent-soft-text); }
.seg button.on.ip { background: var(--seg-warn-bg); color: var(--amber); }
.seg button.on.inherit { background: var(--panel-2); color: var(--text); }
.seg button.on.ai { background: var(--seg-info-bg); color: var(--cyan); opacity: 1; }
.seg.sm button { padding: 2.5px 8px; font-size: 10.5px; }

/* stat cards as filter shortcuts (FeatureView only) */
.stat-card.clickable { cursor: pointer; transition: border-color .12s; }
.stat-card.clickable:hover { border-color: var(--line-2); }
.stat-card.filter-active { border-color: var(--accent-2); background: var(--accent-wash); }

/* search criteria */
.filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 14px 0 0; }
.filter-bar input[type=search] {
  flex: 1; min-width: 220px; background: var(--sunken-2); border: 1px solid var(--line-2);
  border-radius: 7px; color: var(--text); font: 12px var(--mono); padding: 7px 12px;
}
.filter-bar input[type=search]::placeholder { color: var(--faint); }
.filter-bar label {
  color: var(--faint); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  display: inline-flex; align-items: center; gap: 6px;
}
.filter-bar select {
  background: var(--panel-2); border: 1px solid var(--line-2); color: var(--text);
  font: 11.5px var(--mono); border-radius: 6px; padding: 4px 8px; text-transform: none;
}
.linklike {
  appearance: none; border: 0; background: none; color: var(--cyan);
  font: 11px var(--mono); cursor: pointer; padding: 0; margin-left: 6px;
}

/* batch bar */
.batch-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 16px; margin: 14px 0 8px;
}
.batch-bar .grp { display: inline-flex; align-items: center; gap: 8px; }
.batch-bar .grp.grow { flex: 1; }
.batch-bar .lbl { color: var(--faint); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; }
.batch-bar select {
  background: var(--panel-2); border: 1px solid var(--line-2); color: var(--text);
  font: 11.5px var(--mono); border-radius: 6px; padding: 4px 8px;
}
.batch-bar select:disabled { cursor: not-allowed; opacity: .55; }
.batch-bar button.primary {
  background: linear-gradient(92deg, var(--accent-2), var(--accent-deep)); color: var(--on-accent-deep);
  border: 0; border-radius: 7px; padding: 7px 16px; font: 12px var(--mono); cursor: pointer;
}
.batch-bar button.primary:disabled { opacity: .4; cursor: not-allowed; }
.batch-bar .serial-note { width: 100%; color: var(--faint); font-size: 11px; margin: 0; }
.batch-bar .serial-note b { color: var(--amber); font-weight: 400; }

/* item card extras */
.order-num {
  display: inline-block; min-width: 22px; text-align: center; font-size: 11px;
  color: var(--cyan); border: 1px solid var(--tint-info-line-strong); background: var(--tint-info-bg-strong);
  border-radius: 6px; padding: 1px 4px; flex: none;
}
.order-num.off { color: var(--faint); border-color: var(--line); background: transparent; }
.iso-row, .pipeline-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 6px 0 2px; }
.resolved { font-size: 10px; }
.resolved.wt { color: var(--accent-muted); }
.resolved.ip { color: var(--amber-muted); }
.resolved.ai { color: var(--cyan); }
.resolved.inherit { color: var(--text); }
.card-actions { justify-content: flex-end; }
.card-actions .spacer { flex: 1; }
.order-btns { display: inline-flex; }
.order-btns button {
  appearance: none; border: 0; background: transparent; color: var(--faint);
  font: 10px var(--mono); cursor: pointer; padding: 0 4px;
}
.order-btns button:hover { color: var(--accent); }
.run-btn {
  background: transparent; border: 1px solid var(--line-2); color: var(--text);
  border-radius: 6px; padding: 3px 12px; font: 11px var(--mono); cursor: pointer;
}
.run-btn:hover { border-color: var(--accent); color: var(--accent); }

/* per-item reset (rewind to a phase) -- ItemCard menu + ItemView row */
.reset-wrap { position: relative; display: inline-flex; }
.reset-btn {
  background: transparent; border: 1px solid var(--line-2); color: var(--dim);
  border-radius: 6px; padding: 3px 12px; font: 11px var(--mono); cursor: pointer;
}
.reset-btn:hover { border-color: var(--amber-muted); color: var(--amber-hi); }
.reset-menu {
  position: absolute; bottom: calc(100% + 4px); right: 0; z-index: 20;
  display: flex; flex-direction: column; min-width: 170px;
  background: var(--panel-2); border: 1px solid var(--line-2); border-radius: 8px;
  padding: 4px; box-shadow: 0 6px 18px var(--shadow-color);
}
.reset-menu button {
  appearance: none; border: 0; background: transparent; color: var(--text);
  font: 11px var(--mono); text-align: left; padding: 5px 9px; border-radius: 5px; cursor: pointer;
}
.reset-menu button:hover { background: var(--line); color: var(--amber-hi); }
.reset-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.reset-row select {
  background: var(--panel-2); border: 1px solid var(--line-2); color: var(--text);
  font: 11.5px var(--mono); border-radius: 6px; padding: 4px 8px;
}
.items-grid.compact .reset-btn { padding: 2px 10px; font-size: 10.5px; }

/* settings tab */
.settings-panel { margin-top: 14px; max-width: 780px; }
.setting-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 10px 0; }
.setting-row .lbl, .kv-row span {
  color: var(--dim); font-size: 11.5px; min-width: 190px; flex: none;
}
.kv-row { display: flex; gap: 12px; font-size: 12px; margin-bottom: 6px; }
.kv-row b { color: var(--text-2); font-weight: 400; word-break: break-all; }
.legend-list { margin: 0; padding-left: 20px; color: var(--text-2); font-size: 12px; }
.legend-list li { margin-bottom: 5px; }
.legend-list b { color: var(--text); font-weight: 400; }

/* add-item isolation picker */
.iso-pick, .pipeline-pick { display: flex; align-items: center; gap: 8px; color: var(--dim); font-size: 11.5px; }
.iso-pick select, .pipeline-pick select {
  background: var(--panel-2); border: 1px solid var(--line-2); color: var(--text);
  font: 11.5px var(--mono); border-radius: 6px; padding: 4px 8px;
}

/* compact item cards on the feature page -- density matched to
   mockup/feature-page-redesign.html's .card */
.items-grid.compact { grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); }
.items-grid.compact .item-card { padding: 10px 13px 9px; }
.items-grid.compact .item-card .meta { margin-bottom: 4px; gap: 6px; }
.items-grid.compact .item-card .title { font-size: 12.5px; font-weight: 500; line-height: 1.35; }
.items-grid.compact .item-card .pill { font-size: 9.5px; padding: 1px 8px; }
.items-grid.compact .phases { gap: 4px; }
.items-grid.compact .ph { font-size: 9px; padding: 1px 6px; }
.items-grid.compact .iso-row, .items-grid.compact .pipeline-row { margin: 5px 0 0; gap: 6px; }
.items-grid.compact .item-card .prog-row { margin-top: 5px; font-size: 10px; }
.items-grid.compact .item-card .prog-row .hint { font-size: 9.5px; }
.items-grid.compact .card-actions { margin-top: 3px; }
.items-grid.compact .run-btn { padding: 2px 10px; font-size: 10.5px; }
.items-grid.compact .item-card .key { padding-top: 5px; font-size: 10px; }
.items-grid.compact .item-card .key .guid { display: none; }

/* worker history page */
.worker-id-card { margin: 0 0 16px; max-width: 780px; }
.datatable tr.rowlink { cursor: pointer; }
.datatable tr.rowlink:hover td { background: var(--row-hover-soft); }
.mono-cell { font-variant-numeric: tabular-nums; color: var(--dim); white-space: nowrap; }
.err-cell { color: var(--red); font-size: 11px; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* standup meeting page -- density matched to mockup/standup-meeting.html */
.standup-tiles { grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr)); }
.stat-card.rose .stat-value { color: var(--rose-soft); }
.stat-card.cyan .stat-value { color: var(--cyan); }
.stat-pill.st-pass { color: var(--green-soft); }   .stat-pill.st-pass i { background: var(--green); }
.stat-pill.st-block { color: var(--amber-soft); }  .stat-pill.st-block i { background: var(--amber); }
.stat-pill.st-fail { color: var(--red-soft); }   .stat-pill.st-fail i { background: var(--red); }
.stat-pill.st-error { color: var(--rose-soft); }  .stat-pill.st-error i { background: var(--rose); }

.standup-panel { margin-bottom: 22px; padding: 16px 18px 12px; }
.standup-panel-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.standup-panel-head h2 { font-size: 14px; margin: 0; }
.standup-panel-head .hint { margin: 0; }
.standup-panel .empty { padding: 8px 0; }
.newlink { color: var(--accent); font-size: 12px; text-decoration: none; }
.newlink:hover { text-decoration: underline; }

ul.standup-items { list-style: none; margin: 0; padding: 0; }
ul.standup-items > li { border-top: 1px solid var(--line); padding: 9px 4px 10px; }
ul.standup-items > li:first-child { border-top: 0; }
.standup-items .row-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.standup-items .row-sub { display: flex; align-items: center; gap: 12px; margin-top: 4px;
  padding-left: 2px; flex-wrap: wrap; color: var(--dim); font-size: 11px; }
.standup-items .row-sub .why { color: var(--text-2); overflow-wrap: anywhere; }
.standup-items .spacer { flex: 1; }
.standup-items a.i-name { color: var(--text); font-size: 13px; text-decoration: none; white-space: nowrap; }
.standup-items a.i-name:hover { color: var(--accent); text-decoration: underline; }
.standup-items .i-name.plain { color: var(--text); font-size: 13px; white-space: nowrap; }
.standup-items .feat { display: inline-flex; align-items: center; font-size: 10.5px;
  padding: 1px 9px; border-radius: 20px; background: var(--accent-soft); border: 1px solid var(--accent-soft-line);
  color: var(--accent-soft-text); white-space: nowrap; }
.standup-items code.branch { color: var(--blue); font-size: 11px; background: var(--panel-2);
  border: 1px solid var(--line-2); border-radius: 6px; padding: 0 7px; white-space: nowrap; }
.standup-items .dur { color: var(--dim); font-size: 11px; min-width: 52px; text-align: right;
  white-space: nowrap; font-variant-numeric: tabular-nums; }
.standup-items .dur.ordinal { min-width: 24px; text-align: left; }
.standup-items .stat-pill { white-space: nowrap; }

/* phase trail: eight ticks, one per phase; dashed = the pipeline skips it */
.ticks { display: inline-flex; gap: 3px; align-items: center; flex: none; }
.ticks b { width: 9px; height: 9px; border-radius: 2.5px; background: var(--panel-2);
  border: 1px solid var(--line-2); }
.ticks b.ok { background: var(--tick-ok-bg); border-color: var(--tick-ok-line); }
.ticks b.bad { background: var(--tick-bad-bg); border-color: var(--tick-bad-line); }
.ticks b.now { background: var(--tick-now-bg); border-color: var(--tick-now-line); }
.ticks b.skip { background: transparent; border-style: dashed; }

.standup-items .rowactions { display: flex; gap: 6px; }
.standup-items .rowactions button { appearance: none; cursor: pointer; font: 11px var(--mono);
  border-radius: 6px; padding: 3px 10px; background: transparent;
  border: 1px solid var(--line-2); color: var(--dim); }
.standup-items .rowactions button:hover { color: var(--text); border-color: var(--dim); }
.standup-items .rowactions button:disabled { opacity: .5; cursor: default; }
.standup-items .rowactions button.primary { color: var(--accent-soft-text); border-color: var(--accent-soft-line); }
.standup-items .rowactions button.primary:hover { border-color: var(--accent-2); color: var(--text); }

/* ===========================================================================
   The phase rail and the phase console (components/PhaseRail.js,
   components/PhaseConsole.js).

   A phase used to be four things on this page: a pill in the head row, a row
   in the Diagnostics table, a card in the timeline accordion, and -- while a
   run was in flight -- a fifth rendering inside the run panel that looked
   nothing like the other three. Each had its own word for the same object (a
   *call*, an *attempt*, a *group*), and no way to map between them. Now the
   rail picks a phase and one console renders it, live or journalled alike.
   =========================================================================== */

/* --- rail: the pipeline as one strip, width proportional to elapsed time --- */
.rail-wrap {
  position: sticky; top: 0; z-index: 30; padding: 10px 0 8px; margin: 14px 0 14px;
  background: linear-gradient(180deg, var(--bg) 72%, transparent);
}
.rail { display: flex; gap: 3px; align-items: stretch; }
.rail-seg {
  position: relative; flex: 1 1 0; min-width: 76px; text-align: left; cursor: pointer;
  background: var(--panel); color: var(--dim); border: 1px solid var(--line);
  border-radius: 7px; padding: 22px 9px 8px; font: inherit; overflow: hidden;
  transition: background-color .15s, border-color .15s, color .15s;
}
.rail-seg:hover { color: var(--text); border-color: var(--line-2); }
.rail-seg.is-pending { opacity: .5; }
.rail-seg[aria-selected="true"] { background: var(--panel-2); border-color: var(--accent); color: var(--text); }
.rail-seg[aria-selected="true"]::after {
  content: ""; position: absolute; left: 50%; bottom: -1px; width: 22px; height: 2px;
  transform: translateX(-50%); background: var(--accent);
}
.rail-bar { position: absolute; inset: 0 0 auto 0; height: 4px; background: var(--line-2); }
.rail-seg.ok .rail-bar { background: var(--green); }
.rail-seg.part .rail-bar { background: var(--amber); }
.rail-seg.no .rail-bar { background: var(--red); }
.rail-seg.now .rail-bar {
  background: linear-gradient(90deg, var(--accent), var(--accent-2), var(--accent));
  background-size: 220% 100%; animation: rail-sweep 1.7s linear infinite;
}
@keyframes rail-sweep { to { background-position: -220% 0; } }
.rail-name {
  display: block; font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rail-time { display: block; font-size: 10.5px; color: var(--faint); font-variant-numeric: tabular-nums; margin-top: 2px; }
.rail-seg[aria-selected="true"] .rail-time { color: var(--dim); }
/* A phase the judge sent back is a fact about the run, not a detail two
   clicks down -- the rail carries it. */
.rail-loop { position: absolute; top: 7px; right: 7px; font-size: 9.5px; color: var(--amber); display: inline-flex; align-items: center; gap: 2px; }
.rail-loop svg { width: 9px; height: 9px; }
.rail-summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px;
  margin: 9px 2px 0; color: var(--dim); font-size: 11px;
}
.diag-open {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px; background: transparent;
  border: 1px solid var(--line-2); color: var(--dim); border-radius: 6px; padding: 4px 11px;
  font: inherit; font-size: 11px; cursor: pointer;
}
.diag-open:hover { color: var(--accent); border-color: var(--accent); }
.diag-open svg { width: 11px; height: 11px; }
@media (max-width: 720px) { .rail { flex-wrap: wrap; } .rail-seg { flex: 1 1 44%; } }

/* --- console --- */
.console { border: 1px solid var(--line-2); border-radius: 12px; background: var(--panel); overflow: hidden; }
.console.ok { box-shadow: inset 3px 0 0 var(--green); }
.console.part { box-shadow: inset 3px 0 0 var(--amber); }
.console.no { box-shadow: inset 3px 0 0 var(--red); }
.console.now { box-shadow: inset 3px 0 0 var(--accent); }
.console.pending { box-shadow: inset 3px 0 0 var(--line-2); }
.console-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px 18px 12px; border-bottom: 1px solid var(--line);
}
.console-title { font-size: 15px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; margin: 0; }
.console-sub { color: var(--dim); font-size: 11.5px; }
.console-nav { margin-left: auto; display: flex; gap: 6px; }
.navbtn {
  background: transparent; border: 1px solid var(--line-2); color: var(--dim);
  border-radius: 6px; padding: 3px 9px; font: inherit; font-size: 11px; cursor: pointer;
}
.navbtn:hover:not(:disabled) { color: var(--text); border-color: var(--accent); }
.navbtn:disabled { opacity: .35; cursor: default; }
.status-icon.ok { color: var(--green); }
.status-icon.no { color: var(--red); }
.status-icon.part { color: var(--amber); }
.status-icon.now { color: var(--accent); }
.status-icon.now svg { animation: icon-spin 1.1s linear infinite; transform-origin: center; }

/* The judge's reason, in prose, first. It is the sentence that explains the
   phase, and it used to be a dim 11px span behind a table-row expander. */
.verdict {
  padding: 15px 18px 14px; border-bottom: 1px solid var(--line);
  background: linear-gradient(90deg, var(--accent-wash-2), transparent 70%);
}
.verdict-who {
  display: inline-flex; align-items: center; gap: 6px; color: var(--faint);
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase; margin: 0 0 6px;
}
.verdict-text { margin: 0; font-size: 13.5px; line-height: 1.7; color: var(--text); max-width: 84ch; }
.verdict.no .verdict-text { color: var(--red-pale); }
.verdict-none { color: var(--dim); font-style: italic; }
.verdict-reasons { margin: 10px 0 0; padding-left: 18px; color: var(--dim); font-size: 12px; max-width: 84ch; }
.verdict-reasons li { margin: 4px 0; }
.verdict.no .verdict-reasons li::marker { color: var(--red); }

.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: 1px; background: var(--line); border-bottom: 1px solid var(--line);
}
.fact { background: var(--panel); padding: 12px 18px 14px; min-width: 0; }
.fact-label { margin: 0 0 8px; color: var(--faint); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; }
.fact .hint { margin: 0; }

/* Cost as a proportion rather than three numbers to divide in your head:
   `duration_ms` covers the agent, its judge and the writes between them, and
   "is the judge worth what it costs" is the question it gets asked most. */
.costbar { display: flex; height: 9px; border-radius: 5px; overflow: hidden; background: var(--sunken); border: 1px solid var(--line); }
.costbar i { display: block; }
.c-agent { background: var(--cyan); }
.c-judge { background: var(--accent); }
.c-over { background: var(--line-2); }
.cost-legend { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 8px 0 0; font-size: 11px; color: var(--dim); }
.cost-legend span { display: inline-flex; align-items: center; gap: 5px; }
.cost-legend i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.cost-legend b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }

/* consumes -> phase -> produces, from the agent contract. Parsed since the
   roster existed, shown here for the first time: it is what answers "why did
   this phase see that prompt". */
.flow { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 11px; }
.flow-arrow { color: var(--faint); }
.chip {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 5px;
  font: inherit; font-size: 10.5px; border: 1px solid var(--line-2); background: var(--sunken); color: var(--dim);
}
.chip.in { border-color: var(--tint-info-line); color: var(--cyan); }
.chip.out { border-color: var(--tint-ok-line); color: var(--green); }
.chip.self { border-color: var(--accent); color: var(--accent); }
.chip.none { font-style: italic; color: var(--faint); }
button.chip { cursor: pointer; }
button.chip:hover { border-color: var(--accent); color: var(--text); }

/* Attempts are versions of one piece of work, so you switch between them.
   A five-column table asks you to read across when what you want is to
   compare -- and the thing worth comparing is the artifact, below. */
.attempts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 12px 18px 0; }
.attempts-label { color: var(--faint); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; }
.atab {
  display: inline-flex; align-items: center; gap: 7px; background: var(--sunken);
  border: 1px solid var(--line); border-bottom-color: transparent; color: var(--dim);
  border-radius: 7px 7px 0 0; padding: 7px 12px; font: inherit; font-size: 11.5px; cursor: pointer;
}
.atab:hover { color: var(--text); }
.atab[aria-selected="true"] { background: var(--panel-2); border-color: var(--line-2); border-bottom-color: transparent; color: var(--text); }
.atab .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--line-2); }
.atab .dot.ok { background: var(--green); }
.atab .dot.no { background: var(--red); }
.atab .dot.part { background: var(--amber); }
.atab .dot.now { background: var(--accent); }
.atab-when { color: var(--faint); font-size: 10.5px; font-variant-numeric: tabular-nums; }
.diffbtn {
  margin-left: auto; background: transparent; border: 1px solid var(--line-2); color: var(--dim);
  border-radius: 6px; padding: 4px 10px; font: inherit; font-size: 11px; cursor: pointer;
}
.diffbtn:hover { color: var(--text); border-color: var(--accent); }
.diffbtn[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); background: var(--tint-accent-bg); }
.diffwrap { padding: 14px 18px 0; }
.diffbox { border: 1px solid var(--line-2); border-radius: 9px; overflow: hidden; background: var(--sunken); }
.diffbox pre { margin: 0; padding: 11px 13px; font: 11.5px/1.62 var(--mono); white-space: pre-wrap; word-break: break-word; }
.diffbox .add { color: var(--green); display: block; background: var(--diff-add-bg); }
.diffbox .del { color: var(--red); display: block; background: var(--diff-del-bg); }

/* The exchange: prompt -> output -> artifact -> verdict, in the order it
   happened, one numbered lane. */
.exchange { list-style: none; margin: 0; padding: 14px 18px 18px; position: relative; }
.turn { position: relative; padding-left: 30px; margin: 0 0 10px; }
.turn::before { content: ""; position: absolute; left: 9px; top: 26px; bottom: -10px; width: 1px; background: var(--line); }
.turn:last-child::before { display: none; }
.turn-marker {
  position: absolute; left: 2px; top: 8px; width: 17px; height: 17px; border-radius: 50%;
  background: var(--panel); border: 1px solid var(--line-2); color: var(--faint);
  font-size: 9.5px; display: flex; align-items: center; justify-content: center;
}
.turn.t-judge .turn-marker { border-color: var(--tint-accent-line); color: var(--accent); }
.turn.t-artifact .turn-marker { border-color: var(--tint-info-line); color: var(--cyan); }
.turn.t-artifact.rejected .turn-marker { border-color: var(--tint-bad-line); color: var(--red); }

/* A card that peeks rather than scrolls (components/PeekBlock.js). It
   replaces a `.md-block` that was `max-height: 340px; overflow: auto` --
   stacking two of those inside a scrolling page put three scroll regions in a
   column, and the reader had to find the right one before reading anything. */
.peek-card { border: 1px solid var(--line); border-radius: 9px; background: var(--sunken); overflow: hidden; }
.t-artifact .peek-card { border-color: var(--tint-info-line-soft); }
.t-artifact.rejected .peek-card { border-color: var(--tint-bad-line); }
.peek-head {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 9px 13px; border-bottom: 1px solid var(--line); background: var(--panel);
}
.peek-kind { font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; font-weight: 700; color: var(--text); }
.t-artifact .peek-kind { color: var(--cyan); }
.t-artifact.rejected .peek-kind { color: var(--red); }
.t-judge .peek-kind { color: var(--accent); }
.peek-meta { color: var(--faint); font-size: 10.5px; }
.peek-tools { margin-left: auto; display: flex; gap: 6px; }
.peek-tool {
  background: transparent; border: 1px solid var(--line-2); color: var(--dim);
  border-radius: 6px; padding: 2px 9px; font: inherit; font-size: 10.5px; cursor: pointer;
}
.peek-tool:hover { color: var(--text); border-color: var(--accent); }
.peek-body { padding: 4px 13px 8px; position: relative; }
.peek-body.clamped {
  /* `--peek-lines` against the rendered line-height, so "12 lines" means
     lines rather than a pixel guess. */
  max-height: calc(var(--peek-lines) * 1.68em); overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent);
  mask-image: linear-gradient(180deg, #000 55%, transparent);
}
.peek-more {
  display: flex; align-items: center; gap: 8px; width: 100%; background: var(--panel);
  border: 0; border-top: 1px solid var(--line); color: var(--dim); padding: 7px 13px;
  font: inherit; font-size: 11px; cursor: pointer; text-align: left;
}
.peek-more:hover { color: var(--accent); background: var(--panel-2); }
.peek-more svg { width: 10px; height: 10px; flex: none; transition: transform .15s; }
.peek-more[aria-expanded="true"] svg { transform: rotate(180deg); }
.peek-note { display: flex; align-items: center; gap: 8px; margin: 0; padding: 10px 13px; color: var(--dim); font-size: 11.5px; }
.peek-truncated { margin: 0; padding: 7px 13px; border-top: 1px solid var(--line); color: var(--amber); font-size: 11px; }
.legacy-calls { padding: 0 18px 18px; display: grid; gap: 8px; }
.legacy-calls .hint { margin: 0 0 4px; max-width: 84ch; }
.console-empty { padding: 26px 18px 30px; color: var(--dim); font-size: 12.5px; text-align: center; }
.console-empty b { display: block; color: var(--text); margin-bottom: 6px; }
.console-empty p { margin: 0 auto; max-width: 70ch; }

/* Diagnostics, in the drawer. It is not replaced by the console: it answers
   what the whole run cost end to end, which is the only item-wide question
   here. Moving it out of the page column is what buys `reason` its own line
   -- inline it was a seventh column, so it lived behind a row expander. */
.diag-total { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0 0 12px; color: var(--dim); font-size: 11.5px; }
.diag-total b { color: var(--text); font-weight: 600; }
.diag-agent small { display: block; color: var(--faint); font-size: 10px; }
tr.diag-reason-row td { border-bottom: 1px solid var(--line); padding: 0 8px 9px; }
.diag-reason { display: block; color: var(--dim); max-width: 92ch; line-height: 1.6; margin-bottom: 4px; }
.side-panel-body .diag-table-wrap { max-height: none; }

@media (prefers-reduced-motion: reduce) {
  .rail-seg.now .rail-bar, .status-icon.now svg { animation: none !important; }
}

/* ===========================================================================
   Job preparation (portal/static/components/PreparationPanel.js) -- what a job
   did between "Run" and the first phase of its first item. Design:
   mockup/job-preparation-phase.html.
   =========================================================================== */
.prep { margin: 0 0 8px; }

/* The rail. Segment widths are proportional to real elapsed time, so where
   the wait went is legible before a single number is read -- but only with
   the space left over after every segment has room for its own label.
   `flex-basis: auto` plus `flex-shrink: 0` makes each card at least as wide
   as its longest line, and PreparationPanel.js supplies the grow weight that
   splits the surplus. Cards wrap rather than clip when even the minimums do
   not fit: an ellipsised worker id says less than a second row does. */
.prep-rail { display: flex; flex-wrap: wrap; gap: 3px; align-items: stretch; margin: 0 0 10px; }
.prep-seg {
  position: relative; background: var(--panel); border: 1px solid var(--line);
  border-radius: 7px; padding: 20px 11px 9px; overflow: hidden;
  flex: 0 0 auto; min-width: 124px;
}
.prep-seg .bar { position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--line-2); }
.prep-seg.ok .bar { background: var(--green); }
.prep-seg.part .bar { background: var(--amber); }
.prep-seg.skip, .prep-seg.pending { opacity: .55; }
.prep-name { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text); white-space: nowrap; }
.prep-sub { display: block; font-size: 11px; color: var(--faint); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Out of flow, so it never widens the card -- and capped so an unexpectedly
   long value ellipsises inside its own corner instead of sliding left under
   the segment bar. */
.prep-time {
  position: absolute; top: 7px; right: 9px; max-width: calc(100% - 20px);
  font-size: 10px; color: var(--faint); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.prep-total { display: flex; flex-wrap: wrap; gap: 6px 18px; color: var(--dim); font-size: 11.5px; margin: 0 2px 14px; }
.prep-total b { color: var(--text); font-weight: 600; }
/* Narrow: the rail already wraps, so all that is left is to stop a lone card
   on the last row from stretching to the full width. */
@media (max-width: 760px) { .prep-seg { flex-grow: 1 !important; } }

.prep-cols { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: 14px; margin: 0 0 14px; }
@media (max-width: 900px) { .prep-cols { grid-template-columns: 1fr; } }
.prep-cols .panel { border: 1px solid var(--line); border-radius: 10px; padding: 16px 18px; background: var(--panel); }
.prep-card-h { font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--dim); margin: 0 0 12px; }

.prep-kv { display: grid; grid-template-columns: max-content 1fr; gap: 7px 16px; font-size: 12px; align-items: baseline; margin: 0; }
.prep-kv dt { color: var(--faint); white-space: nowrap; }
.prep-kv dd { margin: 0; overflow-wrap: anywhere; }
.prep-kv .sub, .prep .sub { color: var(--faint); font-size: 11px; }
.prep-kv .mono-id { color: var(--cyan); font-size: 11.5px; }

.prep-policy { width: 100%; border-collapse: collapse; font-size: 12px; }
.prep-policy th { text-align: left; color: var(--faint); font-weight: 500; font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; padding: 0 10px 7px 0; border-bottom: 1px solid var(--line); }
.prep-policy td { padding: 8px 10px 8px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.prep-policy tr:last-child td { border-bottom: 0; }
/* The precedence chain, rendered rather than explained: the rule that had
   nothing to say is struck through, the one that decided is highlighted. */
.prep-policy .chain { display: block; font-size: 10.5px; color: var(--faint); margin-top: 3px; }
.prep-policy .chain .lost { text-decoration: line-through; text-decoration-color: var(--line-2); }
.prep-policy .chain .won { color: var(--accent); }
.prep-policy .chain i { font-style: normal; color: var(--line-2); margin: 0 4px; }

.prep-planner { border: 1px solid var(--line-2); border-radius: 12px; background: var(--panel); overflow: hidden; }
.prep-planner.ok { box-shadow: inset 3px 0 0 var(--green); }
.prep-planner.part { box-shadow: inset 3px 0 0 var(--amber); }
.prep-planner.skip { box-shadow: inset 3px 0 0 var(--line-2); }
.prep-planner-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 18px; border-bottom: 1px solid var(--line); background: var(--panel-2); }
.prep-planner-head h3 { font-size: 12.5px; margin: 0; letter-spacing: .04em; }
.prep-planner-meta { margin-left: auto; color: var(--faint); font-size: 11px; font-variant-numeric: tabular-nums; }
.prep-planner-body { padding: 14px 18px 16px; }
.prep-verdict { margin: 0; font-size: 12px; }
.prep-verdict b { display: block; margin-bottom: 3px; }
.prep-verdict.ok b { color: var(--green); }
.prep-verdict.part b { color: var(--amber); }
.prep-verdict.skip b { color: var(--dim); }
.prep-verdict span { color: var(--dim); }
.prep-reasons { margin: 9px 0 0; padding-left: 18px; color: var(--amber); font-size: 11.5px; }
.prep-reasons li { margin: 3px 0; }
.prep-peek-toggle { margin-top: 12px; font-size: 11px; }
.prep-stdout {
  margin: 9px 0 0; padding: 12px 14px; background: var(--bg); border: 1px solid var(--line);
  border-radius: 8px; font-size: 11.5px; line-height: 1.6; color: var(--text-2);
  max-height: 320px; overflow: auto; white-space: pre-wrap; word-break: break-word;
}

/* The job's item table: preparation's columns and execution's, over the same
   rows. Tinted apart so either half can be read alone; the rule between them
   is where the job stops being a plan and starts being a run. */
.tablewrap { overflow-x: auto; }
table.jobitems { min-width: 760px; }
table.jobitems .grouprow th { padding-bottom: 2px; font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; border-bottom: 0; color: var(--faint); }
table.jobitems .grouprow .g-prep { color: var(--accent); }
table.jobitems .grouprow .g-run { color: var(--green); }
table.jobitems .g-run { background: var(--run-row-bg); }
table.jobitems .g-run.start { border-left: 1px solid var(--line-2); }
table.jobitems .ord { white-space: nowrap; font-variant-numeric: tabular-nums; }
table.jobitems .ord .was { color: var(--amber); font-size: 10.5px; margin-left: 6px; }
table.jobitems .num { font-variant-numeric: tabular-nums; color: var(--dim); }
table.jobitems .itemtitle { display: block; color: var(--dim); font-size: 11.5px; }
table.jobitems .src { display: block; font-size: 10px; letter-spacing: .05em; text-transform: uppercase; color: var(--faint); margin-top: 2px; }
