/* Duet Playground — shared stylesheet. Tokens and components follow demo.duetlabs.co (assets/site.css, viewer.css,
   mini-timeline.css, insights.css). Self-hosted only: system fonts, graph-paper.png and duet-square.png next to the pages. */
:root {
  color-scheme: light;
  --bg: #FAFCFC;
  --panel: #FFFFFF;
  --surface-2: #F8FAFC;
  --pressed: #F1F5F9;
  --ink: #0F172A;
  --ink-hover: #24344D;
  --on-fill: #FFFFFF;
  --secondary: #475569;
  --muted: #5F6F84;
  --border: #E2E8F0;
  --border-mid: #CBD5E1;
  --border-strong: #94A3B8;
  --accent: #2563EB;
  --accent-hover: #1D4ED8;
  --pastel-lavender: #E4E4FF;
  --pastel-mint: #E4FFE4;
  --pastel-blush: #FFE4E4;
  --pastel-gray: #E4E4E4;
  --pastel-yellow: #FFFFE4;
  --a: #8A4848;
  --b: #545493;
  --a-soft: var(--pastel-blush);
  --b-soft: var(--pastel-lavender);
  --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* --header-row: the brand / nav row. --header-height: the whole sticky header; playground-ui.js keeps it equal to the
     measured .site-header height (status row and wrapped rows included). Only things outside the header use it. */
  --header-row: 62px;
  --header-height: 62px;
  --toolbar-height: 0px;  /* the page's sticky toolbar (main.page > .toolbar), measured by playground-ui.js */
  /* what a panel that sticks under the header leaves above it for that toolbar: the toolbar's 8px offset, its measured
     height (a wrapped toolbar included) and the 12px grid gap; only the offset where the toolbar is not sticky (<= 920px) */
  --toolbar-stack: calc(8px + var(--toolbar-height) + 12px);
  /* status colours (text on white ≥ 4.5:1); *-ink = text on the matching pastel */
  --ok: #15803D;
  --warn: #A16207;
  --bad: #B91C1C;
  --ok-ink: #166534;
  --bad-ink: #991B1B;
  --warn-bg: #FFF8EB;
  --warn-border: #EAD5AB;
  --warn-ink: #714B13;
  /* chart series (metrics page); adjacent bars and the not-visible strip keep ≥ 3:1 against white (WCAG 1.4.11) */
  --chart-1: #2563EB;
  --chart-2: #B45309;
  --chart-3: #0E9F8E;
  --chart-4: #6D46B8;
  --chart-dim: #94A3B8;
  /* mid-strength pastel fills for thin canvas strips and lane bars (dark text stays ≥ 4.5:1 on them; also legible on the
     dark theme's panels, so they are not overridden there) */
  --fill-green: #86CBA3;
  --fill-yellow: #E8D871;
  --fill-gray: #C6CDD6;
  --fill-lavender: #B9B9EC;
  --fill-blush: #F2BFBF;
  --fill-blue: #9DB7E0;
  --fill-tan: #D6BC8A;
  --fill-violet: #BDB6D8;
  --fill-rose: #DDA59D;
  --fill-red: #F0A3A3;
  /* names the page scripts still read (inline var() and getComputedStyle) */
  --line: var(--border);
  --mute: var(--muted);
  /* 2D video-overlay colours: drawn on black video, unchanged */
  --left: #57E39B;
  --right: #FF6B6B;
  --partner: #FFB36B;
  --body: #B58CFF;
  --obj: #3EA7FF;
  --held: #FFD447;
  font-family: var(--sans);
  font-synthesis: none;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--ink);
  background: var(--bg);
  font-size: 13px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
/* Dark theme for the long labelling pages (Timeline, Review): playground-ui.js sets data-theme="dark" on <html>.
   Screen only, so a printout stays light. Status colours are lightened to keep ≥ 4.5:1 on the dark panels. */
@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #0E1312;
    --panel: #151C1A;
    --surface-2: #1A2321;
    --pressed: #1F2A27;
    --ink: #E6ECE9;
    --ink-hover: #C9D3CE;
    --on-fill: #0E1312;
    --secondary: #B7C1BC;
    --muted: #8A9591;
    --border: #26302D;
    --border-mid: #34403C;
    --border-strong: #4D5B56;
    --accent: #7DA6FF;
    --accent-hover: #A3C0FF;
    --pastel-lavender: #25254A;
    --pastel-mint: #17331F;
    --pastel-blush: #3D1E1E;
    --pastel-gray: #2A302E;
    --pastel-yellow: #33301A;
    --a: #E2A3A3;
    --b: #ABABEE;
    --ok: #4ADE80;
    --warn: #FBBF24;
    --bad: #F87171;
    --ok-ink: #A7F3C0;
    --bad-ink: #FECACA;
    --warn-bg: #2A2312;
    --warn-border: #5E4B1E;
    --warn-ink: #F5D78E;
    --chart-1: #7DA6FF;
    --chart-2: #E39A4F;
    --chart-3: #2DC7B3;
    --chart-4: #B993EC;
    --chart-dim: #6B7A75;
  }
  :root[data-theme="dark"] body { background-image: none; }
  :root[data-theme="dark"] .badge:is(.handover, .auto, .joint_work, .reviewed, .request, .waiting, .error) { border-color: var(--border-mid); color: var(--ink); }
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-padding-top: calc(var(--header-height) + 16px); }
body {
  margin: 0;
  min-width: 320px;
  background-color: var(--bg);
  background-image: linear-gradient(rgba(255,255,255,.72), rgba(255,255,255,.72)), url('./graph-paper.png');
  background-position: left top;
  background-size: 256px 256px;
  background-repeat: repeat;
}
h1, h2, h3, h4, p, figure, dl, dd { margin: 0; }
h1, h2, h3, h4 { line-height: 1.2; letter-spacing: -.025em; }
a { color: var(--accent); text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }
button, input, select, textarea { font: inherit; }
button, select, summary { cursor: pointer; }
button { color: inherit; }
button:disabled { cursor: default; }
:is(button, a, input, select, textarea, summary, [tabindex]):focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
button, a, input, select { -webkit-tap-highlight-color: transparent; }
video, canvas, img, svg { max-width: 100%; }
video { display: block; }
[hidden] { display: none !important; }
table { border-collapse: collapse; font-variant-numeric: tabular-nums; }
th { text-align: left; font-weight: 600; }
.mono { font-family: var(--sans); font-variant-numeric: tabular-nums; }
.mute, .muted { color: var(--muted); }
.bad { color: var(--bad); }
.warn { color: var(--warn); }
.ok { color: var(--ok); }
/* visually hidden, still read by screen readers (the per-page <h1>, file inputs behind their labels) */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

/* ---------- header (shared by the seven pages) ---------- */
.site-header { position: sticky; top: 0; z-index: 20; background: var(--panel); border-bottom: 1px solid var(--border); }
.header-inner { max-width: 1440px; margin: 0 auto; padding: 0 32px; min-height: var(--header-row); display: flex; align-items: center; flex-wrap: wrap; gap: 0 24px; }
.brand { display: inline-flex; align-items: center; gap: 9px; min-height: var(--header-row); text-decoration: none; color: var(--ink); flex-shrink: 0; }
.brand img { width: 28px; height: 28px; border-radius: 6px; }
.brand span { font-size: 22px; font-weight: 700; letter-spacing: -.055em; }
.brand small { margin-left: 2px; padding: 1px 7px; border: 1px solid var(--border); border-radius: 5px; color: var(--secondary); font-size: 12px; font-weight: 500; line-height: 18px; letter-spacing: 0; }
.section-nav { display: flex; align-items: center; gap: 20px; min-width: 0; }
.section-nav a { position: relative; display: inline-flex; align-items: center; min-height: var(--header-row); white-space: nowrap; font-size: 14px; font-weight: 550; text-decoration: none; color: var(--secondary); }
.section-nav a:hover, .section-nav a[aria-current="page"] { color: var(--ink); }
.section-nav a[aria-current="page"]::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--accent); }
.section-nav a:focus-visible { outline-offset: -3px; }  /* the nav scrolls, so an outside ring would be clipped */
.section-nav::-webkit-scrollbar { display: none; }
.header-tools { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin-left: auto; padding: 9px 0; }
.header-tools label { color: var(--secondary); white-space: nowrap; }
.header-tools select { max-width: 240px; }
.header-tools form { display: inline-flex; align-items: center; gap: 8px; }
/* theme switch: playground-ui.js appends it to .header-tools (header-button height, quieter text). It names the current
   theme ("Theme: dark", aria-pressed = dark); the fixed width keeps the header from shifting when it flips. */
.theme-toggle { flex-shrink: 0; min-width: 92px; color: var(--secondary); font-size: 12px; font-weight: 600; }
.header-tools .theme-toggle { padding: 7px 10px; }
.theme-toggle:hover { color: var(--ink); }
#msg { flex-basis: 100%; padding: 0 0 9px; font-size: 12px; line-height: 1.5; color: var(--secondary); }
#msg:empty { display: none; }
#msg.bad { color: var(--bad); }
#msg .retry { min-height: 26px; margin-left: 10px; padding: 2px 9px; font-size: 12px; vertical-align: middle; }
.header-status #msg .retry { margin-left: 8px; }
/* status row under the brand / nav row: stage state, run state, #msg; hidden while all of them are empty */
.header-status { display: none; flex-basis: 100%; flex-wrap: wrap; align-items: baseline; gap: 4px 16px; padding: 0 0 9px; font-size: 12px; line-height: 1.5; }
.header-status:has(> :not(:empty)) { display: flex; }
.header-status #msg { flex-basis: auto; padding: 0; }
#runstate, #stageinfo { font-size: 12px; }
#runstate:empty, #stageinfo:empty { display: none; }

/* ---------- page shell ---------- */
.page { display: flex; flex-direction: column; gap: 12px; max-width: 1440px; margin: 0 auto; padding: 12px 32px 40px; }
.page > * { min-width: 0; }
.grid { display: grid; gap: 12px; align-items: start; }
.grid > * { min-width: 0; }
.viewer-grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
.timeline-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); }
.review-grid { grid-template-columns: minmax(0, 3fr) minmax(300px, 2fr); }
.annotate-grid { grid-template-columns: minmax(320px, 3fr) minmax(0, 4fr); }
.two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.two.wide-left { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.wide { grid-column: 1 / -1; }
.spacer { flex: 1; }
#content { display: flex; flex-direction: column; gap: 12px; }
.page-footer { margin-top: 12px; padding-top: 16px; border-top: 1px solid var(--border); color: var(--muted); font-size: 12px; line-height: 1.5; }
.page-footer:empty { display: none; }

/* ---------- panels ---------- */
.panel { min-width: 0; padding: 14px 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; }
.panel h3 { margin: 0 0 10px; font-size: 15px; font-weight: 650; line-height: 1.3; letter-spacing: -.015em; color: var(--ink); }
.panel > h3:not(:first-child) { margin-top: 14px; }
.panel-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 16px; margin-bottom: 10px; }
.panel-head h3 { margin: 0; }
.panel-head .legend, .panel-head .row { margin: 0; }
.row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.row:first-child, .panel > h3 + .row, .panel-head + .row { margin-top: 0; }
.hint { font-size: 12px; line-height: 1.5; color: var(--secondary); }
p.hint { margin: 8px 0 0; }
.empty { padding: 24px; color: var(--secondary); text-align: center; overflow-wrap: anywhere; }
.notice { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px; padding: 16px 20px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; color: var(--secondary); font-size: 13px; line-height: 1.5; }
.notice p { flex: 1 1 240px; margin: 0; overflow-wrap: anywhere; }
.notice-error { border-color: var(--warn-border); background: var(--warn-bg); color: var(--warn-ink); }

/* empty state: a title, one sentence, an optional command (<code> or <pre><code>) and an optional button */
.empty-state { display: grid; justify-items: start; gap: 8px; text-align: left; }
.panel.empty-state { padding: 22px 24px; }
.empty-state > * { max-width: 78ch; }
.empty-state-title, .empty-state > :is(h2, h3, h4) { margin: 0; font-size: 15px; font-weight: 650; line-height: 1.3; letter-spacing: -.015em; color: var(--ink); }
.empty-state p { margin: 0; color: var(--secondary); line-height: 1.55; overflow-wrap: anywhere; }
.empty-state code { -webkit-box-decoration-break: clone; box-decoration-break: clone; padding: 1px 5px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface-2); color: var(--ink); font-family: var(--mono); font-size: 12px; }
.empty-state pre { width: 100%; max-height: none; padding: 9px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-2); color: var(--ink); font-size: 12px; }
.empty-state pre code { padding: 0; border: 0; background: none; }
.empty-state button { margin-top: 4px; }
/* a command block with a Copy button in its corner (pair labels): one command per line, scrolled sideways, never wrapped */
.empty-state > .cmd { position: relative; width: 100%; max-width: 100%; }
.cmd pre { padding-right: 84px; overflow-x: auto; white-space: pre; scrollbar-width: thin; }
.cmd .copy { position: absolute; top: 5px; right: 6px; min-height: 26px; margin: 0; padding: 2px 10px; font-size: 12px; }
.empty-state > p.hint { margin: 2px 0 0; }
.panel > .empty-state:only-child { padding: 6px 8px; }  /* pair labels: pairlabel.js fills #empty (a .panel) with one */
#list > .empty-state { padding: 22px 24px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; }  /* annotations: no keyframes yet */

/* sign-in card (playground-ui.js renders it on a token-protected server before the session exists) */
.login-panel { align-self: center; display: grid; gap: 12px; width: min(100%, 440px); margin: 48px auto; padding: 24px 24px 22px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 12px 32px rgba(15, 23, 42, .06); text-align: left; }
.login-panel :is(h1, h2, h3) { margin: 0; font-size: 18px; font-weight: 650; line-height: 1.3; letter-spacing: -.02em; color: var(--ink); }
.login-panel p { margin: 0; color: var(--secondary); line-height: 1.55; overflow-wrap: anywhere; }
.login-panel form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 4px 0 0; }
.login-panel form input:not([type="checkbox"]):not([type="hidden"]) { flex: 1 1 200px; min-height: 36px; }
.login-panel button { min-height: 36px; padding: 7px 16px; font-weight: 600; }
.login-panel > p:first-child { color: var(--ink); font-size: 14px; font-weight: 600; }
.login-panel.notice-error { border-color: var(--warn-border); }
.login-error { padding: 8px 10px; border: 1px solid var(--warn-border); border-radius: 6px; background: var(--warn-bg); color: var(--warn-ink); }
.login-panel .login-error { color: var(--warn-ink); }

/* ---------- controls ---------- */
button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 32px; padding: 5px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--ink); font-size: 13px; font-weight: 500; line-height: 20px; white-space: nowrap; }
button:hover { border-color: var(--border-strong); }
button.primary { background: var(--ink); border-color: var(--ink); color: var(--on-fill); font-weight: 600; }
button.primary:hover { background: var(--ink-hover); border-color: var(--ink-hover); }
button.armed { background: var(--bad); border-color: var(--bad); color: var(--on-fill); }
button[aria-pressed="true"] { border-color: var(--border-strong); background: var(--pressed); font-weight: 600; }
.header-tools button { min-height: 36px; padding: 7px 14px; border-radius: 7px; font-weight: 600; }
.header-tools button.primary { padding: 7px 16px; }
input:not([type="checkbox"]):not([type="range"]):not([type="file"]), select, textarea { min-height: 32px; padding: 5px 9px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--ink); font-size: 13px; }
input:not([type="checkbox"]):not([type="range"]):not([type="file"]):hover, select:hover, textarea:hover { border-color: var(--border-strong); }
input[type="number"] { width: 72px; }
input[type="checkbox"] { width: 15px; height: 15px; margin: 0; accent-color: var(--accent); }
input[type="range"] { accent-color: var(--accent); }
textarea { width: 100%; min-height: 36px; resize: vertical; }
label { display: inline-flex; align-items: center; gap: 6px; color: var(--secondary); }
kbd { display: inline-block; min-width: 18px; padding: 0 5px; border: 1px solid var(--border-mid); border-bottom-width: 2px; border-radius: 4px; background: var(--surface-2); color: var(--ink); font-family: var(--sans); font-size: 11px; line-height: 16px; text-align: center; }
progress { accent-color: var(--accent); }

/* play / scrub / speed toolbar (viewer.css .vw-toolbar) */
.toolbar { position: sticky; top: calc(var(--header-height) + 8px); z-index: 5; display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; padding: 8px 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; }
#play { min-width: 86px; min-height: 36px; padding: 7px 12px; border-color: var(--accent); background: var(--accent); color: var(--on-fill); font-size: 14px; font-weight: 600; }
#play:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
#scrub { flex: 1; min-width: 70px; height: 30px; margin: 0; cursor: pointer; }
#tlabel, #clock { font-size: 14px; color: var(--secondary); white-space: nowrap; font-variant-numeric: tabular-nums; }
#tlabel { min-width: 110px; text-align: right; }
.toolbar #tlabel { margin-left: auto; }
#transport #tlabel { margin-left: 0; }
/* speed buttons: every one has a border; the pressed one gets a 2 px ring, ink text and bold, so state is not colour alone */
#rates { display: inline-flex; align-items: center; gap: 3px; }
#rates button { min-width: 37px; padding: 5px 6px; border-color: var(--border); border-radius: 5px; background: transparent; color: var(--secondary); font-size: 14px; }
#rates button:hover { border-color: var(--border-strong); color: var(--ink); }
#rates button[aria-pressed="true"] { border-color: var(--border-strong); box-shadow: inset 0 0 0 1px var(--border-strong); background: var(--panel); color: var(--ink); font-weight: 650; }

/* disabled: full opacity, muted text on a quiet surface (an ink "Save edits" at 45 % opacity read as an enabled grey button) */
button:disabled, button:disabled:hover, button.primary:disabled, button[aria-pressed="true"]:disabled, #play:disabled { color: var(--muted); background: var(--surface-2); border-color: var(--border); }

/* ---------- tables ---------- */
table { width: 100%; font-size: 13px; line-height: 1.45; }
th, td { padding: 5px 8px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: middle; }
th:first-child, td:first-child { padding-left: 0; }
th:last-child, td:last-child { padding-right: 0; }
thead th { padding-top: 0; padding-bottom: 6px; color: var(--secondary); font-size: 12px; font-weight: 500; white-space: nowrap; }
tbody tr:last-child > * { border-bottom: 0; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.empty { padding: 16px 0; }
.tablewrap { max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; }

/* ---------- legends ---------- */
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12px; line-height: 1.5; color: var(--secondary); }
.legend > span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { display: inline-block; flex-shrink: 0; width: 13px; height: 9px; border-radius: 2px; box-shadow: inset 0 0 0 1px rgba(71, 85, 105, .33); }
.panel > .legend { margin-top: 10px; }
.legend + .legend { margin-top: 6px; }

/* ---------- metric cards (insights.css .tl-metrics) ---------- */
/* auto-fit collapses empty tracks: 7 cards sit in one row from about 1030 px up, 5 cards from about 750 px */
#cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); overflow: hidden; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; }
#cards:empty { display: none; }
.card { display: flex; flex-direction: column; gap: 2px; min-width: 0; margin: -1px 0 0 -1px; padding: 14px 18px; border-top: 1px solid var(--border); border-left: 1px solid var(--border); }
.card h3 { order: 2; margin: 0; font-size: 13px; font-weight: 500; line-height: 1.4; letter-spacing: 0; color: var(--ink); }
.card .v { order: 1; font-size: 28px; font-weight: 650; line-height: 1.15; letter-spacing: -.02em; color: var(--ink); font-variant-numeric: tabular-nums; }
.card .v small { margin-left: 4px; font-size: 14px; font-weight: 500; color: var(--secondary); }
.card .sub { order: 3; font-size: 12px; line-height: 1.4; color: var(--secondary); }
#cards .empty { grid-column: 1 / -1; }
/* never leave one card alone on a row: 7 cards (metrics) as 4 + 3, 5 cards (optimize) as 3 + 2, phones two per row */
@media (min-width: 641px) and (max-width: 1040px) { #cards:has(> .card:nth-child(7):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 641px) and (max-width: 760px) { #cards:has(> .card:nth-child(5):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  #cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #cards > .card:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* ---------- badges (annotations coordination type, optimize finding basis) ---------- */
.badge { display: inline-block; padding: 1px 7px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--secondary); font-size: 11px; line-height: 16px; white-space: nowrap; }
.badge.handover, .badge.auto { border-color: #B6B087; background: var(--pastel-yellow); color: #625D30; }
.badge.joint_work, .badge.reviewed { border-color: #8AAB8A; background: var(--pastel-mint); color: #2F5D34; }
.badge.request { border-color: #ABAAC3; background: var(--pastel-lavender); color: var(--b); }
.badge.waiting { border-color: #A5A5A5; background: var(--pastel-gray); color: #334155; }
.badge.error { border-color: #B6A0A0; background: var(--pastel-blush); color: var(--a); }

/* ---------- video surfaces: black 16:9, overlay canvas above ---------- */
.view { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: #000; border-radius: 10px; }
.view video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.view canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.tag { position: absolute; left: 10px; bottom: 8px; display: inline-flex; align-items: center; gap: 6px; padding: 2px 7px; border-radius: 4px; background: rgba(0, 0, 0, .6); color: #fff; font-size: 12px; line-height: 1.5; }
.tag b { font-weight: 600; color: #fff; }
.tag .warn { color: #FCD34D; }
.view[data-participant="a"] .tag::before, .view[data-participant="b"] .tag::before { content: ''; flex: 0 0 7px; width: 7px; height: 7px; border-radius: 50%; background: var(--a); box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .75); }
.view[data-participant="b"] .tag::before { background: var(--b); }

/* ---------- viewer page ---------- */
/* stage chips: one row that scrolls sideways (about 30 px instead of three wrapped rows). While chips are cut off, app.js
   fades the cut edge(s) and shows a "+N more" chip after the row; it expands the row to all chips (wrapped). */
#stagebar { display: flex; align-items: flex-start; gap: 6px; min-width: 0; }
#stagebar:has(> #stages:empty) { display: none; }
#stages { flex: 1 1 auto; display: flex; flex-wrap: nowrap; gap: 6px; min-width: 0; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; padding-bottom: 2px; }
#stages.fade-right { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent); }
#stages.fade-left { -webkit-mask-image: linear-gradient(to right, transparent, #000 48px); mask-image: linear-gradient(to right, transparent, #000 48px); }
#stages.fade-left.fade-right { -webkit-mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent); mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent); }
#stages.expanded { flex-wrap: wrap; overflow: visible; -webkit-mask-image: none; mask-image: none; }
#stagesMore { flex: 0 0 auto; min-height: 0; padding: 3px 11px; border-radius: 999px; color: var(--accent); font-size: 12px; font-weight: 600; line-height: 18px; }
#stagesMore:hover { border-color: var(--accent); }
.stage { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px; padding: 3px 10px 3px 8px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); font-size: 12px; color: var(--ink); white-space: nowrap; }
.stage .state { color: var(--muted); }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--border-mid); }
.done .dot { background: var(--accent); }
.running .dot, .queued .dot { background: var(--chart-2); animation: pulse 1s infinite; }
.failed .dot, .interrupted .dot { background: var(--bad); }
.skipped .dot, .stale .dot { background: var(--border-mid); }
@keyframes pulse { 50% { opacity: .3; } }
#egos { display: grid; gap: 12px; }
#exopanel:not(:has(.view)) { display: none; }
#exos { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
#side { display: grid; gap: 12px; align-content: start; }
#three { display: block; width: 100%; aspect-ratio: 4 / 3; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; }
#threeView { min-height: 28px; padding: 3px 24px 3px 8px; font-size: 12px; }
#threeNote { margin-top: 6px; }
#notes { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 12px; line-height: 1.55; color: var(--secondary); }
#uploader { padding: 0 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; }
#uploader > summary { display: flex; align-items: center; min-height: 44px; list-style: none; color: var(--accent); font-size: 13px; font-weight: 600; }
#uploader > summary::-webkit-details-marker { display: none; }
#uploadForm { display: grid; gap: 10px; max-width: 900px; padding: 2px 0 16px; }
#dropZone { padding: 18px; border: 1px dashed var(--border-strong); border-radius: 8px; background: var(--surface-2); color: var(--secondary); text-align: center; }
#dropZone label { display: inline; color: var(--accent); font-weight: 600; cursor: pointer; }
#dropZone label:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 3px; }  /* the file inputs are keyboard-focusable but visually hidden */
.upopts { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
#upName { width: 200px; }
#upRef { max-width: 360px; }
#upFps { width: 64px; }
#upPlan { display: grid; gap: 8px; }
#upPlan:empty { display: none; }
.uprow { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 12px; }
.upPerson { width: 160px; }
.uprow input, .uprow select { min-height: 28px; padding: 3px 6px; }
.upEpisode { border-radius: 8px !important; padding: 8px 10px !important; }
.upsubmit { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
#upProgress { width: 220px; }
#syncPanel { padding: 14px 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; }
.sync-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.sync-head b { color: var(--warn); }
.sync-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; margin-top: 10px; }
.sync-grid > div { min-width: 0; }
.syncSide video { width: 100%; aspect-ratio: 16 / 9; margin-top: 4px; background: #000; border-radius: 10px; }
.sync-ctl { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.sync-off { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
#syncOffset { width: 120px; }
#attribution { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---------- timeline page ---------- */
@media (min-width: 901px) { .timeline-grid:has(> .panel.dual) { grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr); } }
#video, #video2 { display: block; width: 100%; aspect-ratio: 16 / 9; max-height: 50vh; background: #000; border-radius: 10px; object-fit: contain; }
#videos.dual { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }
.vname { height: 18px; margin: 0 0 4px; overflow: hidden; color: var(--secondary); font-size: 12px; line-height: 18px; white-space: nowrap; text-overflow: ellipsis; }
button.vname { display: block; max-width: 100%; min-height: 0; padding: 0; border: 0; border-radius: 0; background: none; color: var(--ink); font-weight: 500; text-align: left; }
button.vname:hover { color: var(--accent); text-decoration: underline; }
.vwrap { position: relative; }
#video2 { cursor: pointer; }
#video2.gap { opacity: .35; }
#v2note { position: absolute; left: 8px; top: 8px; padding: 2px 7px; border-radius: 4px; background: rgba(15, 23, 42, .85); color: #FCD34D; font-size: 12px; pointer-events: none; }
#gantt { display: block; width: 100%; cursor: crosshair; touch-action: pan-y; }
#viewbar button { min-width: 32px; padding: 4px 9px; }
#viewinfo { font-size: 12px; }
#selinfo { font-size: 13px; }
#kpis { font-size: 13px; line-height: 1.6; }
#kpis b { color: var(--ink); font-weight: 600; }
#steps input[type="text"] { width: 100%; min-width: 70px; min-height: 28px; padding: 3px 6px; }
#steps select { min-height: 28px; padding: 3px 4px; }
#steps button { min-height: 28px; padding: 2px 7px; }
#taskTitle { width: 320px; max-width: 100%; }
ul.errors { margin: 6px 0; padding-left: 18px; color: var(--bad); font-size: 12px; }
ul.errors:empty { display: none; }
#dirty { color: var(--warn); }
#dirty:empty, #stalewarn:empty, #savestate:empty, #taskstate:empty { display: none; }
#rq tbody tr { cursor: pointer; }
#rq tbody tr:hover { background: var(--surface-2); }
/* the time cell's role="button" span is the row's keyboard control (timeline.js renderQueue); the row tints while it has focus */
#rq td [role="button"] { border-radius: 3px; }
#rq td [role="button"]:hover { color: var(--accent); }
#rq tbody tr:has(:focus-visible) { background: var(--surface-2); }
#rq tr.cur { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--pressed); }  /* current item: tint + outline, not width alone */
#rq tr.done { color: var(--muted); }
#rq .kind-disagreement { color: var(--warn); }  /* timeline.js sets kind-<kind> on the "why" cell */
#rqConf { width: 72px; }
.scroll-y { max-height: 260px; overflow-y: auto; }
/* keyboard shortcuts: collapsed under the lanes so the review queue stays close */
.keyhelp { margin-top: 10px; }
.keyhelp > summary { width: fit-content; color: var(--secondary); font-size: 12px; font-weight: 550; }
.keyhelp > summary:hover { color: var(--ink); }
#keys { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 3px 14px; margin: 8px 0 0; padding: 0; list-style: none; }
#keys li.mouse { grid-column: 1 / -1; }
#newTaskId { width: 220px; }

/* ---------- review page ---------- */
#progress { flex: 1 1 160px; height: 6px; overflow: hidden; border-radius: 3px; background: var(--border); }
#progress i { display: block; width: 0; height: 100%; background: var(--accent); transition: width .15s; }
#ptext { flex-basis: 100%; font-size: 12px; color: var(--secondary); }
#ptext:empty { display: none; }
#frac, #seed { width: 72px; }
#frame { position: relative; align-self: start; overflow: hidden; background: #000; border-radius: 10px; }
#canvas { display: block; width: 100%; height: auto; }
#frame .tag { top: 8px; bottom: auto; }
/* no frame yet (before a sample loads, or an empty sample): review.js leaves #pos empty then */
.empty-state.frame-empty { display: none; padding: 20px 2px 8px; }
.review-grid:has(#pos:empty) .empty-state.frame-empty { display: grid; }
.review-grid:has(#pos:empty) #frame { display: none; }
.vrow { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 8px; align-items: center; padding: 7px 0; border-bottom: 1px solid var(--border); }
.vrow:first-child { padding-top: 0; }
.vrow .lbl { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-weight: 500; }
.vrow .lbl i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; box-shadow: inset 0 0 0 1px rgba(71, 85, 105, .33); }
.vrow .lbl small { flex-basis: 100%; color: var(--muted); font-size: 12px; font-weight: 400; }
.vrow .btns { display: flex; flex-wrap: wrap; gap: 6px; }
.vrow kbd, #nav kbd { color: var(--secondary); }
button.v-ok.on { border-color: var(--ok); background: var(--pastel-mint); color: var(--ok-ink); }
button.v-wrong.on { border-color: var(--bad); background: var(--pastel-blush); color: var(--bad-ink); }
button.v-unsure.on { border-color: var(--warn); background: var(--pastel-yellow); color: var(--warn-ink); }
#note { margin-top: 10px; }
#nav { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
#pos, #status { font-size: 12px; color: var(--secondary); }
/* the verdict column stays in view beside the frame while the page scrolls (wide screens: the grid has two columns):
   sticky under the sticky toolbar (--toolbar-stack follows its measured height, so a toolbar wrapped to more rows in a
   narrow window does not cover the column; 901-920px: the toolbar scrolls away, the column sticks under the header), at
   most as tall as the window between that point and the page's 40px bottom padding (so the grid's end never pushes it
   back under the toolbar), with its own scrollbar for the proposals and the summary */
@media (min-width: 901px) {
  .review-grid > aside#side { position: sticky; top: calc(var(--header-height) + var(--toolbar-stack)); max-height: calc(100vh - var(--header-height) - var(--toolbar-stack) - 40px); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
}
.prop { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 7px 0; border-bottom: 1px solid var(--border); }
/* title, then the meta (time · giver → receiver · conf): the meta never breaks inside; it moves under the title as a whole
   and ends in an ellipsis in a column narrower than itself (full text in its tooltip); a long title shrinks the same way */
.prop-text { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; min-width: 0; }
.prop-text > b, .prop .meta { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prop .meta { color: var(--muted); font-size: 12px; }
.prop .st { flex-basis: 100%; }
.prop .btns { display: flex; gap: 6px; }
.prop:first-child { padding-top: 0; }
.prop:last-child { padding-bottom: 0; border-bottom: 0; }
.prop .st { font-size: 12px; color: var(--muted); }
.prop .st.accepted { color: var(--ok); }
.prop .st.rejected { color: var(--bad); }

/* ---------- annotations page ---------- */
#meta { display: flex; flex-wrap: wrap; gap: 4px 18px; font-size: 12px; color: var(--secondary); }
#meta:empty { display: none; }
#list { display: grid; gap: 8px; align-content: start; max-height: calc(100vh - var(--header-height) - 72px); overflow: auto; padding-right: 4px; scrollbar-width: thin; }
.item { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 12px; padding: 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--panel); cursor: pointer; }
.item:hover { border-color: var(--border-strong); }
.item.active { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.item img { width: 150px; aspect-ratio: 1.28; object-fit: cover; background: #000; border-radius: 6px; }
.item .t { color: var(--ink); font-weight: 600; }
.item .sum { margin: 3px 0; }
.item .row { display: block; margin: 0; color: var(--secondary); font-size: 12px; }
.item .badge, #dSummary .badge { margin-right: 6px; }
aside#detail { position: sticky; top: calc(var(--header-height) + 16px); display: grid; gap: 12px; align-self: start; }
/* contact sheet: a fixed 16:9 box (tiles letterboxed), hidden until annotate.js sets a src */
#big { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: contain; background: #000; border-radius: 10px; }
#big:not([src]), #big[src=""] { display: none; }
#dSummary { margin-bottom: 8px; }
#dHandover { margin-top: 8px; color: var(--secondary); }
details.panel > summary { color: var(--secondary); font-weight: 500; }
details.panel[open] > summary { margin-bottom: 8px; }
pre { margin: 0; max-height: 260px; overflow: auto; color: var(--secondary); font-family: var(--mono); font-size: 11px; line-height: 1.5; white-space: pre-wrap; }

/* ---------- metrics page ---------- */
#perMinute { height: 220px; }
#timeline { height: 150px; }  /* fixed like #perMinute: metrics.js sizes the backing store from the CSS box */
#score { margin-bottom: 8px; font-size: 34px; font-weight: 650; line-height: 1.1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
#components table { font-size: 13px; }
#formula { margin-top: 8px; color: var(--secondary); font-size: 12px; overflow-wrap: anywhere; }
canvas.chart { display: block; width: 100%; }

/* ---------- optimize page ---------- */
#reportTitle { font-size: 17px; font-weight: 650; line-height: 1.3; letter-spacing: -.02em; }
#reportTitle:empty { display: none; }
#banner { padding: 12px 16px; border: 1px solid var(--warn-border); border-radius: 8px; background: var(--warn-bg); color: var(--warn-ink); }
.sev { margin: 14px 0 2px; font-size: 12px; font-weight: 600; color: var(--secondary); }
.sev:first-child { margin-top: 0; }
.finding { position: relative; padding: 9px 0 9px 18px; border-top: 1px solid var(--border); break-inside: avoid; }
.finding::before { content: ''; position: absolute; left: 0; top: 15px; width: 8px; height: 8px; border-radius: 50%; background: var(--border-mid); }
.finding.sev-high::before { background: var(--bad); }
.finding.sev-warn::before { background: var(--chart-2); }
.finding.sev-info::before { background: var(--border-strong); }
.finding .t { font-weight: 600; color: var(--ink); }
.finding .m { margin: 2px 0; color: var(--secondary); font-size: 12px; }
.finding .ev { margin-top: 2px; font-size: 12px; }
.finding .ev a { margin-right: 12px; font-weight: 600; text-decoration: none; }
.finding .ev a:hover { text-decoration: underline; }
.finding .badge { margin-left: 6px; vertical-align: 2px; }
#thresholds { font-size: 12px; overflow-wrap: anywhere; }
#excluded ul { margin: 0; padding-left: 16px; }

/* ---------- pair labels page ---------- */
#state { font-size: 12px; color: var(--secondary); overflow-wrap: anywhere; }
#state:empty { display: none; }
#bar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-bottom: 12px; }
#bar .hint { margin-left: auto; }  /* the toolbar's right end */
.vidgrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }
.vidgrid figure { margin: 0; min-width: 0; }
.vidgrid video { display: block; width: 100%; max-height: 44vh; background: #000; border-radius: 10px; }
.vidgrid figcaption { display: flex; align-items: center; gap: 7px; margin-top: 5px; font-size: 13px; font-weight: 600; color: var(--ink); }
.vidgrid figure[data-participant="a"] figcaption::before, .vidgrid figure[data-participant="b"] figcaption::before { content: ''; flex: 0 0 7px; width: 7px; height: 7px; border-radius: 50%; background: var(--a); }
.vidgrid figure[data-participant="b"] figcaption::before { background: var(--b); }
.vidgrid .empty { display: flex; align-items: center; justify-content: center; aspect-ratio: 16 / 9; border: 1px dashed var(--border); border-radius: 10px; }
#lanes { display: block; width: 100%; cursor: crosshair; touch-action: none; }
dl#detail, dl#prov { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 3px 14px; }
dl#detail dt, dl#prov dt { color: var(--secondary); }
dl#detail dd, dl#prov dd { margin: 0; overflow-wrap: anywhere; }
ul#findings, ul#gaps { margin: 0; padding-left: 16px; }
ul#findings li, ul#gaps li { margin: 2px 0; overflow-wrap: anywhere; }

/* ---------- breakpoints (site.css: 1120 / 920 / 640; grids collapse at 900) ---------- */
/* >= 921 px: one row (brand, nav, tools, theme switch) whenever it fits, which is every page from 1280 px up. Below that
   the tools wrap under the nav instead of squeezing it: a basis-0 nav would scroll most page links out of sight at
   1024 px (233 of 493 px visible on the viewer). The sticky offsets follow the measured --header-height either way. */
@media (min-width: 921px) and (max-width: 1440px) {
  .header-inner { gap: 0 14px; }
  .section-nav { gap: 12px; }
  .header-tools { gap: 8px; }
  .header-tools select { max-width: 190px; }
  .header-tools:has(#runAll) select { max-width: 140px; }  /* the viewer carries two actions and the theme switch */
}
/* short laptop screens: letterbox the timeline video so the Gantt lanes stay on the first screen */
@media (min-width: 901px) and (max-height: 720px) {
  #video, #video2 { max-height: 32vh; }
}
@media (max-width: 1120px) {
  .header-inner { padding: 0 24px; }
  .page { padding-left: 24px; padding-right: 24px; }
}
@media (max-width: 920px) {
  :root { --header-row: 48px; --header-height: 104px; --toolbar-stack: 8px; }  /* the toolbar is not sticky here (below) */
  .header-inner { min-height: 64px; gap: 0 12px; padding-top: 6px; }
  .section-nav { order: 3; flex-basis: 100%; width: 0; margin-left: 0; overflow-x: auto; scrollbar-width: none; gap: 20px; }
  .header-tools { padding: 4px 0; }
  #msg, .header-status { order: 4; }
  /* the two-row header is already sticky; a sticky toolbar under it would cost a third of a short screen */
  .toolbar { position: relative; top: auto; }
}
@media (max-width: 900px) {
  .viewer-grid, .timeline-grid, .review-grid, .annotate-grid, .two, .two.wide-left, .vidgrid, .sync-grid { grid-template-columns: minmax(0, 1fr); }
  #list { max-height: none; }
  aside#detail { position: static; }
}
@media (max-width: 640px) {
  .header-inner { padding-left: 16px; padding-right: 16px; }
  .brand span { font-size: 20px; }
  .brand small { display: none; }
  .section-nav { gap: 14px; }
  .section-nav a { font-size: 12px; }
  .page { padding-left: 16px; padding-right: 16px; }
  #tlabel { min-width: 0; }
}
@media (max-width: 600px) {
  #videos.dual { grid-template-columns: minmax(0, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
@media print {
  body { background: #fff; }
  .site-header { position: static; border-bottom: 1px solid #999; }
  .section-nav, .header-tools, .header-status, #stageinfo, #runstate, select, button, label.pick, #msg, .toolbar { display: none !important; }
  .scroll-y, pre, #list { max-height: none; overflow: visible; }
  /* swatches and dots carry meaning: print their colours even with background printing off */
  .legend i, .vrow .lbl i, .badge, .dot, .finding::before, .vidgrid figcaption::before, kbd { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  aside#detail { position: static; }
  .panel, .card, .finding { break-inside: avoid; background: #fff; }
  #banner { background: #fff; }
  a { color: #111; }
}
