/* AI Animation Studio — operator UI.
 *
 * Deliberately dependency-free: no build step, no CDN, no outbound request of
 * any kind. It has to work on a DGX Spark with no network, served straight off
 * the API, so Archivo ships as two woff2 files beside this stylesheet.
 *
 * The Modernist system this implements: light ground, a single red accent spent
 * sparingly, Archivo throughout, zero corner radius anywhere, 2px rules as the
 * only separator, everything flush left including button labels, and content
 * imagery printed in black and white.
 *
 * Alignment is the discipline. Two gutters and nothing else: 24px in the main
 * column, 16px in the sidebar and inside every bordered box. A card's rule sits
 * on the 24px gutter and its contents sit 16px inside it, so headings, table
 * cells and stat labels all land on the same line. Type comes from one scale
 * and spacing from one scale; nothing off those scales appears below.
 */

/* Archivo as the variable latin subsets — one file per range covers the whole
   100-900 axis, so every weight is a real instance and never a synthesised
   bold. unicode-range means the browser fetches latin-ext only if it needs it. */
@font-face {
  font-family: "Archivo";
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  src: url(fonts/archivo-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+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  src: url(fonts/archivo-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: light;

  --bg: #f3f2f2;
  --surface: #eae9e9;
  --ink: #201e1d;
  --accent: #ec3013;
  --divider: color-mix(in srgb, #201e1d 40%, transparent);

  --n-100: #f8f4f4;
  --n-200: #eae7e7;
  --n-300: #d7d3d3;
  --n-400: #bab6b6;
  --n-500: #9b9797;
  --n-600: #7d7979;
  --n-700: #605d5d;
  --n-800: #444141;
  --n-900: #2d2b2b;

  --a-100: #fff2ef;
  --a-200: #ffe0d9;
  --a-600: #dd2b0f;
  --a-700: #ae1800;

  /* Semantic state is carried by weight and fill, not by a second hue. The
     accent is the only colour in the system, so "needs a person" is accent and
     everything else is ink or neutral. */
  --ok: var(--ink);
  --warn: var(--n-700);
  --error: var(--accent);

  --sans: "Archivo", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --t-h1: 42px;
  --t-h2: 32px;
  --t-h3: 25px;
  --t-h4: 20px;
  --t-body: 15px;
  --t-sm: 13px;
  --t-xs: 11px;
  --t-micro: 10px;

  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-6: 24px; --s-8: 32px;

  --gutter: 24px;
  --inset: 16px;
  --rule: 2px;
  --rail: 232px;
}

/* Dark theme: the same system with ink and paper swapped. The ground takes
   the ink value, text takes the paper value, and the neutral ramp reverses so
   every component keeps its contrast relationships — an "ink fill" pill
   becomes a paper fill. The accent stays #ec3013 for fills; where the light
   theme darkens it for hover text, the dark theme brightens it instead,
   because darker red vanishes against a dark ground. The UI follows the OS
   preference — there is no per-app toggle to stamp. */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --bg: #1d1b1a;
    --surface: #282524;
    --ink: #f0eeec;
    --divider: color-mix(in srgb, #f0eeec 34%, transparent);

    --n-100: #2d2b2b;
    --n-200: #444141;
    --n-300: #4c4948;
    --n-400: #7d7979;
    --n-500: #9b9797;
    --n-600: #aba7a6;
    --n-700: #c9c5c4;
    --n-800: #e5e2e1;
    --n-900: #f8f4f4;

    --a-100: #3b1712;
    --a-200: #521d15;
    --a-600: #ff563c;
    --a-700: #ff8f77;
  }
}

*, *::before, *::after { box-sizing: border-box; }

html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--a-200); }
:focus-visible { outline: var(--rule) solid var(--accent); outline-offset: 2px; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--n-400); }
::-webkit-scrollbar-track { background: var(--n-200); }

/* ---- layout ------------------------------------------------------------ */

.app { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); min-height: 100vh; }

.sidebar {
  border-right: var(--rule) solid var(--divider);
  padding: 0;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.brand {
  padding: var(--s-4) var(--inset);
  border-bottom: var(--rule) solid var(--divider);
  display: flex; align-items: center; gap: var(--s-3);
}
/* The accent square is the mark. It sets the sidebar's 16px line, which every
   nav label and every meter below it then sits on. */
.brand::before { content: ""; width: 18px; height: 18px; background: var(--accent); flex-shrink: 0; }
.brand h1 {
  font-size: var(--t-body); font-weight: 800; margin: 0;
  letter-spacing: -0.01em; line-height: 1.15; text-transform: uppercase;
}
.brand span {
  display: block; font-size: var(--t-micro); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--n-600); font-weight: 500;
}

.nav { display: flex; flex-direction: column; padding: var(--s-3) 0; }
.nav button {
  position: relative;
  background: none; border: 0; color: var(--ink); text-align: left;
  padding: var(--s-2) var(--inset); border-radius: 0; cursor: pointer;
  font-size: var(--t-sm); font-weight: 500; font-family: inherit;
  display: flex; align-items: center; gap: var(--s-2);
}
/* The accent bar bleeds to the sidebar edge so the label itself stays flush on
   the 16px line rather than being pushed off it by an indicator. */
.nav button::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px; background: transparent;
}
.nav button:hover { background: var(--a-100); }
.nav button.active { background: var(--a-100); color: var(--a-700); font-weight: 700; }
.nav button.active::before { background: var(--accent); }
/* Symbol glyphs are off-system here; the accent bar carries selection instead. */
.nav button .glyph { display: none; }

.sidebar-footer {
  margin-top: auto; padding: var(--s-4) var(--inset);
  border-top: var(--rule) solid var(--divider);
  display: flex; flex-direction: column; gap: var(--s-3);
}

.main { padding: var(--gutter) var(--gutter) 64px; max-width: 1600px; overflow-x: hidden; }

header.page {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-6); flex-wrap: wrap;
  padding-bottom: var(--s-4); border-bottom: var(--rule) solid var(--divider);
}
header.page h2 { margin: 0; font-size: var(--t-h3); font-weight: 800; letter-spacing: -0.015em; }
header.page .sub { color: var(--n-700); font-size: var(--t-sm); }
header.page .spacer { flex: 1 1 auto; }

/* ---- primitives -------------------------------------------------------- */

.grid { display: grid; gap: var(--s-6); align-items: start; }
.grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); }

.card {
  background: transparent;
  border: var(--rule) solid var(--divider);
  border-radius: 0;
  padding: var(--inset);
}
.card h3 {
  margin: 0 0 var(--s-3); font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--n-600); font-weight: 700;
}

.stat { display: flex; flex-direction: column; gap: 2px; }
.stat .value {
  font-size: var(--t-h2); font-weight: 800; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; line-height: 1.15;
}
.stat .label {
  font-size: var(--t-micro); color: var(--n-600); text-transform: uppercase;
  letter-spacing: 0.12em; font-weight: 700;
}
.stat .note { font-size: var(--t-xs); color: var(--n-700); }

button.btn {
  background: transparent; color: var(--ink);
  border: var(--rule) solid var(--ink);
  padding: 7px 12px; border-radius: 0; cursor: pointer;
  font-size: var(--t-xs); font-weight: 700; font-family: inherit;
  letter-spacing: 0.08em; text-transform: uppercase; text-align: left; white-space: nowrap;
}
button.btn:hover:not(:disabled) { background: var(--a-100); border-color: var(--accent); color: var(--a-700); }
button.btn:active:not(:disabled) { background: var(--a-200); }
/* A disabled control loses the accent entirely rather than wearing a faded
   version of it — a washed-out red reads as broken, not inert. */
button.btn:disabled {
  opacity: 1; cursor: not-allowed;
  background: transparent; border-color: var(--n-300); color: var(--n-500);
}
button.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button.btn.primary:hover:not(:disabled) { background: var(--a-600); border-color: var(--a-600); color: #fff; }
button.btn.danger:hover:not(:disabled) { background: var(--ink); border-color: var(--ink); color: var(--n-100); }
button.btn.small { padding: 4px 8px; letter-spacing: 0.06em; }

.row { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }

/* Cell inset equals the card inset, so a table inside a card lines its first
   column up with the card's own title. */
table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
th {
  text-align: left; padding: var(--s-2) var(--inset); color: var(--n-600);
  font-weight: 700; font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: 0.1em; border-bottom: var(--rule) solid var(--divider);
  white-space: nowrap; background: var(--surface);
}
td { padding: 10px var(--inset); border-bottom: 1px solid var(--n-300); vertical-align: top; }
tr:last-child td { border-bottom: 0; }
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: var(--a-100); }

.mono { font-family: var(--mono); font-size: var(--t-xs); font-variant-numeric: tabular-nums; }
.dim { color: var(--n-700); }
.faint { color: var(--n-600); }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40ch; }

/* Square, not a pill — the system has no radius anywhere. */
.pill {
  display: inline-flex; align-items: center; gap: var(--s-1);
  padding: 3px 7px; border-radius: 0; font-size: var(--t-micro);
  font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
  background: var(--n-300); color: var(--n-800); border: 0;
}
.pill.ok { background: var(--n-800); color: var(--n-100); }
.pill.locked { background: var(--ink); color: var(--n-100); }
.pill.warn { background: transparent; color: var(--n-700); border: var(--rule) solid var(--divider); padding: 1px 5px; }
.pill.error { background: var(--accent); color: #fff; }
.pill.info { background: transparent; color: var(--n-700); border: var(--rule) solid var(--divider); padding: 1px 5px; text-transform: none; letter-spacing: 0.02em; }

.bar { height: 6px; background: var(--n-300); border-radius: 0; overflow: hidden; min-width: 88px; }
.bar > span { display: block; height: 100%; background: var(--ink); transition: width 0.3s ease; }
.bar.ok > span { background: var(--ink); }
.bar.warn > span { background: var(--n-600); }
.bar.error > span { background: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .bar > span { transition: none; }
}

/* ---- gates ------------------------------------------------------------- */

/* Ink fill means locked. A gate is a human decision, so nothing about it is
   coloured to suggest the platform reached it on its own. */
.gates { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.gate {
  flex: 1 1 168px; padding: var(--s-3) var(--inset); border-radius: 0;
  border: var(--rule) solid var(--divider); background: transparent;
}
.gate .name {
  font-size: var(--t-micro); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--n-600); font-weight: 700;
}
.gate .state { font-size: var(--t-body); font-weight: 800; margin: 2px 0 var(--s-1); letter-spacing: -0.01em; }
.gate .reason { font-size: var(--t-xs); color: var(--n-600); line-height: 1.45; }
.gate.locked { border-color: var(--ink); background: var(--ink); }
.gate.locked .name { color: var(--n-400); }
.gate.locked .state { color: var(--n-100); }
.gate.locked .reason { color: var(--n-400); }
.gate.reopened { border-color: var(--accent); background: var(--a-100); }
.gate.reopened .state { color: var(--a-700); }
.gate.reopened .reason { color: var(--n-700); }

/* ---- stage tabs -------------------------------------------------------- */

.tabs {
  display: flex; gap: 0; border-bottom: var(--rule) solid var(--divider);
  margin-bottom: var(--s-6); overflow-x: auto;
}
.tabs button {
  background: none; border: 0; border-bottom: 3px solid transparent; color: var(--n-700);
  padding: var(--s-3); cursor: pointer; font-size: var(--t-sm); font-weight: 500;
  font-family: inherit; white-space: nowrap;
}
/* The first tab sits on the main column's gutter, in line with the page title
   above it and the content below it. */
.tabs button:first-child { padding-left: 0; }
.tabs button:hover { color: var(--ink); background: var(--a-100); }
.tabs button.active { color: var(--ink); border-bottom-color: var(--accent); font-weight: 700; }
.tabs button .num {
  font-size: var(--t-micro); color: var(--n-500); margin-right: 6px;
  font-variant-numeric: tabular-nums;
}
.tabs button.active .num { color: var(--accent); }

/* ---- shots ------------------------------------------------------------- */

/* One rule grid: the container draws top and left, each cell draws right and
   bottom, so no rule is ever doubled and the frames sit edge to edge. */
.shot-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(216px, 1fr)); gap: 0;
  border-top: var(--rule) solid var(--divider); border-left: var(--rule) solid var(--divider);
}
.shot {
  background: transparent; border: 0;
  border-right: var(--rule) solid var(--divider); border-bottom: var(--rule) solid var(--divider);
  border-radius: 0; overflow: hidden; cursor: pointer;
}
.shot:hover { background: var(--a-100); }
.shot.selected { background: var(--a-100); box-shadow: inset 3px 0 0 var(--accent); }
.shot .frame {
  aspect-ratio: 4 / 3; background: var(--n-200); display: flex;
  align-items: center; justify-content: center; color: var(--n-500); font-size: var(--t-xs);
}
/* System rule: every content image prints in pure black and white. */
.shot .frame img { width: 100%; height: 100%; object-fit: cover; display: block; filter: grayscale(1) contrast(1.06); }
.shot .meta { padding: var(--s-3) var(--inset); }
.shot .slug { font-size: var(--t-sm); font-weight: 700; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }
/* Two lines exactly, whether the intent needs one or three, so the tags below
   sit on one line across the grid instead of stepping card by card. */
.shot .intent {
  font-size: var(--t-xs); color: var(--n-700); margin-top: var(--s-1); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  height: calc(2 * 1.45 * var(--t-xs));
}
.shot .tags { display: flex; gap: var(--s-1); margin-top: var(--s-2); flex-wrap: wrap; }

/* ---- inspector --------------------------------------------------------- */

.drawer {
  position: fixed; top: 0; right: 0; width: min(640px, 94vw); height: 100vh;
  background: var(--bg); border-left: var(--rule) solid var(--ink);
  overflow-y: auto; z-index: 50; box-shadow: none;
}
.drawer header {
  position: sticky; top: 0; z-index: 2; background: var(--surface);
  padding: var(--s-4) var(--gutter);
  border-bottom: var(--rule) solid var(--divider);
  display: flex; align-items: center; gap: var(--s-3);
}
.drawer header h3 { margin: 0; font-size: var(--t-h4); font-weight: 800; font-variant-numeric: tabular-nums; }
.drawer .body { padding: var(--gutter) var(--gutter) 64px; }
.drawer section { margin-bottom: var(--s-6); }
.drawer section > h4 {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--n-600); font-weight: 700; margin: 0 0 var(--s-2);
}
/* Inside the drawer there is no card rule to inset from, so tables run flush to
   the drawer's own gutter instead of inheriting the 16px cell inset. */
.drawer th:first-child, .drawer td:first-child { padding-left: 0; }
.drawer th:last-child, .drawer td:last-child { padding-right: 0; }

.kv { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 6px var(--s-4); font-size: var(--t-sm); margin: 0; }
.kv dt {
  color: var(--n-600); font-size: var(--t-micro); letter-spacing: 0.1em;
  text-transform: uppercase; font-weight: 700; padding-top: 3px;
}
.kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

pre.json {
  background: var(--surface); border: 0; border-left: 3px solid var(--divider); border-radius: 0;
  padding: var(--s-3) var(--inset); font-family: var(--mono); font-size: var(--t-xs); line-height: 1.7;
  overflow-x: auto; max-height: 340px; color: var(--n-800); margin: 0;
  font-variant-numeric: tabular-nums;
}

.candidate {
  display: flex; gap: var(--s-3); padding: var(--s-3);
  border: var(--rule) solid var(--divider); border-radius: 0;
  margin-bottom: var(--s-2); background: transparent;
}
.candidate.selected { border-color: var(--ink); }
.candidate .thumb { width: 116px; aspect-ratio: 4 / 3; background: var(--n-200); border-radius: 0; flex-shrink: 0; }
.candidate .thumb img, .candidate .thumb video {
  width: 100%; height: 100%; object-fit: cover; border-radius: 0;
  filter: grayscale(1) contrast(1.06);
}
.candidate .info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }

/* ---- script ------------------------------------------------------------ */

.scene { border: var(--rule) solid var(--divider); border-radius: 0; margin-bottom: var(--s-4); overflow: hidden; }
.scene > header {
  background: var(--surface); padding: var(--s-3) var(--inset); display: flex;
  align-items: center; gap: var(--s-3); border-bottom: var(--rule) solid var(--divider); flex-wrap: wrap;
}
.scene > header .slug { font-weight: 800; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }
.scene .lines { padding: var(--inset); }
.line { margin-bottom: var(--s-3); display: flex; gap: var(--s-4); align-items: flex-start; }
.line:last-child { margin-bottom: 0; }
.line .who {
  width: 132px; flex-shrink: 0; font-size: var(--t-micro); text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--n-600); font-weight: 700; padding-top: 4px;
}
.line .text { flex: 1; min-width: 0; }
.line .text .paren { color: var(--n-600); font-style: italic; font-size: var(--t-sm); }
.line.stage_direction .text { color: var(--n-700); font-style: italic; }
.line .prov {
  font-size: var(--t-micro); color: var(--n-500); letter-spacing: 0.08em;
  text-transform: uppercase; margin-top: 3px;
}

/* ---- misc -------------------------------------------------------------- */

.empty { padding: 48px var(--gutter); text-align: left; color: var(--n-600); border: var(--rule) solid var(--divider); }
.empty p { margin: var(--s-1) 0; max-width: 60ch; }

.toast-host {
  position: fixed; bottom: var(--gutter); right: var(--gutter);
  display: flex; flex-direction: column; gap: var(--s-2); z-index: 100;
  max-width: min(420px, calc(100vw - 48px));
}
.toast {
  background: var(--ink); color: var(--n-100); border: 0;
  border-left: 3px solid var(--n-500); border-radius: 0;
  padding: var(--s-3) var(--inset); font-size: var(--t-sm); line-height: 1.45;
}
.toast.error { border-left-color: var(--accent); }
.toast.ok { border-left-color: var(--n-100); }
@media (prefers-reduced-motion: no-preference) {
  .toast { animation: rise 0.16s ease-out; }
  @keyframes rise { from { transform: translateY(6px); opacity: 0; } }
}

.spinner {
  width: 12px; height: 12px; border: var(--rule) solid var(--n-300);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin 0.7s linear infinite; display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border-top-color: var(--accent); }
}

select, input[type="text"], textarea {
  background: var(--bg); color: var(--ink);
  border: var(--rule) solid var(--divider); border-radius: 0;
  padding: 7px 10px; font-family: inherit; font-size: var(--t-sm);
}
textarea { width: 100%; resize: vertical; min-height: 80px; line-height: 1.55; }
select:focus, input:focus, textarea:focus { outline: 0; border-color: var(--accent); }

.chat { max-height: 460px; overflow-y: auto; padding-right: 6px; }
.turn { margin-bottom: var(--s-4); }
.turn:last-child { margin-bottom: 0; }
.turn .role {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--n-600); font-weight: 700; margin-bottom: var(--s-1);
}
.turn .bubble {
  padding: var(--s-3) var(--inset); border-radius: 0;
  background: var(--surface); border-left: 3px solid var(--n-400);
  font-size: var(--t-sm);
}
.turn.interviewer .bubble { border-left-color: var(--n-400); }
.turn.creator .bubble { border-left-color: var(--accent); }

.fact {
  display: flex; gap: var(--s-3); padding: var(--s-3) 0;
  border-bottom: 1px solid var(--n-300); font-size: var(--t-sm);
}
.fact:first-child { padding-top: 0; }
.fact:last-child { border-bottom: 0; padding-bottom: 0; }
.fact .body { flex: 1; min-width: 0; }
.fact .controls { display: flex; gap: var(--s-1); flex-wrap: wrap; }

@media (max-width: 880px) {
  .app { grid-template-columns: 1fr; }
  .sidebar {
    position: static; height: auto;
    border-right: 0; border-bottom: var(--rule) solid var(--divider);
  }
  .nav { flex-direction: row; flex-wrap: wrap; }
  .nav button { flex: 1 0 auto; }
  .kv { grid-template-columns: 1fr; gap: 2px; }
  .kv dd { margin-bottom: var(--s-2); }
}
