/*
 * The demo's stylesheet. The first block is copied verbatim from the real dashboard
 * (migration2fs-llmdriven/src/dashboard/client/skin.css): tokens, body, head band, nav pills.
 * Light only, like the real dashboard.
 */

/* Public Sans ships with the demo (fonts/, SIL Open Font License 1.1): it needs no network, so venue
   Wi-Fi that drops packets cannot hold the first paint. One variable file per subset, weights 400-800. */
@font-face {
  font-family: "Public Sans"; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url("../fonts/public-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Public Sans"; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url("../fonts/public-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
:root {
  color-scheme: light;
  --bg: #ffffff;
  --pane: #ffffff;
  --ink: #1a1616;
  /* 5.4:1 on white, 4.7:1 on lavender: secondary text stays readable on a projector. */
  --muted: #646a7e;
  --text: #474c5c;
  --line: #e4e7ef;
  --lavender: #efedfb;
  --lavender-2: #f1e7fe;
  --glow: #b5a8ff;
  --purple: #bd2eff;
  --grape: #8f18ff;
  --tint: #f1f3f7;
  /* The stepper band's surface. It is the pane's own white; the name stays because the band IS the
     rail, whatever shape it takes. */
  --side-bg: #ffffff;
  --side-ink: #1a1616;
  --side-muted: #9aa1b4;
  --side-line: #e4e7ef;
  /* Status: green is done or passed, purple is running or the brand, amber is "a person must act",
     red is stopped. Slate marks what is simulated: where a value comes from, not how it stands. */
  --ok: #0f7a58;
  --run: #bd2eff;
  --warn: #9a5f0e;
  --sim: #5b6478;
  --bad: #d92d20;
  --idle: #9aa1b4;
  --radius: 16px;
  --radius-sm: 10px;
  /* The rail's own five-colour vocabulary (`railStatus` in app.js) — applied identically to the
     dot, the kicker, the badge and the segment. `locked`/`skipped` use no fill at all: a hollow
     ring, never a hue, because neither state is an outcome. */
  --rail-green: #0f7a58;
  --rail-amber: #9a5f0e;
  --rail-red: #d92d20;
  --rail-grad: linear-gradient(135deg, #8f18ff 0%, #bd2eff 100%);
  --rail-muted: #9aa1b4;
  --rail-line: #e4e7ef;
  --r-pill: 999px;
  --bloom: 0 30px 70px -34px rgba(181, 168, 255, .85);
  --bloom-sm: 0 16px 40px -24px rgba(181, 168, 255, .8);
  --font: "Public Sans", "Segoe UI", -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  /* ONE content width. The head band's content, the board's stepper and its pane share `--maxw`
     and the same side gutters, so on a wide screen everything starts and ends on the same lines. */
  --maxw: 1480px;
  --gutter: 48px;
  /* Type: seven sizes. 12 is the floor for capital labels, 13 for anything read as text. */
  --fs-1: 12px;
  --fs-2: 13px;
  --fs-3: 14px;
  --fs-4: 16px;
  --fs-5: 20px;
  --fs-6: 26px;
  --fs-7: 32px;
  /* Motion: four durations and three curves, so every move in the demo has the same feel. Things
     arrive decelerating (enter), leave accelerating (exit), and change in place on the standard
     curve. The run's own timings (a step running for 2.6 s, the import rows) keep theirs. */
  --dur-1: 150ms;             /* hover, focus, a colour */
  --dur-2: 250ms;             /* something small appears or lets go */
  --dur-3: 450ms;             /* a card or a panel arrives */
  --dur-4: 900ms;             /* a slow fade, a bar that fills */
  --dur-highlight: 2700ms;    /* what a beat changed: HIGHLIGHT_MS in js/app.js */
  --ease-standard: cubic-bezier(.4, 0, .2, 1);
  --ease-enter: cubic-bezier(0, 0, .2, 1);
  --ease-exit: cubic-bezier(.4, 0, 1, 1);
}
* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  background-image:
    radial-gradient(52% 38% at 88% 4%, rgba(181, 168, 255, .30), transparent 68%),
    radial-gradient(44% 34% at 4% 34%, rgba(189, 46, 255, .10), transparent 70%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-4);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
.mono { font-family: var(--mono); font-size: var(--fs-2); }
.empty { color: var(--muted); font-style: italic; }
a { color: var(--grape); text-decoration-thickness: 1px; text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--purple); outline-offset: 3px; }
::selection { background: var(--purple); color: #fff; }

/* ── the head band: brand, run, live, the other surfaces ──────────────────── */
/* The one strip a reader navigates the three pages by. Its rule spans the window; its CONTENT sits
   on the same lines as everything below it. */
.side-head {
  display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
  padding: 16px var(--gutter) 14px; border-bottom: 1px solid var(--side-line);
  background: rgba(255, 255, 255, .92);
}
.side-head { padding-left: max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter))); padding-right: max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter))); }
.brand { display: flex; align-items: center; gap: 11px; }
.brand-mark { width: 12px; height: 12px; border-radius: 50%; background: var(--purple); }
/* In the demo the brand is the way back to the start page. */
a.brand { text-decoration: none; border-radius: var(--r-pill); }
a.brand .brand-mark { transition: box-shadow var(--dur-1) var(--ease-standard); }
a.brand:hover .brand-mark, a.brand:focus-visible .brand-mark { box-shadow: 0 0 0 4px rgba(189, 46, 255, .2); }
.brand-name { font-weight: 800; font-size: var(--fs-4); letter-spacing: -.01em; color: #000; }
.brand-slash { color: var(--purple); }
.side-run { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex: 1; }
.side-head .slug { font-size: var(--fs-4); font-weight: 700; color: var(--ink); letter-spacing: -.01em; white-space: nowrap; }
.side-head .run-id { font-family: var(--mono); font-size: var(--fs-2); color: var(--muted); white-space: nowrap; }
/* The workspace path is an identifier, not reading matter: one line, clipped from the right, the
   whole of it in the title attribute the browser shows on hover. */
.side-head .where { font-size: var(--fs-2); color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-nav { display: flex; gap: 6px; }
.nav-pill {
  font-size: var(--fs-2); font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text); padding: 8px 16px; border-radius: var(--r-pill); text-decoration: none;
  transition: color var(--dur-1) var(--ease-standard), background var(--dur-1) var(--ease-standard);
}
.nav-pill:hover, .nav-pill:focus-visible { color: #000; background: var(--lavender); }
.nav-pill.current { color: #fff; background: var(--purple); }
.side-head .when {
  margin-left: auto; display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-2); font-weight: 700; color: var(--text); white-space: nowrap;
}
.side-head .when::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--purple);
  box-shadow: 0 0 0 4px rgba(189, 46, 255, .18);
}
/* The event stream is down. Amber rather than red: the page is still true, it has just stopped
   being told when it stops being true. */
.side-head .when.offline { color: var(--warn); }
.side-head .when.offline::before { background: var(--warn); box-shadow: none; }

/* ── narrow ───────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  :root { --gutter: 20px; }
  .side-head { gap: 12px; }
}

/* ══ Everything below is the demo's own. The rules above are the real dashboard's skin.css,
   copied verbatim; the board rules below follow the real styles.css, mapped onto the demo's five
   statuses: todo · running · your-turn · done · blocked. ═══════════════════════════════════ */

.muted { color: var(--muted); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
code { font-family: var(--mono); font-size: var(--fs-2); color: var(--ink); background: var(--tint); padding: 1px 6px; border-radius: 6px; }
button { font: inherit; }
button:disabled { cursor: default; }
.kicker, .rail-kicker {
  font-size: var(--fs-1); letter-spacing: .14em; text-transform: uppercase; font-weight: 800;
}
.kicker { color: var(--muted); margin-bottom: 8px; }
.kicker .mono { text-transform: none; letter-spacing: 0; }

/* ── head band: buttons dressed as the real links ───────────────────────── */
#head { position: relative; z-index: 5; }
/* Between 900 and ~1100 px the run row is squeezed: clip it rather than run under the badge. */
.side-run { overflow: hidden; }
/* The run in two lines: the site, then when it ran and where from. The run id is on hover. */
.run-info { display: grid; min-width: 0; line-height: 1.25; }
.run-meta { font-size: var(--fs-2); font-weight: 600; color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 1100px) { .side-head { gap: 14px; } }
.nav-pill { border: 0; background: none; cursor: pointer; font-family: inherit; }
/* Small white text needs the darker purple: on --purple it reaches only 4.2:1. */
.nav-pill.current { background: var(--grape); }
.nav-pill:disabled { opacity: .45; }
.nav-pill:disabled:hover { background: none; color: var(--text); }
.demo-badge {
  flex: 1 1 auto; display: flex; justify-content: center; margin: 0 10px; min-width: 0;
  font-size: var(--fs-1); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; color: var(--sim);
}
/* The badge takes the band's free width; its dashed border goes round the words only. */
.demo-badge-text { border: 1px dashed var(--sim); border-radius: var(--r-pill); padding: 3px 10px; }
/* So the run line keeps only its own width, and the clock sits beside the badge. */
.side-run { flex: 0 1 auto; }
.side-head .when { margin-left: 0; }

/* ── layout: the band (the rail) over the pane (the stage detail) ───────── */
.band { border-bottom: 1px solid var(--side-line); padding: 22px 0 18px; }
.side-top {
  width: calc(100% - 2 * var(--gutter)); max-width: calc(var(--maxw) - 2 * var(--gutter)); margin: 0 auto;
}
.pane { padding: 30px var(--gutter) 90px; max-width: var(--maxw); width: 100%; margin: 0 auto; }
/* Room for the tour panel docked over the bottom right. */
body.tour-open .pane, body.tour-open .hub { padding-bottom: 340px; }

/* ── the stepper ─────────────────────────────────────────────────────────── */
.side-rail {
  background: var(--pane); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--bloom); padding: 12px 22px 16px; min-width: 0;
}
/* The stage rail: the phase captions over their stages, a bracket per stage over its steps, a bar
   and a tile per step; 14 columns plus a narrow one for the dashed line between Phase 1 (stages 1–3)
   and Phase 2 (stage 4), which runs through all four rows. */
.stage-grid {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)) 30px repeat(7, minmax(0, 1fr));
  column-gap: 4px; row-gap: 8px;
}
.phase-line { grid-column: 8; grid-row: 1 / span 4; justify-self: center; width: 0; border-left: 2px dashed var(--glow); }
.phase-cap {
  grid-row: 1; display: flex; align-items: center; gap: 16px; min-width: 0; white-space: nowrap;
  font-size: var(--fs-1); font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
}
.stage { grid-row: 2; }
.seg { grid-row: 3; }
.step { grid-row: 4; }
.rail-hint { display: none; margin: 8px 0 0; font-size: var(--fs-1); color: var(--muted); text-align: right; }
/* The key to the owner marks on the tiles, at the end of the Phase 2 caption. */
.owner-key { margin-left: auto; display: flex; gap: 14px; font-weight: 600; letter-spacing: 0; text-transform: none; }
.owner-key > span { display: inline-flex; align-items: center; gap: 5px; }
.owner-icon { width: 12px; height: 12px; flex: none; fill: currentColor; }
.own-agent .owner-icon { color: var(--grape); }
.own-tool .owner-icon { color: var(--muted); }
.own-reviewer .owner-icon { color: var(--rail-amber); }
.stage {
  display: flex; align-items: center; gap: 8px; min-width: 0; padding: 6px 10px; cursor: pointer; font: inherit;
  font-size: var(--fs-3); font-weight: 800; color: var(--text); text-align: left;
  background: var(--tint); border: 1px solid var(--line); border-bottom: 3px solid var(--line); border-radius: 10px 10px 4px 4px;
  transition: border-color var(--dur-1) var(--ease-standard), background var(--dur-1) var(--ease-standard);
}
.stage:hover { border-color: var(--glow); }
.stage.done { border-bottom-color: var(--ok); }
.stage.started { border-bottom-color: var(--glow); }
.stage.attention { border-bottom-color: var(--rail-amber); }
.stage.on { color: var(--grape); background: var(--lavender); border-color: var(--glow); box-shadow: 0 0 0 3px var(--lavender); }
.stage-num {
  flex: none; width: 20px; height: 20px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--fs-1); font-weight: 800; background: rgba(26, 22, 22, .08); color: var(--muted);
}
.stage.done .stage-num { background: var(--ok); color: #fff; }
.stage.attention .stage-num { background: rgba(154, 95, 14, .14); color: var(--warn); }
/* A long title wraps to two balanced lines rather than ending in an ellipsis. */
.stage-title { min-width: 0; line-height: 1.2; text-wrap: balance; }
.seg { height: 6px; border-radius: var(--r-pill); background: var(--lavender); }
.seg.done { background: var(--rail-green); }
.seg.running { background: var(--rail-grad); animation: breathe 1.8s ease-in-out infinite; }
.seg.your-turn { background: var(--rail-amber); }
.seg.blocked { background: var(--rail-red); }

/* A step tile: two fixed rows, the badge and the owner's mark, then the title on two reserved lines,
   so each row lines up across all fourteen tiles at every width. */
.step {
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; gap: 7px; min-width: 0;
  text-align: left; cursor: pointer; padding: 10px 9px; border-radius: var(--radius-sm); background: none;
  color: var(--side-ink); border: 1px solid transparent;
  transition: background var(--dur-1) var(--ease-standard), border-color var(--dur-1) var(--ease-standard);
}
.step:hover, .step:focus-visible { background: var(--lavender); outline: none; }
.step-top { display: flex; align-items: center; gap: 7px; min-height: 22px; }
.step-top .rail-owner { margin-left: auto; display: flex; }
.step-top .owner-icon { width: 14px; height: 14px; }
.rail-kicker { color: var(--muted); }
.rail-kicker.done { color: var(--rail-green); }
.rail-kicker.running { color: var(--purple); }
.rail-kicker.your-turn { color: var(--rail-amber); }
.rail-kicker.blocked { color: var(--rail-red); }
.rail-label {
  min-width: 0; min-height: 2.5em; font-size: var(--fs-2); font-weight: 800; letter-spacing: -.01em; color: var(--ink); line-height: 1.25;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.step.todo .rail-label { color: var(--text); font-weight: 700; }
.step.your-turn, .step.running { background: var(--lavender); border-color: var(--purple); box-shadow: var(--bloom-sm); }
.step.blocked { border-color: var(--rail-red); }
.step.current { border-color: var(--purple); border-style: solid; }
.step.blocked.current { border-color: var(--rail-red); }
.step.selected { background: var(--lavender); box-shadow: inset 0 0 0 2px var(--glow); }
/* Up to 1440px a tile has about 60px: a size smaller and tighter, so every word still fits whole. */
@media (max-width: 1440px) {
  .stage { font-size: var(--fs-2); padding: 6px 8px; gap: 6px; }
  .step { padding: 8px 6px; }
  .rail-label { font-size: var(--fs-1); }
}

.rail-dot {
  position: relative; flex: none; width: 20px; height: 20px; border-radius: 50%;
  background: transparent; box-shadow: inset 0 0 0 1.5px var(--rail-line);
}
.rail-dot.done { background: var(--rail-green); box-shadow: none; }
.rail-dot.done::after {
  content: ''; position: absolute; left: 6px; top: 4px; width: 5px; height: 9px;
  border-right: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(45deg);
}
.rail-dot.your-turn { background: var(--rail-amber); box-shadow: 0 0 0 4px rgba(201, 130, 27, .18); }
.rail-dot.blocked { background: var(--rail-red); box-shadow: none; }
.rail-dot.running { background: var(--purple); box-shadow: 0 0 0 4px rgba(189, 46, 255, .18); animation: statePulse 1.6s ease-in-out infinite; }
/* On a tile the badge carries the step's number; the check takes its place once the step is done. */
.step .rail-dot {
  width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;
  font: 800 var(--fs-1)/1 var(--font); font-style: normal; font-variant-numeric: tabular-nums; color: var(--muted);
}
.step .rail-dot.running, .step .rail-dot.your-turn, .step .rail-dot.blocked { color: #fff; }
.step .rail-dot.done::after { left: 7px; top: 4.5px; }

/* ── the status chip (dot + kicker), used outside the rail ──────────────── */
.chip { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.chip .rail-dot { width: 14px; height: 14px; }
.chip .rail-dot.done::after { left: 4.5px; top: 2.5px; width: 3.5px; height: 6.5px; border-right-width: 1.5px; border-bottom-width: 1.5px; }
.chip .rail-dot.your-turn, .chip .rail-dot.running { box-shadow: 0 0 0 2px rgba(189, 46, 255, .18); }


/* ── buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--line); background: var(--pane); color: var(--ink);
  font: inherit; font-size: var(--fs-2); font-weight: 700; padding: 8px 16px;
  border-radius: var(--r-pill); cursor: pointer; text-decoration: none;
  transition: border-color var(--dur-1) var(--ease-standard), background var(--dur-1) var(--ease-standard), color var(--dur-1) var(--ease-standard), box-shadow var(--dur-1) var(--ease-standard);
  max-width: 100%;
}
.btn:hover, .btn:focus-visible { border-color: var(--purple); color: var(--grape); }
.btn:disabled { opacity: .5; }
.btn:disabled:hover { border-color: var(--line); color: var(--ink); }
/* --grape, not --purple: white on it is 5.6:1 (on --purple 4.2:1). */
.btn-primary { background: var(--grape); border-color: var(--grape); color: #fff; }
.btn-primary:hover, .btn-primary:focus-visible { background: color-mix(in srgb, var(--grape) 82%, #000); border-color: color-mix(in srgb, var(--grape) 82%, #000); color: #fff; }
.btn-sm { font-size: var(--fs-2); padding: 5px 12px; }
.btn.live { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); background: color-mix(in srgb, var(--warn) 7%, var(--pane)); }

/* ── tabs and the run log ────────────────────────────────────────────────── */
.tabs {
  min-height: 60vh; min-width: 0; background: var(--pane); border: 1px solid var(--glow); border-radius: var(--radius);
  box-shadow: 0 0 0 3px var(--lavender);
}
.tabs-head { margin: 0; padding: 14px 18px 4px; font-size: var(--fs-4); font-weight: 800; color: var(--grape); }
/* Off the tour: what the board shows, where the tour is, and the way back. It arrives with the click
   that left the tour (body.still keeps it from replaying) and goes with the way back. */
.tour-off {
  display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap;
  padding: 10px 18px; font-size: var(--fs-3); color: var(--text); background: var(--lavender);
  border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0;
  animation: tourOffIn var(--dur-2) var(--ease-enter) both;
}
.tour-off b { color: var(--ink); }
.tour-off-acts { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
@keyframes tourOffIn { from { opacity: 0; transform: translateY(-4px); } }
.btn-link {
  border: 0; background: none; padding: 0; font: inherit; font-size: var(--fs-2); font-weight: 700; color: var(--grape);
  cursor: pointer; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.btn-link:hover, .btn-link:focus-visible { color: var(--purple); }
.tabbar {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 2px;
  padding: 0 4px; border-bottom: 1px solid var(--line); margin-bottom: 0;
}
.tab {
  display: inline-flex; align-items: baseline; gap: 8px; cursor: pointer;
  font: inherit; font-size: var(--fs-3); font-weight: 700; color: var(--text);
  background: none; border: 0; border-bottom: 3px solid transparent;
  padding: 8px 10px 9px; margin-bottom: -1px; border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  transition: background var(--dur-1) var(--ease-standard), color var(--dur-1) var(--ease-standard);
}
.tab:hover, .tab:focus-visible { background: var(--lavender); color: var(--ink); }
.tab.on { color: var(--grape); border-bottom-color: var(--purple); }
.tab-count { font-size: var(--fs-1); font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; }
.tab.on .tab-count { color: var(--grape); }
.tabpanel {
  background: var(--pane); border: 1px solid var(--line); border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius); margin-bottom: 10px;
}
.tabs > .tabpanel { border: 0; margin-bottom: 0; padding: 22px 24px 28px; }

/* ── cards, the hub ──────────────────────────────────────────────────────── */
.card {
  background: var(--pane); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--bloom-sm); padding: 24px 28px;
}
.hub { max-width: 920px; margin: 0 auto; padding: 40px var(--gutter) 90px; display: grid; gap: 22px; }
.hub h1 { margin: 0 0 18px; font-size: var(--fs-7); font-weight: 800; letter-spacing: -.035em; line-height: 1.1; color: var(--ink); }
.hub-new { box-shadow: var(--bloom); }
.hub-form { display: flex; gap: 10px; flex-wrap: wrap; }
.hub-url { position: relative; flex: 1 1 260px; min-width: 0; display: flex; }
.hub-url .src-web { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); pointer-events: none; }
.hub-form input {
  flex: 1 1 auto; width: 100%; min-width: 0; font: inherit; font-size: var(--fs-4); color: var(--ink);
  padding: 10px 16px 10px 48px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--tint);
}
.hub-what { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line); }
.hub-what ul { margin: 0; padding-left: 18px; font-size: var(--fs-3); }
.hub-what li + li { margin-top: 4px; }
/* The other ways in: a Figma file, a DXM project. Each tile opens its picker. */
.hub-or {
  display: flex; align-items: center; gap: 12px; margin: 20px 0 12px;
  font-size: var(--fs-1); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.hub-or::before, .hub-or::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.hub-alts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.hub-alt {
  display: flex; align-items: center; gap: 14px; min-width: 0; padding: 12px 16px; text-align: left;
  font: inherit; color: var(--text); background: var(--pane); border: 1px solid var(--line); border-radius: 14px;
  cursor: pointer; transition: border-color var(--dur-1) var(--ease-standard), box-shadow var(--dur-1) var(--ease-standard);
}
.hub-alt:hover, .hub-alt:focus-visible { border-color: var(--glow); box-shadow: var(--bloom-sm); }
.hub-alt b { display: block; font-size: var(--fs-3); color: var(--ink); }
.hub-alt small { display: block; font-size: var(--fs-2); color: var(--muted); }
.hub-alt-go { margin-left: auto; font-weight: 800; color: var(--grape); }
.src-logo { width: 30px; height: 30px; flex: none; object-fit: contain; border-radius: 5px; }
.src-web { color: var(--grape); }
.run-src { display: inline-flex; }

/* ── a source picker over the hub (a mock-up) ───────────────────────────── */
.src-shade {
  position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center;
  padding: 16px; background: rgba(26, 22, 22, .32); animation: fadeIn var(--dur-2) var(--ease-enter) both;
}
.src-dialog { width: 100%; max-width: 520px; display: grid; gap: 12px; box-shadow: var(--bloom); }
.src-dialog h2 { display: flex; align-items: center; gap: 12px; margin: 0; font-size: var(--fs-5); color: var(--ink); letter-spacing: -.02em; }
.src-dialog p { margin: 0; font-size: var(--fs-3); }
.src-label { margin: 4px 0 -6px; }
.src-input {
  width: 100%; min-width: 0; font: inherit; font-size: var(--fs-3); color: var(--ink);
  padding: 9px 16px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--tint);
}
.src-file { display: grid; padding: 10px 14px; font-size: var(--fs-3); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.src-file small { font-size: var(--fs-2); color: var(--muted); }
.src-select {
  display: flex; justify-content: space-between; gap: 10px; padding: 9px 16px; font-size: var(--fs-3); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--tint);
}
.src-foot { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
/* Room and a radius for the glow a beat puts around the new run; the negative margin keeps its
   content on the card's lines. */
.run-row { display: grid; gap: 8px; padding: 14px 12px 8px; margin: 0 -12px; border-radius: var(--radius-sm); }
.run-main { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.run-name { font-size: var(--fs-3); font-weight: 700; color: var(--ink); overflow-wrap: anywhere; }
.run-meta { font-size: var(--fs-2); overflow-wrap: anywhere; }
.run-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ── demo markers ────────────────────────────────────────────────────────── */
/* Badges: one shape in three roles.
   - status: how a run or a step stands (passed, stopped, coming up);
   - provenance: where a value comes from (real run solid, simulated dashed slate);
   - meta: an owner or a kind, neutral. */
.sim-tag, .real-tag, .src, .owner-pill, .exit, .chip-coming, .badge {
  display: inline-flex; align-items: center; vertical-align: middle; min-height: 22px; padding: 0 9px;
  border: 1px solid transparent; border-radius: var(--r-pill); font-family: var(--font); font-size: var(--fs-1);
  font-weight: 800; letter-spacing: .06em; text-transform: uppercase; line-height: 1; white-space: nowrap;
}
.real-tag, .src.real { color: var(--grape); background: var(--lavender); }
.sim-tag, .src.sim { color: var(--sim); border: 1px dashed var(--sim); }
.owner-pill, .badge { color: var(--text); background: var(--tint); }
.badge.error { color: var(--bad); }
.badge.warn { color: var(--warn); }
.badge.ok { color: var(--ok); }
.exit { color: var(--ok); border-color: currentColor; }
.exit:not(.exit-0) { color: var(--bad); background: color-mix(in srgb, var(--bad) 6%, #fff); }
.chip-coming { color: var(--text); background: var(--tint); border-color: var(--line); }
.chip-coming::before { content: ''; flex: none; width: 8px; height: 8px; margin-right: 6px; border: 1.5px solid currentColor; border-radius: 50%; }
.img-missing {
  display: flex; align-items: center; justify-content: center; min-height: 120px; padding: 16px;
  border: 1px dashed var(--muted); border-radius: var(--radius-sm); background: var(--tint);
  color: var(--muted); font-size: var(--fs-2); text-align: center;
}
.guard { max-width: 620px; margin: 12vh auto; padding: 32px 36px; }
.guard h1 { margin: 0 0 10px; font-size: var(--fs-6); font-weight: 800; color: var(--ink); letter-spacing: -.02em; }
.fallback { color: var(--muted); font-style: italic; }

/* ── step showcases: the head every step starts with ────────────────────── */
.sc-head { padding-bottom: 16px; margin-bottom: 18px; border-bottom: 1px solid var(--line); }
.sc-title { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 4px 0 6px; }
.sc-title h3 { margin: 0; font-size: var(--fs-6); font-weight: 800; letter-spacing: -.02em; color: var(--ink); }
.sc-plain { margin: 0 0 8px; font-size: var(--fs-4); color: var(--text); max-width: 72ch; }
.sc-cmd { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: var(--fs-2); color: var(--muted); }
.sc-cmd code { min-width: 0; overflow-wrap: anywhere; color: var(--ink); background: #fff; border: 1px solid var(--line); padding: 5px 10px; }
.btn-copy {
  flex: none; cursor: pointer; font-size: var(--fs-1); font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--grape); background: #fff; border: 1px solid var(--glow); border-radius: var(--r-pill); padding: 4px 10px;
  transition: border-color var(--dur-1) var(--ease-standard);
}
.btn-copy:hover, .btn-copy:focus-visible { border-color: var(--purple); }
.btn-copy.copied { background: var(--grape); color: #fff; border-color: var(--grape); }
.run-bar { height: 6px; margin-top: 12px; border-radius: var(--r-pill); background: var(--lavender); overflow: hidden; }
/* --run-at is the time the step has already run (js/app.js): a redraw during the run carries the bar
   on from where it stands. */
.run-bar > i { display: block; height: 100%; width: 100%; background: var(--rail-grad); animation: fill 2.6s linear both; animation-delay: calc(0ms - var(--run-at, 0ms)); }
/* A step still running after its animation: a short bar slides on, so it never looks stuck at full. */
.run-bar.ongoing > i { width: 35%; animation: runOn 1.4s var(--ease-standard) infinite; }
@keyframes runOn { from { transform: translateX(-100%); } to { transform: translateX(290%); } }
.run-note { margin: 8px 0 0; font-size: var(--fs-2); color: var(--muted); }
/* What a running step does, in place of the result it has not produced yet. */
.run-wait { margin: 4px 0 0; font-size: var(--fs-3); color: var(--muted); }
/* A number counting up with its step looks like the number it becomes (not like the label span next
   to it) and keeps its width while the digits change. */
.counter b > .count, .big b > .count, .legend b > .count, .sc-sub > .count { font: inherit; color: inherit; font-variant-numeric: tabular-nums; }
/* One column that never grows past the panel: a wide table or picture scrolls inside, not the page. */
.sc-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; min-width: 0; }
.sc-sub { margin: 6px 0 0; font-size: var(--fs-2); font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.small { font-size: var(--fs-2); }
.sc-body > p, .sc-body p.small, .sc-body p.muted { max-width: 80ch; }
.banner { padding: 12px 16px; border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--tint); font-size: var(--fs-3); }
.banner.good { border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); background: color-mix(in srgb, var(--ok) 8%, var(--pane)); color: var(--ink); }
.banner.info { color: var(--text); }
.banner.warn { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); background: color-mix(in srgb, var(--warn) 8%, var(--pane)); color: var(--ink); }
.counters { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; border-radius: var(--radius-sm); }
/* Stat tiles: the counters, the quality cards and the verify numbers share one look. A number that
   needs work (.needs-work) carries the amber of "a person must act". */
.counter, .q-card, .big {
  display: grid; gap: 4px; align-content: start; padding: 14px 16px; background: var(--pane);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.counter b, .q-card b, .big b {
  font-size: var(--fs-6); font-weight: 800; letter-spacing: -.02em; line-height: 1.1; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.counter span, .q-card span, .big span { font-size: var(--fs-3); font-weight: 700; color: var(--text); }
.q-card.needs-work { border-left: 3px solid var(--warn); }
.q-card.needs-work b { color: var(--warn); }
.table-wrap { overflow-x: auto; }

/* findings, as cards */
.finding { border: 1px solid var(--line); border-left: 4px solid var(--muted); border-radius: var(--radius-sm); padding: 12px 16px; display: grid; gap: 6px; min-width: 0; }
.finding.warn { border-left-color: var(--warn); }
.finding.error { border-left-color: var(--bad); }
.finding.resolved { border-left-color: var(--ok); background: var(--tint); }
.finding p { margin: 0; font-size: var(--fs-3); }
.f-top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px; }
.finding code { overflow-wrap: anywhere; }
.f-sev { font-size: var(--fs-1); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.finding.warn .f-sev { color: var(--warn); }
.finding.error .f-sev { color: var(--bad); }
.f-kind { font-size: var(--fs-3); font-weight: 700; color: var(--ink); }
.f-subject { font-family: var(--mono); font-size: var(--fs-2); color: var(--muted); }
.f-sample { font-size: var(--fs-2); color: var(--muted); overflow-wrap: anywhere; }
.f-guide { color: var(--text); max-width: 80ch; }
.f-raw { margin-top: 6px; font-size: var(--fs-2); color: var(--muted); max-width: 80ch; }
.f-raw summary { cursor: pointer; font-weight: 700; }
.f-raw p { margin: 6px 0 0; }

/* 1 · capture */
.page-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
/* The cards in a row line up: picture, title, address and tag each share one row of the grid. */
.page-card {
  margin: 0; border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; background: var(--pane);
  display: grid; grid-row: span 4; grid-template-rows: subgrid; row-gap: 0;
}
/* The pages arrive once the light is on them (0.6 s: the board's crossfade and glide), one every 0.4 s,
   all five in before the run ends; a redraw carries them on (--run-at). */
.page-card.arriving { animation: cardIn var(--dur-3) var(--ease-enter) both; animation-delay: calc(.6s + var(--i) * .4s - var(--run-at, 0ms)); }
@keyframes cardIn { from { opacity: 0; transform: translateY(8px); } }
.pc-thumb { display: block; width: 100%; height: 150px; object-fit: cover; object-position: top; background: var(--tint); }
.pc-html { display: flex; align-items: center; justify-content: center; padding: 12px; text-align: center; font-size: var(--fs-2); font-weight: 700; color: var(--muted); border-bottom: 1px dashed var(--line); }
.page-card figcaption {
  grid-row: 2 / span 3; display: grid; grid-template-rows: subgrid; row-gap: 4px; align-items: start;
  padding: 8px 10px 10px; font-size: var(--fs-2); min-width: 0;
}
.page-card figcaption b { color: var(--ink); }
/* A page address reads as a breadcrumb, not as code: the page itself bold, the folders quiet. */
.page-path { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 5px; font-size: var(--fs-2); color: var(--muted); line-height: 1.35; overflow-wrap: anywhere; min-width: 0; }
.page-path b { font-weight: 700; color: var(--text); }
.page-path i { font-style: normal; color: var(--glow); }
.pc-tag { font-size: var(--fs-1); color: var(--grape); }
.mixes { display: flex; flex-wrap: wrap; gap: 8px; }
.mix { font-family: var(--mono); font-size: var(--fs-2); padding: 4px 12px; border-radius: var(--r-pill); background: var(--tint); }
.mix b { color: var(--grape); }

/* 2 · reference copy */
.pickers { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; min-width: 0; }
.picker { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.picker-label { font-size: var(--fs-1); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); min-width: 56px; }
.pick {
  font: inherit; font-size: var(--fs-2); font-weight: 600; color: var(--text); cursor: pointer;
  border: 1px solid var(--line); background: var(--pane); border-radius: var(--r-pill); padding: 4px 12px; max-width: 100%;
}
.pick:hover, .pick:focus-visible { border-color: var(--purple); color: var(--grape); }
.pick[aria-pressed="true"] { background: var(--grape); border-color: var(--grape); color: #fff; }
.clone-view { border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.clone-cap { padding: 8px 12px; font-size: var(--fs-2); background: var(--tint); border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
.clone-frame {
  max-height: 520px; overflow-y: auto; background: var(--tint);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; padding: 0 16px 16px;
}
/* At the phone width each picture keeps its own 375 px, the two centred. */
.clone-frame.narrow { grid-template-columns: repeat(2, minmax(0, 375px)); justify-content: center; }
.clone-col { margin: 0; min-width: 0; }
/* Each column's name stays in view while the two pictures scroll together. */
.clone-col figcaption {
  position: sticky; top: 0; z-index: 1; padding: 10px 2px 8px; background: var(--tint);
  font-size: var(--fs-2); font-weight: 800; color: var(--ink);
}
.clone-col figcaption span { margin-left: 6px; font-weight: 400; color: var(--muted); }
.clone-img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 6px; background: #fff; }
.clone-zoom { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: 6px; }
.clone-zoom:hover .clone-img, .clone-zoom:focus-visible .clone-img { border-color: var(--purple); }
.clone-zoom:focus-visible { outline: 3px solid var(--glow); outline-offset: 2px; }
/* A table is as wide as its content, not the panel: a page sits next to its page type. In the grid
   of .sc-body it must not stretch either. */
.sc-body > .table-wrap, .sc-body > .v-table, .wrap-part > .table-wrap, .wrap-part > .v-table { justify-self: start; max-width: 100%; }
.v-table { width: auto; min-width: min(100%, 640px); border-collapse: collapse; font-size: var(--fs-2); }
.v-table th.num, .v-table td.num { width: 1%; white-space: nowrap; }
/* Separate borders, so the radius (and the glow a beat puts around it) follows the corners. */
.rvs-table { border-collapse: separate; border-spacing: 0; border-radius: var(--radius-sm); }
.v-table th { text-align: left; font-size: var(--fs-1); font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); padding: 6px 28px 6px 8px; border-bottom: 1px solid var(--line); }
.v-table td { padding: 7px 28px 7px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.v-row.on td { background: var(--lavender); }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ok-mark { color: var(--ok); font-weight: 700; }
.bad-mark { color: var(--bad); font-weight: 700; }

/* 3 · templates */
.tpl-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; font-size: var(--fs-2); font-weight: 700; color: var(--ink); }
.tpl-filter input {
  flex: 1 1 220px; min-width: 0; font: inherit; font-weight: 400; font-size: var(--fs-3); color: var(--ink);
  padding: 7px 14px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--tint);
}
.tpl-list { border: 1px solid var(--line); border-radius: var(--radius-sm); max-height: 460px; overflow-y: auto; }
.tpl-row { border-top: 1px solid var(--line); }
.tpl-row:first-child { border-top: 0; }
.tpl-row[hidden] { display: none; }
.tpl-row summary { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; padding: 9px 14px; cursor: pointer; font-size: var(--fs-3); }
.tpl-row summary:hover { background: var(--lavender); }
.tpl-row summary b { color: var(--ink); }
.tpl-row summary .mono { font-size: var(--fs-1); overflow-wrap: anywhere; }
.tpl-row .badge { min-width: 76px; justify-content: center; }
.tpl-n { margin-left: auto; font-size: var(--fs-2); color: var(--muted); }
.tpl-fields { margin: 0; padding: 4px 14px 12px 34px; font-size: var(--fs-2); display: grid; gap: 3px; }
.tpl-fields code { color: var(--grape); }
.f-type { font-family: var(--mono); font-size: var(--fs-1); color: var(--ink); background: var(--tint); padding: 1px 6px; border-radius: 6px; white-space: nowrap; }
.tpl-empty { padding: 14px; }

/* 4 · naming, 5 · review — screenshots of the real Storybook */
.headline { margin: 0; font-size: var(--fs-5); color: var(--ink); }
/* The before → after reads in one glance: the HTML name at the sentence's size, struck through but readable. */
.headline code { font-size: .9em; color: var(--text); text-decoration: line-through; text-decoration-thickness: 2px; }
.headline b { color: var(--grape); }
.story-menu select {
  flex: 1 1 260px; min-width: 0; max-width: 100%; font: inherit; font-size: var(--fs-3); font-weight: 600; color: var(--ink); cursor: pointer;
  padding: 6px 12px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--pane);
}
.story-menu select:hover, .story-menu select:focus-visible { border-color: var(--purple); }
.sb-shot { margin: 0; display: grid; gap: 6px; min-width: 0; }
.sb-zoom {
  display: block; width: 100%; padding: 0; margin: 0; font: inherit; cursor: zoom-in; background: var(--tint);
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; box-shadow: var(--bloom-sm);
}
.sb-zoom:hover, .sb-zoom:focus-visible { border-color: var(--purple); }
.sb-img { display: block; width: 100%; height: auto; }
/* The Storybook screenshots are 16:9 (1920x1080 at scale 2): until the next one has loaded, its box
   keeps that shape, so a tab or story switch never makes the page shorter (and the browser never pulls the scroll up). */
.sb-shot:not(.cc-shot) .sb-img { aspect-ratio: auto 1920 / 1080; }
.sb-shot figcaption { font-size: var(--fs-2); color: var(--muted); overflow-wrap: anywhere; }
/* The ContentCreator screenshots are wide (2:1): a frame keeps them from feeling like the page itself. */
.cc-shot .sb-zoom { box-shadow: var(--bloom-sm); }
/* Every view has the same size: the box keeps its height while the next picture loads, so a switch
   never makes the page shorter (and the browser never pulls the scroll up). */
.cc-shot .sb-img { aspect-ratio: 3136 / 1488; }
.verdicts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* 7 · import */
.checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: var(--fs-3); }
.check { position: relative; padding-left: 24px; }
.check::before { position: absolute; left: 0; top: 0; font-weight: 800; }
.check.ok::before { content: "✓"; color: var(--ok); }
.check.bad::before { content: "✕"; color: var(--bad); }
.imp-rows { display: grid; gap: 8px; max-width: 560px; }
.imp-rows { max-width: 720px; }
.imp-row { display: grid; grid-template-columns: 64px 32px minmax(48px, 1fr) minmax(0, 1.6fr); align-items: center; gap: 10px; font-size: var(--fs-3); }
.imp-what { font-size: var(--fs-2); color: var(--muted); }
.media-warns { margin: 0; padding: 0; list-style: none; font-size: var(--fs-2); display: grid; gap: 6px; }
.media-warns li { display: flex; gap: 10px; align-items: baseline; padding: 7px 12px; border-radius: var(--radius-sm); border-left: 3px solid var(--warn); background: color-mix(in srgb, var(--warn) 6%, var(--pane)); color: var(--ink); }
.media-warns .f-sev { color: var(--warn); }
.imp-kind { font-family: var(--mono); font-weight: 700; color: var(--ink); }
.imp-row b { text-align: right; font-variant-numeric: tabular-nums; color: var(--grape); }
.imp-bar { height: 8px; border-radius: var(--r-pill); background: var(--lavender); overflow: hidden; }
.imp-bar > i { display: block; height: 100%; width: 100%; background: var(--rail-grad); }
.imp-row.filling .imp-bar > i { animation: fill .6s ease-out both; animation-delay: calc(var(--i) * .6s - var(--run-at, 0ms)); }

@media (max-width: 900px) {
  .v-table { font-size: var(--fs-2); }
  .v-table th:nth-child(4), .v-table td:nth-child(4) { display: none; }
}

/* ── Phase 2 showcases ──────────────────────────────────────────────────── */
.seam { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 18px; align-items: stretch; }
.seam-col { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 16px 18px; background: var(--pane); }
.seam-col:first-child { background: var(--lavender); border-color: transparent; }
.seam-list { margin: 0; padding-left: 18px; font-size: var(--fs-3); }
.seam-list li + li { margin-top: 6px; }
.seam-arrow { align-self: center; font-size: var(--fs-6); color: var(--purple); font-weight: 800; }
.pt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
/* The cards in a row line up: name and address, confidence, sections and reason each share a row. */
.pt-card {
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 14px 16px; display: grid; gap: 8px;
  grid-row: span 4; grid-template-rows: subgrid; animation: cardIn var(--dur-3) var(--ease-enter) both;
}
.pt-card > * { align-self: start; }
.pt-top { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; }
.pt-top b { color: var(--ink); }
.pt-card p { margin: 0; }
.pt-conf { display: flex; align-items: center; gap: 10px; font-size: var(--fs-2); }
.conf { flex: 0 0 90px; height: 6px; border-radius: var(--r-pill); background: var(--tint); overflow: hidden; }
.conf i { display: block; height: 100%; background: var(--rail-grad); animation: fill var(--dur-4) var(--ease-standard) both; }
.pills { display: flex; flex-wrap: wrap; gap: 5px; }
.pill { font-size: var(--fs-1); font-family: var(--mono); padding: 1px 8px; border-radius: var(--r-pill); background: var(--lavender); color: var(--grape); }
.table-wrap.tall { max-height: 360px; overflow-y: auto; }
.val-head { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; font-size: var(--fs-3); }
.val-row.untyped td { background: color-mix(in srgb, var(--bad) 6%, var(--pane)); color: var(--bad); }
.val-row.dismissed td { color: var(--muted); }
.val-row.dismissed td:first-child { text-decoration: line-through; }
.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 18px; }
.tree { list-style: none; margin: 0; padding: 0; font-size: var(--fs-3); }
.tree-item { padding: 4px 0 4px calc(var(--d, 0) * 20px); color: var(--ink); }
.tree-item span { color: var(--purple); }
.principles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.principle { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 14px 16px; }
.principle b { color: var(--ink); }
.principle p { margin: 6px 0 0; font-size: var(--fs-2); }
.split-bar { display: flex; height: 14px; border-radius: var(--r-pill); overflow: hidden; background: var(--tint); }
.split-bar i { display: block; height: 100%; animation: fill var(--dur-4) var(--ease-standard) both; }
.split-bar .ref, .legend i.ref { background: var(--rail-grad); }
.split-bar .abs, .legend i.abs { background: var(--sim); }
.legend { display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: var(--fs-2); align-items: center; }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: middle; }
.l-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.l-row { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); font-size: var(--fs-2); overflow-wrap: anywhere; }
.l-row code { overflow-wrap: anywhere; }
.big-nums { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; border-radius: var(--radius-sm); }
.deliv-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 1100px) { .deliv-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .deliv-grid { grid-template-columns: 1fr; } }
.deliv-card { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 14px 16px; background: var(--pane); box-shadow: var(--bloom-sm); animation: cardIn var(--dur-3) var(--ease-enter) both; }
.deliv-card .kicker { color: var(--ok); margin-bottom: 4px; }
.deliv-card b { color: var(--ink); }
.deliv-card p { margin: 4px 0 0; font-size: var(--fs-2); }
.deliv-card.todo { box-shadow: none; border-style: dashed; opacity: .6; }
.deliv-card.todo .kicker { color: var(--muted); }
.limits { margin: 0; padding-left: 18px; font-size: var(--fs-3); }
/* A step the run has not reached: its head with a neutral chip, and outlines of what is to come. */
.coming-head .kicker { color: var(--muted); }
.coming-skel { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.coming-skel i, .coming-lines i { display: block; background: var(--tint); border-radius: var(--radius-sm); }
.coming-skel i { height: 72px; border: 1px dashed var(--line); }
.coming-lines { display: grid; gap: 8px; }
.coming-lines i { height: 10px; width: 62%; }
.coming-lines i + i { width: 38%; }

/* ── tabs: findings, templates ──────────────────────────────────────────── */
.real-findings { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 10px 14px; }
.real-findings summary { cursor: pointer; font-weight: 700; color: var(--ink); font-size: var(--fs-3); }
.real-findings[open] summary { margin-bottom: 10px; }
.rf-row .f-sev { font-size: var(--fs-1); font-weight: 800; text-transform: uppercase; letter-spacing: .08em; }
.rf-row.error .f-sev { color: var(--bad); }
.rf-row.warn .f-sev { color: var(--warn); }
.q-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; border-radius: var(--radius-sm); }
.q-card { animation: cardIn var(--dur-3) var(--ease-enter) both; }
.q-card p { margin: 4px 0 0; }

/* ── an enlarged screenshot ─────────────────────────────────────────────── */
.zoom {
  position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center;
  padding: 56px 16px 16px; background: rgba(26, 22, 22, .82); cursor: zoom-out; animation: fadeIn var(--dur-2) var(--ease-enter) both;
}
.zoom img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--radius-sm); box-shadow: var(--bloom); background: #fff; }
.zoom-close { position: absolute; top: 12px; right: 16px; }
/* A captured page (the copy check): its own width, the whole length to scroll. */
.zoom.page { display: block; overflow-y: auto; }
.zoom.page img { max-height: none; margin: 0 auto; }
.zoom.page .zoom-close { position: fixed; }

/* ── the tour panel ─────────────────────────────────────────────────────── */
#tour { position: fixed; right: 20px; bottom: calc(20px + env(safe-area-inset-bottom, 0px)); z-index: 30; width: 380px; max-width: calc(100vw - 32px); }
#tour:has(.tour-pill) { width: auto; }
.tour-card { position: relative; padding: 18px 20px 14px; box-shadow: var(--bloom); max-height: calc(100vh - 40px); overflow-y: auto; }
/* The grip says the top bar moves the panel. */
.tour-grip {
  position: absolute; top: 6px; left: 50%; width: 36px; height: 4px; margin-left: -18px; border-radius: 2px;
  background: var(--line); transition: background var(--dur-1) var(--ease-standard);
}
.tour-drag:hover .tour-grip, #tour.dragging .tour-grip { background: var(--glow); }
.tour-top { display: flex; align-items: center; gap: 10px; }
.tour-top .kicker { margin: 0; color: var(--grape); flex: 1 1 auto; }
.tour-pos { font-size: var(--fs-2); font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.icon-btn {
  border: 1px solid var(--line); background: var(--pane); color: var(--ink); width: 26px; height: 26px; border-radius: 50%;
  font: inherit; font-weight: 800; line-height: 1; cursor: pointer; padding: 0;
}
.icon-btn:hover, .icon-btn:focus-visible { border-color: var(--purple); color: var(--grape); }
/* A scroll area the keyboard can reach (the copy-check picture, the sections table). */
.clone-frame:focus-visible, .table-wrap:focus-visible { outline: 3px solid var(--glow); outline-offset: 3px; }
/* Where the focus goes when the control that had it is gone with a redraw. */
.tour-title:focus { outline: none; }
.tour-title:focus-visible { outline: 3px solid var(--glow); outline-offset: 4px; border-radius: 6px; }
.tour-title { margin: 8px 0 6px; font-size: var(--fs-5); font-weight: 800; letter-spacing: -.02em; color: var(--ink); line-height: 1.25; }
.tour-say { margin: 0; padding-left: 18px; font-size: var(--fs-3); }
.tour-say li + li { margin-top: 3px; }
.tour-say li::marker { color: var(--purple); }
.tour-notes { margin: 10px 0 0; padding: 10px 12px; border-radius: var(--radius-sm); background: var(--lavender); font-size: var(--fs-3); line-height: 1.5; color: var(--ink); }
/* A beat without notes says so, quietly. */
.tour-notes.none { padding: 8px 12px; background: none; border: 1px dashed var(--line); font-size: var(--fs-2); color: var(--muted); }
.icon-btn.on { border-color: var(--purple); color: var(--grape); background: var(--lavender); }
.icon-btn svg { display: block; margin: auto; }
/* Progress: a bar per chapter, a tick per beat. A tick is 24 px tall to hit; only its middle 6 px is drawn. */
.tour-progress { position: relative; display: flex; gap: 6px; margin: 8px 0 6px; }
/* The beat under the pointer, named over the bar at once (bindTickTips). */
.tour-tip {
  position: absolute; bottom: calc(100% + 2px); white-space: nowrap; pointer-events: none;
  padding: 4px 8px; border-radius: 6px; background: var(--ink); color: #fff; font-size: var(--fs-1); font-weight: 700;
}
.tour-tip[hidden] { display: none; }
.tour-ch { display: flex; min-width: 0; }
.tick { flex: 1 1 0; min-width: 0; height: 24px; padding: 0 1px; border: 0; border-radius: 4px; background: none; cursor: pointer; }
.tick::before {
  content: ''; display: block; height: 6px; border-radius: 3px; background: var(--line);
  transition: background var(--dur-1) var(--ease-standard);
}
.tick.seen::before { background: var(--glow); }
.tick[aria-current="step"]::before { background: var(--purple); box-shadow: 0 0 0 2px var(--lavender-2); }
.tick:hover::before { background: var(--grape); }
.tick:focus-visible { outline: 2px solid var(--grape); outline-offset: 0; }
/* Up next: the beat after this one, so the speaker can lead into it. */
.tour-next { margin: 0 0 8px; font-size: var(--fs-2); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tour-next-k { margin-right: 4px; font-size: var(--fs-1); font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--grape); }
.tour-nav { display: flex; gap: 8px; align-items: center; }
.tour-nav [data-act="next"] { margin-left: auto; }
/* An on/off button (Notes, Pulse, Dim): framed like any button, lavender while on. */
.btn-toggle[aria-pressed="true"] { background: var(--lavender); color: var(--grape); border-color: var(--glow); }
.btn-toggle kbd { font: 600 var(--fs-1) var(--mono); color: var(--muted); }
.tour-settings { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.tour-settings[hidden] { display: none; }
.tour-jump { display: block; }
.tour-jump select {
  width: 100%; font: inherit; font-size: var(--fs-2); color: var(--ink); padding: 6px 10px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--tint);
}
.tour-fx { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.tour-fx-head { display: block; font-size: var(--fs-1); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.tour-fx-row { display: flex; gap: 8px; margin-top: 6px; }
/* The keys in two lines: stepping, then the rest. */
.tour-keys { margin: 8px 0 0; }
.tour-keys span { display: block; }
/* "Press R again": a short question above the panel, gone after RESET_ASK_MS. */
.tour-ask {
  margin: 0 0 8px; padding: 8px 14px; border-radius: var(--radius-sm); background: var(--ink); color: #fff;
  font-size: var(--fs-2); font-weight: 700; box-shadow: var(--bloom); animation: fadeIn var(--dur-2) var(--ease-enter) both;
}
.tour-ask kbd { font-family: var(--mono); padding: 0 6px; border: 1px solid rgba(255, 255, 255, .4); border-radius: 4px; }
.tour-pill {
  display: inline-flex; align-items: center; gap: 6px; border: 0; cursor: pointer; font: inherit; font-size: var(--fs-2); font-weight: 700;
  color: #fff; background: var(--rail-grad); padding: 10px 18px; border-radius: var(--r-pill); box-shadow: var(--bloom);
}
.tour-pill:focus-visible { outline: 3px solid var(--glow); outline-offset: 2px; }
/* The top bar moves the panel; popped out into its own window, the window moves instead. */
.tour-drag { cursor: grab; touch-action: none; user-select: none; }
#tour.dragging .tour-drag { cursor: grabbing; }
.tour-pip { margin: 0; background: var(--pane); }
.tour-pip #tour { position: static; width: auto; max-width: none; }
.tour-pip .tour-card { max-height: none; min-height: 100vh; border-radius: 0; box-shadow: none; }
.tour-pip .tour-drag { cursor: default; }
/* Up to 1440px the docked panel takes less of the demo: narrower, a size smaller, the notes in a
   scroll area that fades out at its foot. */
@media (max-width: 1440px) {
  #tour { width: 360px; }
  .tour-card { padding: 14px 16px 12px; }
  .tour-top .kicker { white-space: nowrap; }
  .tour-title { margin: 6px 0 4px; font-size: var(--fs-4); }
  .tour-say { font-size: var(--fs-2); }
  .tour-notes:not(.none) {
    max-height: 8em; overflow-y: auto;
    -webkit-mask-image: linear-gradient(#000 calc(100% - 22px), transparent); mask-image: linear-gradient(#000 calc(100% - 22px), transparent);
  }
  /* Popped out, the panel is the presenter's own window: full size there. */
  .tour-pip .tour-title { font-size: var(--fs-5); }
  .tour-pip .tour-say { font-size: var(--fs-3); }
  .tour-pip .tour-notes:not(.none) { max-height: none; -webkit-mask-image: none; mask-image: none; }
}

@media (max-width: 900px) {
  .seam { grid-template-columns: 1fr; }
  .seam-arrow { transform: rotate(90deg); justify-self: center; }
  #tour { right: 16px; left: 16px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); width: auto; max-width: none; }
  #tour:has(.tour-pill) { left: auto; }
  .tour-card { max-height: 46vh; padding: 14px 16px 12px; }
  /* Room for the panel at its tallest (46vh), so the end of the page is never under it. */
  body.tour-open .pane, body.tour-open .hub { padding-bottom: calc(46vh + 24px); }
  .tour-keys { display: none; }
  .tour-drag { cursor: default; }
  .tour-grip { display: none; }
}

/* ── motion ──────────────────────────────────────────────────────────────── */
/* Cards and bars play their entrance when they arrive: on a new beat, tab, step or phase. Any other
   render (N, T, P, D, a picker) shows them as they are; `still` is set by render() in js/app.js. */
/* What a beat brings into the phase detail fades in softly instead of cutting; the board around it
   stays still. A redraw that brings nothing new (body.still) shows it as it is. */
.tabs .tabpanel { animation: panelIn var(--dur-2) var(--ease-enter) both; }
@keyframes panelIn { from { opacity: 0; } }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--dur-3); animation-timing-function: var(--ease-standard); }
body.still .pt-card, body.still .deliv-card, body.still .q-card, body.still .conf i, body.still .split-bar i, body.still .tour-off, body.still .tabs .tabpanel { animation: none; }
/* The same panel on the next beat: its parts stay as they are; only the glow (.pulsing) plays. */
body.panel-still .tabs .tabpanel, body.panel-still .tabs .tabpanel *:not(.pulsing) { animation: none; }
.wrap-part { display: grid; gap: 14px; min-width: 0; }
.wrap-part + .wrap-part { margin-top: 18px; padding-top: 22px; border-top: 1px solid var(--line); }
@keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes statePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(189, 46, 255, .45); }
  50% { box-shadow: 0 0 0 8px rgba(189, 46, 255, 0); }
}
/* What a beat changed glows: in over 300 ms, held to 1.8 s, out over 900 ms (--dur-highlight). The
   start and end are the element's own shadow, so a tile that already has one glides into the glow
   and back instead of losing it first. `--fx-at`, a negative delay, lets a render while it plays
   join the glow where it stands instead of starting it over. */
@keyframes beatGlow {
  11%, 67% { box-shadow: 0 0 0 3px rgba(189, 46, 255, .32), 0 0 24px 4px rgba(189, 46, 255, .24); }
}
.pulsing { animation: beatGlow var(--dur-highlight) var(--ease-standard) both; animation-delay: var(--fx-at, 0s); }
/* A selected tile's ring is an inset shadow; the glow keeps it, or it would blink off for the glow. */
@keyframes beatGlowSelected {
  11%, 67% { box-shadow: inset 0 0 0 2px var(--glow), 0 0 0 3px rgba(189, 46, 255, .32), 0 0 24px 4px rgba(189, 46, 255, .24); }
}
.step.selected.pulsing { animation-name: beatGlowSelected; }
/* The soft spotlight around it (Dim, D): in over 450 ms, held while the glow holds, out over 900 ms.
   Its mask, cut by highlight() in js/app.js, feathers the holes. Interrupted (D, the element goes),
   it lets go from where it stands over --dur-2 instead of vanishing; the presenter moving on
   crossfades it to the page's second sheet around the new change. */
.dim {
  display: none; position: absolute; top: 0; left: 0; z-index: 25; pointer-events: none;
  background: rgba(10, 6, 20, .36); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.dim.on { display: block; animation: dimFade var(--dur-highlight) linear both; animation-delay: var(--fx-at, 0s); }
.dim.out { display: block; transition: opacity var(--dur-2) var(--ease-exit); }
/* While a step runs, the light leads: it fades in on the running step (DIM_IN_MS) and holds until the
   result is in, when it crossfades over to what changed. */
.dim.on.hold { animation-name: dimHold; animation-duration: var(--dur-3); }
@keyframes dimHold {
  0% { opacity: 0; animation-timing-function: cubic-bezier(0, 0, .2, 1); }  /* --ease-enter */
  100% { opacity: 1; }
}
@keyframes dimFade {
  0% { opacity: 0; animation-timing-function: cubic-bezier(0, 0, .2, 1); }    /* --ease-enter */
  17% { opacity: 1; }
  67% { opacity: 1; animation-timing-function: cubic-bezier(.4, 0, .2, 1); }  /* --ease-standard */
  100% { opacity: 0; }
}
@keyframes pulse { 0% { transform: scale(.75); opacity: .55; } 100% { transform: scale(1.5); opacity: 0; } }
@keyframes fill { from { width: 0; } }
@keyframes fadeIn { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition: none !important; }
  /* No motion, but still a mark: a still ring on what changed while the highlight lasts, and no
     sudden dark. An outline, not a box-shadow: a selected or running step tile sets its own. */
  .pulsing { outline: 3px solid rgba(189, 46, 255, .5); outline-offset: 3px; }
  .dim.on, .dim.out { display: none; }
  /* A bar that stays running stands still at half, without sliding; the line under it says it runs. */
  .run-bar.ongoing > i { width: 50%; transform: none; }
}

/* ── narrow ──────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .band { padding: 16px 0 14px; }
  /* The fourteen tiles keep their row: on a narrow screen the rail scrolls sideways inside its card. */
  /* It fades out at the right edge and says so below: the rest is a swipe away. The grid ends in a
     strip as wide as the fade, so the last tile clears it once scrolled to the end. */
  .rail-scroll {
    overflow-x: auto; padding-bottom: 6px;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 72px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 72px), transparent);
  }
  .stage-grid { min-width: 1232px; padding-right: 72px; }
  .rail-hint { display: block; }
  .tabs > .tabpanel { padding: 18px 16px 22px; }
  .card { padding: 20px; }
  .hub { padding-top: 24px; }
  .hub h1 { font-size: var(--fs-6); }
  .hub-alts { grid-template-columns: 1fr; }
  .side-run { flex: 1 1 100%; order: 5; flex-wrap: wrap; }
  .app-nav { flex-wrap: wrap; }
}
