/* UserBus studio — design system and layout.
   Dark is the default; the customer can choose and persist a light ground.
   Both palettes are measured in test/studio/design_ground_test.exs.
   Media retains a black field in either theme.

   The register is an edit suite rather than a marketing page: a monospaced face
   for anything technical, tabular figures for numbers, and a denser scale (4 · 8 ·
   12 · 16 · 24 · 32). No web fonts, no third-party requests, no gradients. */

:root {
  color-scheme: dark;

  /* Typography: one system stack, five sizes, tabular numerals for data. */
  /* THE LANDING'S OWN STACK, VERBATIM (`--sans` in landing/public/styles.css): transit signage is
     the product's voice, and it ships no font files. */
  --font-sans: "Helvetica Neue", Helvetica, Arial, "Liberation Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --fs-xs: 0.75rem;    /* 12px — metadata, chips */
  --fs-sm: 0.8125rem;  /* 13px — dense data, table cells */
  --fs-md: 0.9375rem;  /* 15px — body, controls */
  --fs-lg: 1.125rem;   /* 18px — section titles */
  --fs-xl: 1.625rem;   /* 26px — page titles */
  --lh-tight: 1.25;
  --lh-body: 1.55;

  /* Spacing scale */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  /* ---- THE PALETTE IS THE LANDING'S DARK REGISTER, TAKEN VERBATIM (2026-09-20) ----
     The studio is one product with landing/public/styles.css, and the landing HAS a dark
     register - it uses it exactly where a figure is being judged: `.calc-board` (the
     calculators' result panel) is `background: var(--black); color: var(--white)` with the
     key figures in `var(--yellow)`, `.board-section` is black with an amber "on" dot, and
     `--night-rule: #3a3a3a` is a rule colour the landing declares FOR DARK SURFACES ONLY.
     So the studio is that register, scaled from a panel to an application, and every colour
     below is the landing's own token rather than a second palette invented beside it.

     WHY NOT `#000` FOR THE PAGE: on the landing black is a BAND inside a white page; here it
     is the whole page, and at pure black every panel edge and rule must be LIGHTER than the
     surface to be seen at all - a bright grid around a dark picture. `#0a0a0a` is 1.05:1 from
     `#000` (below the threshold at which a human reads it as a second colour) and it keeps the
     picture the darkest thing on the screen. See docs/landing-language-adoption.md §2. */
  --c-bg: #0a0a0a;
  --c-bg-raised: #0f0f0f;
  --c-surface: #111111;
  --c-surface-2: #171717;
  --c-surface-3: #1f1f1f;
  --c-line: #2a2a2a;
  --c-line-strong: #3a3a3a; /* the landing's --night-rule, verbatim */

  /* Text: the landing's --white, and the greys it uses ON BLACK (.board "off" is #c9c9c9,
     .board-section's lead is #e2e2e2). */
  --c-text: #ffffff;
  --c-text-soft: #e2e2e2;
  --c-text-dim: #c9c9c9;
  --c-text-invert: #000000;

  /* THE ACCENT IS THE PRODUCT'S COLOUR: the landing's signage yellow, verbatim. */
  --c-accent: #ffd400;
  --c-accent-ink: #ffd400;
  --c-accent-strong: #ffe14d;
  --c-accent-quiet: rgba(255, 212, 0, 0.14);
  --c-accent-line: rgba(255, 212, 0, 0.45);

  /* THE SELECTED STATE (userbus-design tokens.css, 2026-09-27, userbus/docs#35): the active nav item, the
     balance pill on a billing page, a checked option. On dark it is a lighter NEUTRAL step - the translucent
     yellow over black read as a muddy yellow-brown - and the yellow stays in the icon or the edge. */
  --c-selected: #262626;
  --c-selected-line: #5c5c5c;

  /* Semantic state colours, in the landing's own vocabulary: AMBER is what the landing uses
     for "on/live" and nothing else (`.board [data-state="on"]`), `--alarm` is its negative,
     and the strong figure is the accent - so DELIVERED reads in yellow and the studio's green
     is gone, because a hue the product does not own would be the one thing on the screen that
     does not belong to it. The dashed border is the landing's "planned/unknown" mark. */
  --c-queued: #c9c9c9;
  --c-running: #ffb000;
  --c-succeeded: #ffd400;
  --c-failed: #ff8a75;
  --c-canceled: #c9c9c9;
  --c-warn: #ffb000;

  /* THE WORK IS THE HERO: media keeps a neutral black field of its own, and the
     frame it sits in is the widest thing on the page. */
  --c-media: #000000;
  --w-media: 100%;

  /* EDGES, FROM THE LANDING: its radii are 4/6/8/12/14/18 and its biggest panel (the calculator's
     card) is 14px; and it has NO DROP SHADOWS ANYWHERE - structure is carried by rules and surfaces,
     not by things that float. The studio's two shadow tokens are gone with their usages, which is the
     single biggest visual difference between the two surfaces today. */
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 14px;
  --r-pill: 999px; /* userbus-design tokens.css: a pill is a pill, whatever its height */

  /* CONTROL HEIGHTS, ONE PAIR: every button, input and select is 36px on a pointer and 44px where the
     pointer is a finger (≤720px or a coarse pointer); the large size is 44/48. The height is EXACT -
     `padding-block: 0` and a 20px line - so a 36px control measures 36, not 38.15. */
  --ctl-md: 36px;
  --ctl-lg: 44px;
  --ctl-touch: 44px;
  --ctl-touch-lg: 48px;

  /* THE BUTTON FILLS: the secondary button is a raised surface with the strong rule; the primary is the
     yellow with no edge of its own on the dark ground (the fill is the edge) and a black one on light. */
  --c-btn: var(--c-surface-2);
  --c-btn-hover: var(--c-surface-3);
  --c-primary-edge: transparent;
  --c-accent-hover: var(--c-accent-strong);

  /* THE FOCUS RING IS THE LANDING'S: 3px, offset 3px. On a dark surface the landing sets its focus
     colour to the yellow (`.calc-board`, `.strip`, `.board-section` all do `--focus: var(--yellow)`),
     which is what the studio is, so the ring is the accent. */
  --focus: 3px solid var(--c-accent-ink);
  --focus-offset: 3px;
}


:root[data-theme="light"] {
  color-scheme: light;
  --c-bg: #f7f7f7;
  --c-bg-raised: #ffffff;
  --c-surface: #ffffff;
  --c-surface-2: #f2f2f2;
  --c-surface-3: #e9e9e9;
  --c-line: #d9d9d9;
  --c-line-strong: #858585;
  --c-text: #000000;
  --c-text-soft: #000000;
  --c-text-dim: #5c5c5c;
  --c-accent-ink: #000000;
  --c-accent-line: #000000;
  --c-selected: #fff7d1;
  --c-selected-line: #000000;
  --c-queued: #5c5c5c;
  --c-running: #000000;
  --c-succeeded: #000000;
  --c-failed: #b00020;
  --c-canceled: #5c5c5c;
  --c-warn: #000000;
  /* ON WHITE a #f2f2f2 secondary reads as a muddy slab: the secondary is white with the strong rule, and
     the primary keeps the landing's black edge so the yellow holds on white. */
  --c-btn: #ffffff;
  --c-btn-hover: #f2f2f2;
  --c-primary-edge: #000000;
  --c-accent-hover: #f0c400;
}

/* Everlabs' rotating sun/moon idea, with UserBus colours and no decorative glow. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; width: 44px; height: 44px; padding: 0;
  border: 1px solid var(--c-line-strong); border-radius: 50%;
  background: var(--c-surface); color: var(--c-accent-ink); cursor: pointer;
}
.theme-toggle:hover { background: var(--c-accent); color: var(--c-text-invert); }
:root[data-theme="light"] .theme-toggle { color: #000000; border-color: #000000; background: transparent; }
:root[data-theme="light"] .theme-toggle:hover { background: var(--c-accent); }
.theme-toggle svg { width: 24px; height: 24px; fill: currentColor; transition: transform .5s ease; pointer-events: none; }
.theme-sun, .theme-moon { transition: opacity .3s ease; }
.theme-sun { opacity: 0; }
.theme-moon { opacity: 1; }
:root[data-theme="light"] .theme-toggle svg { transform: rotate(360deg); }
:root[data-theme="light"] .theme-sun { opacity: 1; }
:root[data-theme="light"] .theme-moon { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .theme-toggle svg, .theme-sun, .theme-moon { transition: none; }
}


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

html { -webkit-text-size-adjust: 100%; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  /* THE LANDING SETS TABULAR FIGURES ON THE BODY, not per element: a figure that changes width moves
     the page under the reader, and this surface is full of figures. */
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

/* THE LANDING'S OWN RULE, ADOPTED: an element carrying `hidden` is not displayed, whatever a more
   specific rule says. The app marks machine-only spans and pre-rendered error blocks with it. */
[hidden] { display: none !important; }

/* THE TRACKING IS THE LANGUAGE; THE SIZE IS THE PAGE. The landing's headings are -0.045em / -0.035em
   / -0.02em at 86px / 62px / 21px; the studio takes the TRACKING and the 700 weight and keeps its own
   sizes, because a tool's page title is not a hero. */
h1, h2, h3 { line-height: var(--lh-tight); margin: 0 0 var(--sp-3); font-weight: 700; }
h1 { letter-spacing: -0.045em; }
h2 { letter-spacing: -0.035em; }
h3 { letter-spacing: -0.02em; }
h1 { font-size: var(--fs-xl); }
h2 { font-size: var(--fs-lg); }
h3 { font-size: var(--fs-md); }
p { margin: 0 0 var(--sp-3); }
/* THE LANDING'S LINK TREATMENT, INCLUDING ITS EXEMPTION: underline thickness 0.09em and offset
   0.18em, thicker on hover - and links that are STRUCTURE (its own nav, doors and tiles) are not
   underlined at rest, only on hover. The studio keeps the accent colour on links in prose, where the
   colour is how a reader finds the action in a paragraph, and follows the landing everywhere else.

   AN UNDERLINE BELONGS TO A TEXT LINK AND TO NOTHING ELSE (2026-09-25). The two rules below used to be
   `p a, li a, dd a, …` and a bare `a:hover`, and they reached every anchor on the page: a button that is
   a link (`<a class="btn">`) underlined on hover while a `<button class="btn">` beside it did not, and a
   tile in an `<li>` underlined its title, its preview and its Open button at rest. A text link is an
   anchor with NO class of its own; a component that is an anchor (a button, a tile, a card, a nav item,
   a pill) carries a class and owns its own states - the few that do underline on hover opt in by name.
   test/studio/button_system_test.exs refuses an unscoped underline rule coming back. */
a {
  color: var(--c-accent-ink);
  text-decoration: none;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 0.09em;
}
:where(p, .lede, li, dd, .fine, .field-hint, .notice, .alert) a:not([class]) { text-decoration: underline; }
a:not([class]):hover, .link:hover, .text-link:hover, .tile-title:hover, .tile-project:hover, a.usage-title:hover {
  text-decoration: underline;
  text-decoration-thickness: 0.16em;
}

/* A VALUE IN THE MONOSPACED FACE KEEPS THE SIZE OF THE LINE IT SITS IN (0.92em evens out the mono face's
   larger x-height) and a mono space is closed to a proportional one: a monospaced space is a whole
   character cell, which is what made "1 s" read as "1  s". */
code, .mono { font-family: var(--font-mono); font-size: 0.92em; word-spacing: -0.3em; }
.num, td.num, .tabular { font-variant-numeric: tabular-nums; }

/* THE RING KEEPS THE CONTROL'S OWN SHAPE: the focus rule sets no radius, so a round control stays round
   when it is focused (it used to become a 4px square). */
:focus-visible { outline: var(--focus); outline-offset: var(--focus-offset); }

/* Media can take focus, so it must show it. */
video:focus-visible, .stage-player:focus-visible, .poster .player:focus-visible {
  outline: var(--focus);
  outline-offset: var(--focus-offset);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--sp-2);
  background: var(--c-surface);
  border: 1px solid var(--c-line-strong);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  z-index: 10;
}
.skip-link:focus { left: var(--sp-3); }

/* ---------- shell ---------- */

.app-shell { display: flex; flex-direction: column; min-height: 100vh; }

.topbar {
  background: var(--c-bg-raised);
  border-bottom: 1px solid var(--c-line);
}
.topbar-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  max-width: 1240px;
  width: 100%;
  margin: 0 auto;
  padding: var(--sp-3) var(--sp-5);
  flex-wrap: wrap;
}

.brand { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px; flex-shrink: 0; color: var(--c-text); }
.brand:hover { text-decoration: none; }
.brand-mark { flex: none; }
.brand-name { font-weight: 700; letter-spacing: -0.03em; font-size: 1.5rem; }
.brand-context { color: var(--c-text-dim); font-size: var(--fs-sm); }

.nav { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-left: var(--sp-2); }
.nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--c-text-soft);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  font-size: 1rem;
  font-weight: 500;
  white-space: nowrap;
}
/* THE LANDING'S OWN NAV TREATMENT, VERBATIM IN SPIRIT: `.strip-nav a[aria-current="page"]` is marked
   by a 3px underline in the accent with an 8px offset - not by a filled pill, which was the studio's
   generic-SaaS tell. */
.nav a:hover { color: var(--c-text); text-decoration: underline; text-decoration-thickness: 3px; text-decoration-color: var(--c-accent); text-underline-offset: 8px; }
.nav a[aria-current="page"] {
  color: var(--c-text);
  text-decoration: underline;
  text-decoration-thickness: 3px;
  text-decoration-color: var(--c-accent);
  text-underline-offset: 8px;
}

.topbar-end { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); min-width: 0; }

/* ---------- section tabs (a tab is a URL, not a widget) ---------- */

/* The strip of a page that has outgrown its own job: plain links in a nav, laid out like the bin
   strip of an edit suite - a quiet row under the page's title, where the CURRENT view is marked by
   the attribute a browser and a screen reader both read (`aria-current="page"`) and by a rule under
   it rather than by a filled pill. Nothing here is scripted, so keyboard order, "open in a new tab"
   and a bookmark all behave the way the browser already behaves. */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  border-bottom: 1px solid var(--c-line);
  margin: 0 0 var(--sp-5);
}
.tabs a {
  color: var(--c-text-soft);
  font-size: var(--fs-sm);
  font-weight: 700;
  padding: var(--sp-2) 0;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
}
.tabs a:hover { color: var(--c-text); text-decoration: none; }
/* THE CURRENT TAB IS THE LANDING'S CURRENT NAV ITEM: a 3px accent rule under it. */
.tabs a[aria-current="page"] { color: var(--c-text); border-bottom-color: var(--c-accent); }

/* A heading or a label that a screen reader needs and sight does not: the Balance tab's card keeps
   an accessible name without printing the page's own title a second time. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

main { flex: 1; padding: var(--sp-5); max-width: 1240px; width: 100%; margin: 0 auto; }

.footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  border-top: 1px solid var(--c-line);
  padding: var(--sp-4) var(--sp-5);
  color: var(--c-text-dim);
  font-size: var(--fs-xs);
  max-width: 1240px;
  margin: 0 auto;
  width: 100%;
}

.page-head { display: flex; align-items: flex-end; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-5); }
.page-head .lede { color: var(--c-text-soft); margin: 0; max-width: 62ch; }
/* A head that is only its title (All videos, userbus-studio#34): the heading sits on the grid's left edge with the
   grid's own gap below it, and no line-box slack above the first row. */
.page-head--title { margin-bottom: var(--sp-4); }
.page-head--title h1 { margin: 0; line-height: 1.15; }
.page-head .head-actions { margin-left: auto; display: flex; gap: var(--sp-2); align-items: center; }

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

.card {
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
}
.card + .card { margin-top: var(--sp-4); }
.card, .studio-grid > * { min-width: 0; }
.card-head { display: flex; align-items: baseline; gap: var(--sp-3); margin-bottom: var(--sp-4); flex-wrap: wrap; min-width: 0; }
.card-head h2 { margin: 0; }
.card-head .card-note { color: var(--c-text-dim); font-size: var(--fs-xs); margin-left: auto; }

/* ---------- buttons: ONE system (2026-09-25; docs/design-direction.md §7) ----------
   FOUR VARIANTS AND A TEXT LINK, TWO SIZES, EXACT HEIGHTS. The class names the markup already carries
   are the system's names, so nothing had to be renamed to adopt it:

     .btn                        secondary - the default; a raised surface with the strong rule
     .btn-primary                primary   - the yellow; ONE per area of a page
     .btn-quiet (= .btn-ghost)   ghost     - no fill and no edge until the pointer is on it
     .btn-danger                 danger    - an irreversible or ending action, outlined in the error red
     .link / .text-link          a standalone text link (underlined on hover only)

     size md (default)  36px, 44px where the pointer is a finger
     size .btn-lg       44px, 48px where the pointer is a finger (.btn-xl is the same size: an alias)
     .btn-block         the full width of its container - opt-in, for a form's single primary

   A BUTTON IS NEVER UNDERLINED, in any state: the underline is how a text link says it is one. The
   landing's own weight and shape stay (`.button` / `.strip-cta`: 700, 8px radius, black on yellow). */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--ctl-md);
  padding: 0 var(--sp-4);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 700;
  line-height: 20px;
  text-align: center;
  text-decoration: none;
  color: var(--c-text);
  background: var(--c-btn);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background-color 120ms ease-out, border-color 120ms ease-out, color 120ms ease-out;
}
.btn:hover, .btn:focus-visible, .btn:active { text-decoration: none; }
.btn:hover { background: var(--c-btn-hover); border-color: color-mix(in srgb, var(--c-text-dim) 60%, transparent); }
/* PRESSED: a step darker, and nothing moves. */
.btn:active { filter: brightness(0.92); }
.btn-primary { background: var(--c-accent); border-color: var(--c-primary-edge); color: var(--c-text-invert); }
.btn-primary:hover { background: var(--c-accent-hover); border-color: var(--c-primary-edge); }
/* THE QUIET BUTTON KEEPS ITS EDGE AT REST (userbus-design, Button, 2026-09-27, userbus/docs#34): "Copy the
   prompt" read as plain text on white until the pointer reached it. No fill, the strong hairline. */
.btn-quiet, .btn-ghost { background: transparent; border-color: var(--c-line-strong); color: var(--c-text-soft); }
.btn-quiet:hover, .btn-ghost:hover { background: var(--c-surface-2); border-color: var(--c-line-strong); color: var(--c-text); }
.copy-prompt { align-self: flex-start; }
/* A DESTRUCTIVE ACTION is outlined in the error colour, never the page's yellow primary. */
.btn-danger { background: transparent; border-color: var(--c-failed); color: var(--c-failed); }
.btn-danger:hover { background: color-mix(in srgb, var(--c-failed) 14%, transparent); border-color: var(--c-failed); }
.btn-lg, .btn-xl { min-height: var(--ctl-lg); padding: 0 var(--sp-5); font-size: var(--fs-md); }
.btn-block { width: 100%; }
.btn .icon { width: 16px; height: 16px; }
.btn-lg .icon, .btn-xl .icon { width: 18px; height: 18px; }
/* DISABLED IS A NEUTRAL SURFACE, NOT A FADED YELLOW: it takes no hover and no press, and its text keeps
   AA contrast (a 55% primary did not). Prefer `aria-disabled` with the reason stated beside it. */
.btn:disabled, .btn[aria-disabled="true"] {
  background: var(--c-surface-2);
  border-color: var(--c-line);
  color: var(--c-text-dim);
  cursor: not-allowed;
  filter: none;
}

/* A GROUP OF BUTTONS: a wrapping row with one 8px gap. `.primary-action`, `.head-actions`,
   `.invite-actions` is a group under its own name. */
.btn-group, .primary-action, .invite-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }

/* A STANDALONE TEXT LINK: quiet at rest, underlined when the pointer is on it. */
.link, .text-link { color: var(--c-text-soft); font-size: var(--fs-sm); }
.link:hover, .text-link:hover { color: var(--c-text); }

/* THE LANDING'S `.mark`: a pill with a dot, a 1.5px edge, and A DASHED EDGE FOR "planned/unknown"
   (`.mark-planned`, `.asks [data-state="over"]`). The studio's `not reported` marker and the timeline
   step the record cannot prove use that dash. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: var(--fs-xs);
  font-weight: 700;
  padding: 2px var(--sp-2);
  border-radius: var(--r-pill);
  border: 1.5px solid var(--c-line-strong);
  color: var(--c-text-soft);
  background: var(--c-surface-2);
  white-space: nowrap;
}
.chip::before { content: ""; width: 6px; height: 6px; border-radius: var(--r-pill); background: currentColor; }
.chip--queued { color: var(--c-queued); border-color: color-mix(in srgb, var(--c-queued) 45%, transparent); }
.chip--leased,
.chip--running { color: var(--c-running); border-color: color-mix(in srgb, var(--c-running) 45%, transparent); }
.chip--succeeded { color: var(--c-succeeded); border-color: color-mix(in srgb, var(--c-succeeded) 45%, transparent); }
.chip--failed { color: var(--c-failed); border-color: color-mix(in srgb, var(--c-failed) 45%, transparent); }
.chip--canceled { color: var(--c-canceled); border-color: color-mix(in srgb, var(--c-canceled) 45%, transparent); }
.chip--plain::before { display: none; }
.chip--unknown { border-style: dashed; }
.chip--warn { color: var(--c-warn); border-color: color-mix(in srgb, var(--c-warn) 45%, transparent); }

.muted { color: var(--c-text-dim); }
.small { font-size: var(--fs-xs); }
.stack-2 > * + * { margin-top: var(--sp-2); }
.row { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }

.alert {
  border: 1px solid var(--c-line-strong);
  /* THE LANDING'S OWN THICKNESS for a note that matters: `.entry` and `.board-warning` use a 6px left
     rule, against a 1px frame. */
  border-left-width: 6px;
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  background: var(--c-surface);
  font-size: var(--fs-sm);
}
.alert.error { border-left-color: var(--c-failed); }
.alert.notice { border-left-color: var(--c-succeeded); }
.alert.info { border-left-color: var(--c-accent-ink); }

/* ---------- forms ---------- */

.field { margin-bottom: var(--sp-4); min-width: 0; }
.field > label, .field-label { display: block; font-size: var(--fs-sm); font-weight: 550; margin-bottom: var(--sp-2); }
.field-hint { color: var(--c-text-dim); font-size: var(--fs-xs); margin: var(--sp-2) 0 0; }
.field-error { color: var(--c-failed); font-size: var(--fs-xs); margin: var(--sp-2) 0 0; }

.input, .textarea, .select {
  width: 100%;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--c-text);
  background: var(--c-bg-raised);
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  min-height: 38px;
}
.textarea { min-height: 132px; resize: vertical; line-height: var(--lh-body); }
.input[readonly], .select[disabled], .select:disabled { color: var(--c-text-soft); background: var(--c-surface-2); }
.input::placeholder, .textarea::placeholder { color: var(--c-text-dim); }
input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--c-accent-ink); }

.param-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
/* THE FRAME ROW sits on the board, so it reads as a decision rather than as an afterthought: two
   columns, and the same 12px rhythm as the grid inside the advanced disclosure. */
.param-grid.frame { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: var(--sp-4); }

fieldset { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
legend { font-size: var(--fs-sm); font-weight: 550; margin-bottom: var(--sp-2); padding: 0; }

.model-cards { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.model-card {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  background: var(--c-bg-raised);
  cursor: pointer;
}
.model-card:has(input:checked) { border-color: var(--c-accent-ink); background: var(--c-selected); }
.model-card input { width: 20px; height: 20px; accent-color: var(--c-accent-ink); }
.model-card-body { display: flex; flex-direction: column; gap: var(--sp-1); }
.model-card .model-name { font-weight: 550; }
.model-card.is-unavailable { color: var(--c-text-dim); background: var(--c-surface-2); cursor: not-allowed; }

/* Advanced parameters, disclosed on demand. */
.advanced { margin-top: var(--sp-4); border-top: 1px solid var(--c-line); padding-top: var(--sp-3); }
.advanced summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 550; color: var(--c-text-soft); }
.advanced summary:hover { color: var(--c-text); }
.advanced[open] summary { margin-bottom: var(--sp-3); }
.tiles { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.tile {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  background: var(--c-bg-raised);
  cursor: pointer;
  font-size: var(--fs-sm);
}
.tile input { accent-color: var(--c-accent-ink); }
.tile-frame { display: inline-block; border: 1px solid var(--c-line-strong); border-radius: var(--r-sm); background: var(--c-surface-3); }
.ratio-5-3 { width: 30px; height: 18px; }
.ratio-16-9 { width: 32px; height: 18px; }
.ratio-1-1 { width: 20px; height: 20px; }
.tile.is-locked { color: var(--c-text-dim); cursor: not-allowed; background: var(--c-surface-2); }
.range { width: 100%; accent-color: var(--c-accent-ink); }

/* Result stage: the video leads, the chrome recedes. */
/* THE STAGE IS THE PICTURE, NOT A PANEL AROUND ONE. A bordered, shadowed card with a heading over a
   video is the generic-SaaS arrangement this direction removes: the picture takes the width of the
   page, and the only thing above it is the status strip. The section keeps an accessible name (a
   visually-hidden `h2`), and WHAT IS LEFT of the chrome - the poll note and the controls - sits
   UNDER the player, where it cannot push the picture down. */
.stage { background: transparent; border: 0; border-radius: 0; padding: 0; margin: 0 0 var(--sp-5); }
/* ---------- status as a timeline, not a badge ---------- */

/* WHERE THE WORK IS: the steps the platform's own states collapse to, the step the job is on, the
   times the record carries, and the reason when it is waiting. Colour only reinforces it - the
   current step is the one marked with `aria-current="step"` and set in the foreground colour, and a
   step the record cannot prove is DASHED and named as unknown rather than shown as not reached. */
.timeline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  list-style: none;
  margin: 0 0 var(--sp-2);
  padding: 0;
}
/* AND THE STRIP IS A ROUTE, WHICH IS THE LANDING'S OWN MOTIF RATHER THAN AN IMITATION OF IT: a RULE
   runs between the stops (`.route li::before { height: 8px; background: var(--black) }`), each stop is
   a circle with a THICK border (`.route li::after { width: 40px; height: 40px; border: 6px solid }`),
   the passed ones are FILLED, and the live one is amber. The landing's glow around it is left out: the
   Studio design rules allow no shadows (5.12, 2026-09-26), and the fill already marks the step. The
   sizes here are scaled for a strip that sits inside a page rather than spanning one; the DRAWING is
   the landing's. */
.timeline-step { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); font-weight: 700; color: var(--c-text-dim); }
.timeline-step + .timeline-step::before { content: ""; width: 24px; height: 6px; background: var(--c-line-strong); }
.timeline-dot { width: 14px; height: 14px; border-radius: 50%; border: 3px solid var(--c-line-strong); background: transparent; flex: none; }
.timeline-time { font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 400; color: var(--c-text-dim); }
.timeline-step.is-done { color: var(--c-text-soft); }
.timeline-step.is-done .timeline-dot { background: var(--c-line-strong); }
.timeline-step.is-current { color: var(--c-text); }
.timeline-step.is-current .timeline-dot { background: var(--c-accent); border-color: var(--c-accent-ink); }
/* A STEP THE WORK IS ACTIVELY ON IS AMBER, which is the landing's "on" and nothing else. */
.timeline-step.is-current[data-timeline-step="generating"] .timeline-dot { background: var(--c-running); border-color: var(--c-running); }
.timeline-step.is-pending { color: var(--c-text-dim); }
.timeline-step.is-unknown { color: var(--c-text-dim); }
.timeline-step.is-unknown .timeline-dot { border-style: dashed; }
.timeline-step.is-ended { color: var(--c-text); }
.timeline-step.is-ended .timeline-dot { background: var(--c-failed); border-color: var(--c-failed); }
.timeline-step.is-ended[data-timeline-status="canceled"] .timeline-dot { background: var(--c-canceled); border-color: var(--c-canceled); }
.timeline-note { color: var(--c-text-dim); font-size: var(--fs-xs); margin: 0 0 var(--sp-4); }

/* THE VIDEO IS THE LARGEST THING ON A SCREEN THAT HAS ONE. It takes the whole width of
   the container, keeps a 16:9 frame so it is already its final size before any metadata
   arrives (a vertical clip is pillarboxed inside it, the way an edit suite does it), and
   never grows past the viewport it is being watched in. */
.stage-player { width: var(--w-media); max-width: var(--w-media); aspect-ratio: 16 / 9; max-height: 78vh; background: var(--c-media); border-radius: var(--r-md); display: block; }
/* THE CANVAS IS THE SAME PICTURE IN THE SAME PLACE, because it IS the video's rectangle: the frame the
   player and the canvas share keeps the 16:9 box, so nothing on the page moves when a clip the browser
   cannot decode is decoded here instead. The canvas carries the picture and the element carries the
   sound, so the two are never stacked on top of each other: the element is hidden when the canvas is
   shown, and the transport below is the only control that is left. A canvas FILLS its box by default, so a
   portrait frame would be squeezed into 16:9; `contain` pillarboxes it the way the element does (2026-09-25). */
.stage-frame { width: var(--w-media); max-width: var(--w-media); }
.stage-canvas { width: var(--w-media); max-width: var(--w-media); aspect-ratio: 16 / 9; max-height: 78vh; background: var(--c-media); border-radius: var(--r-md); display: block; object-fit: contain; }
.stage-transport { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); }
.stage-progress { flex: 1; max-width: 420px; height: 8px; accent-color: var(--c-accent-ink); }
.stage-idle {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  min-height: 220px;
  width: 100%;
  border: 1px dashed var(--c-line-strong);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  text-align: center;
  padding: var(--sp-5);
}

/* ---------- your videos: one tile per job ----------
   EVERY TILE HAS THE SAME SHAPE, SO A ROW OF THEM READS AS ONE ROW: a 16:9 media box (the player's own
   frame, so a thumbnail is the picture the customer will watch, letterboxed rather than cropped), a
   title held to two lines, the facts, and the actions pinned to the tile's foot. The box is there for
   every case - a thumbnail; the words "No preview yet" for a delivered video without one and for work
   in flight (drawn on the landing's "busy" stripe); and, for a job that ended, an empty frame with a
   stroke through it. The ended tile's frame is DRAWN BY THE STYLESHEET and carries no words: nothing is
   "yet" about a job that ended (views.ex `tile_preview/2`), and the row still lines up. */
/* ROWS OF ONE HEIGHT, TILES AS WIDE AS THEIR SHAPE (2026-09-27, userbus-studio#41). Every preview is `--row`
   tall; a slot's ratio (`--r`, from `data-tile-shape`) is both its flex-grow and its flex-basis in row heights,
   so a landscape tile is wide and a portrait one narrow and each shows its own frame - a portrait clip is no
   longer a sliver in a 16:9 box. A slot is never narrower than its text needs, and newest-first order is kept
   (columns of masonry would read top to bottom). The filler after the last slot keeps the last row from
   stretching. */
.video-grid {
  --row: 170px;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
}
.video-grid::after { content: ""; flex: 1000 1 0; }
.tile-slot { --r: 1.7778; display: flex; min-width: min(176px, 100%); flex: var(--r) 1 calc(var(--r) * var(--row)); }
.tile-slot[data-tile-shape="portrait"] { --r: 0.75; }
.tile-slot[data-tile-shape="square"], .tile-slot--new { --r: 1; }
.video-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-bg-raised);
  overflow: hidden;
}
.video-tile:hover { border-color: var(--c-line-strong); }
.video-tile:has(.tile-title:focus-visible) { outline: var(--focus); outline-offset: 2px; }
.tile-preview, .video-tile[data-tile-case="failed"]::before {
  flex: none;
  height: var(--row);
  background: var(--c-surface-2);
  border-bottom: 1px solid var(--c-line);
}
.tile-preview { display: flex; align-items: center; justify-content: center; overflow: hidden; }
.video-tile[data-tile-case="failed"]::before {
  content: "";
  display: block;
  background: linear-gradient(to top right, transparent calc(50% - 1px), var(--c-line-strong) 50%, transparent calc(50% + 1px)), var(--c-surface-2);
}
.video-tile[data-tile-case="running"] .tile-preview {
  background: repeating-linear-gradient(135deg, var(--c-surface-2) 0 6px, var(--c-surface-3) 6px 12px);
}
.tile-thumb { display: block; width: 100%; height: 100%; object-fit: contain; background: var(--c-media); }
/* A portrait or square clip is marked (views.ex, fit_attr) and shown whole in the 3:2 tile rather than cut
   to its middle - the same fit every thumbnail now has, stated for the clip it matters most to. */
.tile-thumb[data-thumb-fit="contain"] { object-fit: contain; }
.tile-absent { color: var(--c-text-dim); font-size: var(--fs-xs); line-height: 18px; padding: var(--sp-1) var(--sp-3); border-radius: var(--r-sm); background: var(--c-surface-2); text-align: center; }
.tile-body { flex: 1; display: flex; flex-direction: column; gap: 6px; padding: var(--sp-3); min-width: 0; }
/* TWO LINES, ALWAYS TWO LINES TALL: a one-line title does not pull its row's facts up out of line. Its link is
   the whole tile's: the ::after covers the tile, and only the project link sits above it. */
.tile-title::after { content: ""; position: absolute; inset: 0; }
.tile-title:focus-visible { outline: none; }
.tile-meta .tile-project { position: relative; z-index: 1; }
.tile-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  min-height: 44px;
  line-height: 22px;
  font-weight: 700;
  overflow-wrap: anywhere;
  color: var(--c-text);
}
/* THE FIGURES' DOTS SIT IN THE GAP, AND A LINE NEVER STARTS OR ENDS WITH ONE. Each figure carries its
   dot in its own left margin; the list is pulled left by that margin and its first 16px are clipped,
   so the dot of whichever figure starts a line – the first, or one a narrow tile wrapped – is cut
   away, and every other dot stays between two figures. The dot is decoration: its alt text is empty. */
.tile-figures { display: flex; flex-wrap: wrap; row-gap: 2px; margin: 0 0 0 calc(-1 * var(--sp-4)); clip-path: inset(0 0 0 var(--sp-4)); color: var(--c-text-soft); font-size: var(--fs-xs); line-height: 18px; }
.tile-figure { position: relative; margin-left: var(--sp-4); font-variant-numeric: tabular-nums; }
.tile-figure::before { content: "·"; content: "·" / ""; position: absolute; left: calc(-1 * var(--sp-4)); width: var(--sp-4); text-align: center; color: var(--c-text-dim); }
.tile-meter { flex: 1; min-width: 120px; }
/* THE GRID'S FILTER (2026-09-27, userbus-studio#42): one switch above the grid, pressed when canceled videos
   are shown. */
.grid-filter { display: flex; justify-content: flex-end; margin: 0 0 var(--sp-3); }
.filter-toggle[aria-pressed="true"] { background: var(--c-selected); border-color: var(--c-selected-line); }
.grid-foot { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-4); }
@media (max-width: 480px) {
  .video-grid { --row: 190px; gap: var(--sp-3); }
  .tile-slot { min-width: 150px; }
}

/* Long identifiers and checksums must wrap, never widen the page. */
.table td.id a, .copy-row .value, .mono, h1 .mono { overflow-wrap: anywhere; word-break: break-word; }

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

.composer .primary-action { margin-top: var(--sp-5); display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }

/* ---------- data ---------- */

.table-wrap { overflow-x: auto; }
table.table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.table caption { text-align: left; color: var(--c-text-dim); font-size: var(--fs-xs); padding-bottom: var(--sp-2); }
.table th, .table td { text-align: left; padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--c-line); vertical-align: middle; }
.table thead th { color: var(--c-text-dim); font-size: var(--fs-xs); font-weight: 550; text-transform: none; letter-spacing: 0.02em; }
.table tbody tr:hover { background: var(--c-surface-2); }
.table td.id, .table th.id { font-family: var(--font-mono); font-size: var(--fs-xs); }
.table .empty-row td { color: var(--c-text-dim); padding: var(--sp-5); text-align: center; }

.meter { display: flex; align-items: center; gap: var(--sp-3); }
.meter-track { flex: 1; height: 8px; background: var(--c-surface-3); border-radius: var(--r-pill); overflow: hidden; min-width: 80px; }
.meter-fill { height: 100%; background: var(--c-running); border-radius: var(--r-pill); width: 0; transition: width 200ms ease-out; }
/* THE FILL WIDTH, ONE RULE PER WHOLE PER CENT. `style-src 'self'` refuses an inline `style="width"`,
   so `meter/2` in views.ex writes `data-pct` (an integer 0..100) and these rules turn it into a width.
   A fill with no `data-pct` (progress not reported) keeps `width: 0` rather than reading full. */
.meter-fill[data-pct="0"]{width:0%} .meter-fill[data-pct="1"]{width:1%} .meter-fill[data-pct="2"]{width:2%} .meter-fill[data-pct="3"]{width:3%} .meter-fill[data-pct="4"]{width:4%}
.meter-fill[data-pct="5"]{width:5%} .meter-fill[data-pct="6"]{width:6%} .meter-fill[data-pct="7"]{width:7%} .meter-fill[data-pct="8"]{width:8%} .meter-fill[data-pct="9"]{width:9%}
.meter-fill[data-pct="10"]{width:10%} .meter-fill[data-pct="11"]{width:11%} .meter-fill[data-pct="12"]{width:12%} .meter-fill[data-pct="13"]{width:13%} .meter-fill[data-pct="14"]{width:14%}
.meter-fill[data-pct="15"]{width:15%} .meter-fill[data-pct="16"]{width:16%} .meter-fill[data-pct="17"]{width:17%} .meter-fill[data-pct="18"]{width:18%} .meter-fill[data-pct="19"]{width:19%}
.meter-fill[data-pct="20"]{width:20%} .meter-fill[data-pct="21"]{width:21%} .meter-fill[data-pct="22"]{width:22%} .meter-fill[data-pct="23"]{width:23%} .meter-fill[data-pct="24"]{width:24%}
.meter-fill[data-pct="25"]{width:25%} .meter-fill[data-pct="26"]{width:26%} .meter-fill[data-pct="27"]{width:27%} .meter-fill[data-pct="28"]{width:28%} .meter-fill[data-pct="29"]{width:29%}
.meter-fill[data-pct="30"]{width:30%} .meter-fill[data-pct="31"]{width:31%} .meter-fill[data-pct="32"]{width:32%} .meter-fill[data-pct="33"]{width:33%} .meter-fill[data-pct="34"]{width:34%}
.meter-fill[data-pct="35"]{width:35%} .meter-fill[data-pct="36"]{width:36%} .meter-fill[data-pct="37"]{width:37%} .meter-fill[data-pct="38"]{width:38%} .meter-fill[data-pct="39"]{width:39%}
.meter-fill[data-pct="40"]{width:40%} .meter-fill[data-pct="41"]{width:41%} .meter-fill[data-pct="42"]{width:42%} .meter-fill[data-pct="43"]{width:43%} .meter-fill[data-pct="44"]{width:44%}
.meter-fill[data-pct="45"]{width:45%} .meter-fill[data-pct="46"]{width:46%} .meter-fill[data-pct="47"]{width:47%} .meter-fill[data-pct="48"]{width:48%} .meter-fill[data-pct="49"]{width:49%}
.meter-fill[data-pct="50"]{width:50%} .meter-fill[data-pct="51"]{width:51%} .meter-fill[data-pct="52"]{width:52%} .meter-fill[data-pct="53"]{width:53%} .meter-fill[data-pct="54"]{width:54%}
.meter-fill[data-pct="55"]{width:55%} .meter-fill[data-pct="56"]{width:56%} .meter-fill[data-pct="57"]{width:57%} .meter-fill[data-pct="58"]{width:58%} .meter-fill[data-pct="59"]{width:59%}
.meter-fill[data-pct="60"]{width:60%} .meter-fill[data-pct="61"]{width:61%} .meter-fill[data-pct="62"]{width:62%} .meter-fill[data-pct="63"]{width:63%} .meter-fill[data-pct="64"]{width:64%}
.meter-fill[data-pct="65"]{width:65%} .meter-fill[data-pct="66"]{width:66%} .meter-fill[data-pct="67"]{width:67%} .meter-fill[data-pct="68"]{width:68%} .meter-fill[data-pct="69"]{width:69%}
.meter-fill[data-pct="70"]{width:70%} .meter-fill[data-pct="71"]{width:71%} .meter-fill[data-pct="72"]{width:72%} .meter-fill[data-pct="73"]{width:73%} .meter-fill[data-pct="74"]{width:74%}
.meter-fill[data-pct="75"]{width:75%} .meter-fill[data-pct="76"]{width:76%} .meter-fill[data-pct="77"]{width:77%} .meter-fill[data-pct="78"]{width:78%} .meter-fill[data-pct="79"]{width:79%}
.meter-fill[data-pct="80"]{width:80%} .meter-fill[data-pct="81"]{width:81%} .meter-fill[data-pct="82"]{width:82%} .meter-fill[data-pct="83"]{width:83%} .meter-fill[data-pct="84"]{width:84%}
.meter-fill[data-pct="85"]{width:85%} .meter-fill[data-pct="86"]{width:86%} .meter-fill[data-pct="87"]{width:87%} .meter-fill[data-pct="88"]{width:88%} .meter-fill[data-pct="89"]{width:89%}
.meter-fill[data-pct="90"]{width:90%} .meter-fill[data-pct="91"]{width:91%} .meter-fill[data-pct="92"]{width:92%} .meter-fill[data-pct="93"]{width:93%} .meter-fill[data-pct="94"]{width:94%}
.meter-fill[data-pct="95"]{width:95%} .meter-fill[data-pct="96"]{width:96%} .meter-fill[data-pct="97"]{width:97%} .meter-fill[data-pct="98"]{width:98%} .meter-fill[data-pct="99"]{width:99%}
.meter-fill[data-pct="100"]{width:100%}
.meter-fill[data-state="succeeded"] { background: var(--c-succeeded); }
.meter-fill[data-state="failed"] { background: var(--c-failed); }
.meter-fill[data-state="canceled"] { background: var(--c-canceled); }
.meter-value { font-variant-numeric: tabular-nums; font-size: var(--fs-xs); color: var(--c-text-soft); min-width: 3.5ch; text-align: right; }

.kv { display: grid; grid-template-columns: minmax(9rem, auto) minmax(0, 1fr); gap: var(--sp-2) var(--sp-4); font-size: var(--fs-sm); }
.kv dt { color: var(--c-text-dim); }
.kv dd { margin: 0; overflow-wrap: anywhere; }

/* A MONEY ROW IS THE LANDING'S CALCULATOR ROW (`.rows > div`): a rule above it, a grey label, and the
   figure in the reading position with weight on it. */
.kv.money { gap: 0 var(--sp-4); }
.kv.money dt, .kv.money dd { border-top: 1px solid var(--c-line); padding-block: var(--sp-2); }
.kv.money dt:first-of-type, .kv.money dd:first-of-type { border-top: 0; }
.kv.money dd span[data-money-field] { font-weight: 700; font-size: var(--fs-md); }

.copy-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.copy-row .value { font-family: var(--font-mono); font-size: var(--fs-xs); overflow-wrap: anywhere; }


video.player { width: 100%; max-width: 720px; background: #000; border-radius: var(--r-md); display: block; }

/* ---------- toast: a short confirmation ("Changes saved", "Copied", "Moved to …") ----------
   THE DESIGN SYSTEM'S RULE (userbus-design src/styles/components.css, "toast", 2026-09-27, userbus/docs#28),
   copied here because this app vendors no design CSS yet. It floats at the window's bottom-right corner on a
   wide screen and across the foot on a phone, and never takes space in the layout, so nothing on the page
   moves when it comes or goes. At most three stack upwards (app.js `toast`). */
/* THE PRICE CONFIRMATION (2026-09-27, userbus/docs#31): one card, as a modal over the composer when the script
   runs and as its own page when it does not. Cancel sits before the acceptance, which is the primary press. */
.quote-actions { display: flex; justify-content: flex-end; gap: var(--sp-3); margin-top: var(--sp-5); flex-wrap: wrap; }
.quote-modal, .confirm-modal {
  width: min(32rem, calc(100vw - 2 * var(--sp-4))); max-height: calc(100dvh - 2 * var(--sp-4));
  padding: 0; border: 0; background: transparent; color: var(--c-text); overflow: auto;
}
.quote-modal::backdrop, .confirm-modal::backdrop { background: rgba(0, 0, 0, 0.55); }
.confirm-modal .card { margin: 0; border-color: var(--c-line-strong); }
.quote-modal .quote-card { margin: 0; border-color: var(--c-line-strong); }

.toast-region {
  position: fixed; inset-inline-end: var(--sp-5); bottom: var(--sp-5); z-index: 30;
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2);
  max-width: min(24rem, calc(100vw - 2 * var(--sp-5))); pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: 0; padding: var(--sp-2) var(--sp-4); min-height: var(--ctl-md);
  background: var(--c-surface-2); border: 1px solid var(--c-line-strong); border-radius: var(--r-md);
  color: var(--c-text); font-size: var(--fs-sm); font-weight: 700; line-height: 20px;
  pointer-events: auto; animation: ub-toast-in 160ms ease-out;
}
.toast .icon { flex: none; width: 16px; height: 16px; color: var(--c-accent-ink); }
.toast.is-leaving { opacity: 0; transform: translateY(4px); transition: opacity 160ms ease-in, transform 160ms ease-in; }
@keyframes ub-toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (max-width: 720px) {
  .toast-region { inset-inline: var(--sp-4); bottom: calc(var(--sp-4) + env(safe-area-inset-bottom, 0px)); align-items: stretch; max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
  .toast.is-leaving { transition: none; }
}
/* A confirmation the server sent with the page is shown as a toast by the script, so its paragraph is not
   drawn as well; with scripts off it stays where it is. */
.js [data-toast-notice] { display: none; }

/* ---------- sign-in ---------- */

.signin { max-width: 560px; margin: var(--sp-7) auto; }
.signin .value-line { font-size: var(--fs-xl); font-weight: 600; letter-spacing: -0.02em; margin-bottom: var(--sp-3); }
.signin .lede { color: var(--c-text-soft); margin-bottom: var(--sp-5); }
.signin .fine { color: var(--c-text-dim); font-size: var(--fs-xs); margin-top: var(--sp-4); }
.signin .unavailable { margin-top: var(--sp-5); border: 1px solid var(--c-line); border-radius: var(--r-md); padding: var(--sp-4); background: var(--c-surface-2); }
.signin .unavailable h2 { font-size: var(--fs-md); margin-bottom: var(--sp-2); }

.blocked { color: var(--c-text-soft); font-size: var(--fs-sm); }

/* ---------- responsive ---------- */

@media (max-width: 720px) {
  main { padding: var(--sp-4) var(--sp-3); }
  .topbar-inner { padding: var(--sp-3); gap: var(--sp-2); }
  .topbar-end { margin-left: 0; width: 100%; justify-content: space-between; }
  .topbar-end:not(:has(.logout)) { width: auto; margin-left: auto; }
  .nav { order: 3; width: 100%; margin-left: 0; }
  .card { padding: var(--sp-4); border-radius: var(--r-md); }
  .param-grid { grid-template-columns: minmax(0, 1fr); }
  .kv { grid-template-columns: minmax(0, 1fr); gap: var(--sp-1) 0; }
  .kv dt { font-size: var(--fs-xs); }
  .btn, .input, .select, .nav a { min-height: 44px; }
  .tabs { gap: var(--sp-1) var(--sp-4); }
  .tabs a { min-height: 44px; display: inline-flex; align-items: center; }
  /* Every standalone control reaches 44px where the pointer is a finger - including the two that the
     header and the tile grid used to leave at the height of their own text. A control INSIDE a label
     (the model cards' radios, the consent checkbox) is not listed here: the label is the target, and
     it is a whole card tall. */
  .balance-badge { min-height: 44px; }
  .statement-row a { min-height: 44px; display: inline-flex; align-items: center; }
  /* AND THE CONTROLS THAT CARRY NO SIZE CLASS OF THEIR OWN, which a measurement at 390px found at the
     height of their own text: the top-up amount and the price ceiling (two money controls, both of
     them real targets) and the links to the videos that are holding money in the wallet. Listed by id
     and by attribute rather than given a class, because neither needs a different WIDTH - only a
     finger-sized box. */
  #topup-amount, #max_price_per_second_minor { min-height: 44px; }
  [data-holding-job] a { min-height: 44px; display: inline-flex; align-items: center; }
  /* A BUTTON IS AS WIDE AS ITS LABEL HERE TOO. What used to be `.btn { width: 100% }` stacked every pair
     of actions into two full-width rows; a group now splits its row between its buttons (the ≤720px
     rules of the button system), and only a form's single primary spans the width. */
  .page-head .head-actions { width: 100%; margin-left: 0; }

  /* Stacked data tables: no horizontal scrolling at 390px. */
  .table thead { display: none; }
  .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
  .table tr { border: 1px solid var(--c-line); border-radius: var(--r-md); margin-bottom: var(--sp-3); padding: var(--sp-2) var(--sp-3); background: var(--c-bg-raised); }
  .table td { border: 0; padding: var(--sp-1) 0; display: flex; gap: var(--sp-3); }
  .table td::before { content: attr(data-label); color: var(--c-text-dim); font-size: var(--fs-xs); min-width: 7rem; }
  .table td.id::before { content: attr(data-label); }
  .table .empty-row td::before { content: ""; min-width: 0; }
  .table-wrap { overflow-x: visible; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}

/* ---------- plain-language studio additions ---------- */

.empty-state { text-align: center; padding: var(--sp-5) var(--sp-4); color: var(--c-text-soft); }
.empty-state h2 { color: var(--c-text); font-size: var(--fs-md); margin-bottom: var(--sp-2); }
.empty-state p { max-width: 46ch; margin-left: auto; margin-right: auto; }

/* THE ACTIVITY STATEMENT (2026-09-27, userbus/userbus-studio#50): a table read like a card statement - dates,
   descriptions, types and statuses left-aligned, the amount right-aligned in tabular figures, a fine line
   between rows. On a phone every row is a small card: the description and the amount on top, the date, the
   type and the status under them. */
.statement { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.statement th { text-align: left; font-size: var(--fs-xs); font-weight: 600; color: var(--c-text-dim); padding: 0 var(--sp-3) var(--sp-2) 0; border-bottom: 1px solid var(--c-line-strong); white-space: nowrap; }
.statement td { padding: var(--sp-3) var(--sp-3) var(--sp-3) 0; border-bottom: 1px solid var(--c-line); vertical-align: top; }
.statement th:last-child, .statement td:last-child { padding-right: 0; }
.statement .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.statement-amount { font-weight: 600; }
.statement-date, .statement-type { color: var(--c-text-soft); white-space: nowrap; }
.statement-desc { width: 100%; min-width: 0; }
.statement-desc .usage-title { overflow-wrap: anywhere; }
.statement-desc .fine { display: block; margin-top: 2px; color: var(--c-text-dim); }
.statement [data-video-deleted] { color: var(--c-text-soft); font-style: italic; }
@media (max-width: 640px) {
  .statement thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .statement, .statement tbody { display: block; }
  .statement-row { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; grid-template-areas: "desc desc desc amount" "date type . status"; gap: 4px var(--sp-3); padding: var(--sp-3) 0; border-bottom: 1px solid var(--c-line); }
  .statement td { display: block; padding: 0; border: 0; }
  .statement-desc { grid-area: desc; width: auto; }
  .statement-amount { grid-area: amount; }
  .statement-date { grid-area: date; font-size: var(--fs-xs); }
  .statement-type { grid-area: type; font-size: var(--fs-xs); }
  .statement-status { grid-area: status; justify-self: end; }
  /* The link keeps its 44px target, and gives the height back so the card does not open with a gap. */
  .statement-desc a.usage-title { margin-block: -12px; }
}

.stage-actions { margin-top: var(--sp-4); }
.support { margin-top: var(--sp-4); }


/* Nothing inside a field may exceed its box: an intrinsic-width control (range
   input, select, button) is the usual cause of a few pixels of inner overflow. */
.field > *, .row > *, .param-grid > * { min-width: 0; }
input[type="range"], .input, .select, .textarea { max-width: 100%; min-width: 0; }
/* A range input carries a default 2px margin in Chromium, which makes a 100%-wide
   slider overflow its box by ~4px; the margins are removed here. */
.range { display: block; width: 100%; margin: 0; }
input[type="range"] { margin: 0; }
.row { min-width: 0; }

/* THE PROVIDER REQUEST (/providers/request): one column of fields at a reading width, and the facts
   under it at the same width. */
.provider-request, .provider-facts { max-width: 640px; }
.provider-facts { color: var(--c-text-dim); font-size: var(--fs-xs); margin-top: var(--sp-4); }
/* The provider request's trap field: off screen for people, present for programs that fill every field. */
.trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }

/* Create and follow a video: one set of numeric controls and one arrival board. */
.studio-grid { display: block; }
.composer { padding: 0; background: transparent; border: 0; }
.create-layout { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.85fr); gap: 20px; align-items: start; }
.creative-panel, .booking-panel { min-width: 0; }
.creative-panel { padding: 20px; border: 1px solid var(--c-line); border-radius: var(--r-lg); background: var(--c-bg-raised); }
.booking-panel { padding: 20px; border: 1px solid var(--c-line-strong); border-top: 2px solid var(--c-accent); border-radius: var(--r-lg); background: var(--c-surface); }
.prompt-footer { display: flex; justify-content: space-between; gap: 16px; margin-top: 8px; }
.prompt-footer .field-hint { margin: 0; font-size: var(--fs-xs); }
/* The description's label row: the label, and Undo (only while it can undo) at the right edge - one line high,
   so no control reaches the box's border (userbus-studio#37). */
.prompt-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; min-height: 28px; margin-bottom: var(--sp-2); }
.prompt-head .field-label { margin-bottom: 0; }
.idea-controls { display: flex; align-items: center; gap: 8px; margin-left: auto; }
/* THE EXAMPLE IDEAS UNDER THE DESCRIPTION (2026-09-26): quiet buttons in one wrapping row, a tap fills the box.
   Shown by the script only. */
.prompt-examples { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); }
.prompt-examples[hidden] { display: none; }
.prompt-examples-label { margin: 0; }
.btn-quiet.prompt-example { border-color: var(--c-line); border-radius: var(--r-pill); font-weight: 500; }
/* THE AVAILABILITY VERDICT ABOVE GENERATE: a plain line, in the warning colour the arrival board uses. */
.arrival-verdict { flex-basis: 100%; margin: 0; font-size: var(--fs-sm); color: var(--c-warn); }
/* "YOU'RE IN": one card, the first video as its only action. */
.welcome-card { max-width: 640px; }
.welcome-card > p + p { margin-top: var(--sp-3); }
/* UNDO'S HOVER SAYS WHAT IT WOULD BRING BACK (data-preview, set by the script), on hover and keyboard focus. */
.idea-undo { position: relative; }
.idea-undo[hidden] { display: none; }
.idea-undo::after { content: attr(data-preview); position: absolute; right: 0; bottom: calc(100% + 6px); z-index: 5; width: max-content; max-width: min(360px, 80vw); padding: 6px 10px; white-space: normal; text-align: left; font-size: var(--fs-xs); font-weight: 500; line-height: 1.4; color: var(--c-text); background: var(--c-surface-3); border: 1px solid var(--c-line-strong); border-radius: var(--r-sm); opacity: 0; pointer-events: none; transition: opacity .12s; }
.idea-undo:hover::after, .idea-undo:focus-visible::after { opacity: 1; }
.creative-panel .param-grid.frame { grid-template-columns: 1fr; gap: 14px; margin-bottom: 14px; }
.number-control { display: flex; align-items: center; gap: 12px; padding: 0 0 0 14px; min-height: 52px; border: 1px solid var(--c-line-strong); border-radius: var(--r-md); background: var(--c-bg); transition: border-color .15s; }
.number-control:focus-within { border-color: var(--c-accent-ink); outline: 1px solid var(--c-accent); outline-offset: 0; }
.number-value { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 4px; cursor: text; }
.number-value input { display: block; width: 3ch; min-width: 3ch; flex: 0 1 auto; padding: 6px 0; border: none; border-radius: var(--r-sm); background: transparent; font: 600 26px/1.25 var(--font-mono); text-align: left; color: var(--c-text); appearance: textfield; -moz-appearance: textfield; }
.number-value input::-webkit-inner-spin-button, .number-value input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.number-value span { flex-shrink: 0; font-size: var(--fs-sm); color: var(--c-text-dim); }
.number-steps { display: grid; grid-template-rows: 1fr 1fr; flex: 0 0 36px; align-self: stretch; border-left: 1px solid var(--c-line); border-radius: 0 var(--r-md) var(--r-md) 0; overflow: hidden; }
.number-step { display: grid; place-items: center; width: 36px; min-height: 25px; border: 0; border-radius: 0; background: transparent; color: var(--c-text-soft); cursor: pointer; padding: 0; }
.number-step + .number-step { border-top: 1px solid var(--c-line); }
.number-step svg { display: block; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.number-step[data-number-step="-1"] svg { transform: rotate(180deg); }
.number-step:hover:not(:disabled) { background: var(--c-surface-2); color: var(--c-accent-ink); }
.number-step:disabled { opacity: 0.3; cursor: default; }
.number-step[hidden] { display: none; }
.number-value input:focus-visible { outline: none; }
.number-step:focus-visible { outline: 2px solid var(--c-accent-ink); outline-offset: -3px; }
.duration-slider:focus-visible { outline: 2px solid var(--c-accent-ink); outline-offset: 2px; }
.duration-slider { display: block; width: 100%; height: 24px; margin: 4px 0 0; accent-color: var(--c-accent-ink); cursor: pointer; appearance: none; background: transparent; }
.duration-slider::-webkit-slider-runnable-track { height: 4px; background: linear-gradient(to right, var(--c-accent-ink) var(--fill, 0%), var(--c-line-strong) var(--fill, 0%)); border-radius: var(--r-sm); }
.duration-slider::-webkit-slider-thumb { appearance: none; width: 18px; height: 18px; margin-top: -7px; background: var(--c-accent); border-radius: 50%; }
.duration-slider::-moz-range-track { height: 4px; background: var(--c-line-strong); border-radius: var(--r-sm); }
.duration-slider::-moz-range-progress { height: 4px; background: var(--c-accent-ink); border-radius: var(--r-sm); }
.duration-slider::-moz-range-thumb { width: 18px; height: 18px; background: var(--c-accent); border: 0; border-radius: 50%; }
.duration-scale { display: flex; justify-content: space-between; font: 11px var(--font-mono); color: var(--c-text-dim); }
/* One tick per length the model takes, under the track, inset by half the thumb so each sits under its stop. */
.duration-ticks { display: flex; justify-content: space-between; padding: 0 8px; margin: 2px 0 2px; }
.duration-ticks > span { width: 1px; height: 5px; background: var(--c-line-strong); }
.number-hint { font-size: var(--fs-xs); }
.number-note { color: var(--c-accent-ink); font-size: var(--fs-xs); }
.number-note:empty { display: none; }
/* THE "?" AFTER A LABEL: the design system's Tooltip (userbus-design src/styles/components.css, "tooltip",
   2026-09-27, userbus/docs#29), copied here because this app vendors no design CSS yet. The "?" sits 6px
   after its label, never across the row; the bubble opens on hover, focus and a tap (app.js `tips`). */
.label-row { display: inline-flex; align-items: center; gap: 6px; }

/* THE BALANCE, LED BY WHAT CAN BE SPENT (2026-09-27, userbus/userbus-studio#47): the available figure large with
   Add credit beside it, Held and Total smaller under it, and one line of fine print. */
.balance-card { max-width: 720px; padding: var(--sp-5); }
.balance-hero { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.balance-label { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); color: var(--c-text-dim); }
.balance-figure { margin: 0; line-height: 1.1; }
.balance-figure [data-money-field] { font-size: clamp(34px, 5vw, 44px); font-weight: 700; letter-spacing: -0.02em; }
.balance-figure [data-money-state="not_reported"] { font-size: var(--fs-md); font-weight: 400; color: var(--c-text-dim); }
.balance-secondary { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-6); margin: var(--sp-5) 0 0; padding-top: var(--sp-4); border-top: 1px solid var(--c-line); }
.balance-secondary dt { font-size: var(--fs-xs); color: var(--c-text-dim); margin-bottom: 4px; }
.balance-secondary dd { margin: 0; }
.balance-secondary [data-money-field] { font-size: var(--fs-md); font-weight: 600; }
.balance-meta { margin: var(--sp-4) 0 0; font-size: var(--fs-xs); color: var(--c-text-dim); }
.balance-card [data-holding-jobs-state="none"], .balance-card [data-holding-jobs-state="unavailable"] { margin: var(--sp-3) 0 0; }
.label-row > label, .label-row > .field-label { margin: 0; }
.tip { position: relative; display: inline-flex; vertical-align: middle; }
.tip-trigger {
  position: relative; display: inline-grid; place-items: center; flex: none;
  width: 18px; height: 18px; padding: 0; margin: 0;
  border: 1px solid var(--c-line-strong); border-radius: 50%; background: transparent;
  color: var(--c-text-dim); font: inherit; font-size: 11px; font-weight: 700; line-height: 1; cursor: help;
}
.tip-trigger::before { content: ""; position: absolute; inset: -13px; }
.tip-trigger:hover, .tip[data-open="true"] .tip-trigger { color: var(--c-text); border-color: var(--c-text-dim); }
.tip-content {
  position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%); z-index: 40;
  width: max-content; max-width: min(18rem, calc(100vw - 2 * var(--sp-4)));
  padding: var(--sp-2) var(--sp-3); background: var(--c-surface-3); border: 1px solid var(--c-line-strong);
  border-radius: var(--r-md); color: var(--c-text); font-size: var(--fs-sm); font-weight: 400;
  line-height: 1.5; text-align: start; white-space: normal; letter-spacing: normal;
}
.tip--below .tip-content { bottom: auto; top: calc(100% + 8px); }
.tip--start .tip-content { left: -6px; transform: none; }
.tip--end .tip-content { left: auto; right: -6px; transform: none; }
.tip:not([data-open="true"]) .tip-content { display: none; }
.tip:hover .tip-content, .tip:focus-within .tip-content { display: block; }
.tip[data-dismissed] .tip-content { display: none; }
.price-limit-label { display: flex; margin-bottom: 6px; min-height: 24px; }
.budget-total { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 6px 12px; padding: 12px 0 4px; margin-top: 12px; border-top: 1px solid var(--c-line); font-size: 14px; }
.budget-total strong { font: 600 32px var(--font-mono); color: var(--c-accent-ink); letter-spacing: -0.04em; }
.budget-total .field-hint { grid-column: 1 / -1; margin: 0; }
.booking-panel .price { font-size: var(--fs-xs); line-height: 1.6; }
.booking-panel .field-hint { line-height: 1.6; }
.arrival-preview { margin-top: 24px; padding-top: 24px; border-top: 1px solid var(--c-line-strong); }
.arrival-board h3 { margin: 0 0 12px; font-size: var(--fs-md); }
.arrival-board .arrival-message { margin: 12px 0 0; font-size: var(--fs-sm); line-height: 1.6; color: var(--c-text-dim); }
.route-preview { display: flex; align-items: center; justify-content: space-between; list-style: none; padding: 0; margin: 20px 0; gap: 8px; }
.route-preview li { display: flex; flex: 1; align-items: center; gap: 8px; font-size: 11px; color: var(--c-text-dim); white-space: nowrap; }
.route-preview li::before { content: ''; width: 8px; height: 8px; border: 2px solid var(--c-accent); border-radius: 50%; flex-shrink: 0; }
.route-preview li:not(:last-child)::after { content: ''; height: 1px; background: var(--c-line-strong); flex: 1; }
.arrival-figure { font: 600 21px/1.4 var(--font-mono); margin: 0 0 8px; }
.arrival-meta { color: var(--c-text-dim); font-size: var(--fs-xs); margin-top: 12px; }
.journey-status { display: flex; align-items: center; gap: 24px; padding: 36px; border: 1px solid var(--c-line-strong); border-radius: var(--r-lg) var(--r-lg) 0 0; background: var(--c-surface); }
.journey-symbol { display: grid; place-items: center; flex-shrink: 0; width: 68px; height: 68px; background: var(--c-accent); color: var(--c-text-invert); font: 600 30px var(--font-mono); border-radius: var(--r-lg); }
.eyebrow { color: var(--c-text-dim); font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em; margin: 0 0 8px; }
.journey-status h2 { margin: 0 0 8px; font-size: clamp(22px, 3vw, 30px); letter-spacing: -0.04em; }
.journey-status .muted { margin: 0; max-width: 600px; line-height: 1.6; }
.journey-status .meter { margin-top: 20px; width: min(100%, 320px); }
[data-live-arrival]:not(:empty) { border: 1px solid var(--c-line-strong); border-top: 0; padding: 24px 36px; border-radius: 0 0 var(--r-lg) var(--r-lg); background: var(--c-bg-raised); }
[data-live-arrival] .arrival-board { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px 32px; }
[data-live-arrival] .arrival-board h3 { grid-column: 1 / -1; }
[data-live-arrival] .arrival-message { margin: 0; }
[data-live-money] .money { margin: 28px 0; }
.head-actions .text-link { font-size: var(--fs-sm); color: var(--c-text-dim); padding: 12px; }
@media (max-width: 900px) {
  .create-layout { grid-template-columns: 1fr; gap: 20px; }
  .booking-panel { max-width: none; }
}
@media (max-width: 540px) {
  .prompt-footer { flex-wrap: wrap; gap: 4px; }
  .param-grid.frame { grid-template-columns: 1fr; }
  .journey-status { padding: 24px 20px; align-items: flex-start; gap: 16px; }
  .journey-symbol { width: 44px; height: 44px; font-size: 20px; border-radius: var(--r-md); }
  [data-live-arrival]:not(:empty) { padding: 20px; }
  [data-live-arrival] .arrival-board { display: block; }
}

/* Keep the creative decision and the booking action within a compact desktop view. */
.booking-panel .arrival-preview { margin-top: 14px; padding-top: 12px; }
.booking-panel .route-preview { margin: 4px 0 14px; }
.booking-panel .arrival-figure { font-family: inherit; font-size: 20px; letter-spacing: -0.02em; }
[data-live-money] .money dd > .fine { display: block; margin-top: 4px; font-size: var(--fs-xs); }
@media (max-width: 540px) {
  .page-head .head-actions { flex-wrap: wrap; }
}
.money[data-job-money] { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 24px; padding: 24px 0; border-block: 1px solid var(--c-line); }
.money[data-job-money] dt { grid-row: 1; padding: 0 0 8px; border: 0; font-size: var(--fs-xs); }
.money[data-job-money] dd { grid-row: 2; padding: 0; border: 0; }
.money[data-job-money] dt:nth-of-type(1), .money[data-job-money] dd:nth-of-type(1) { grid-column: 1; }
.money[data-job-money] dt:nth-of-type(2), .money[data-job-money] dd:nth-of-type(2) { grid-column: 2; }
.money[data-job-money] dt:nth-of-type(3), .money[data-job-money] dd:nth-of-type(3) { grid-column: 3; }
.money[data-job-money] dd span[data-money-state="not_reported"] { font-weight: 400; font-size: 14px; color: var(--c-text-dim); }
@media (max-width: 540px) {
  .money[data-job-money] { grid-template-columns: 1fr; gap: 6px; }
  .money[data-job-money] dt, .money[data-job-money] dd { grid-row: auto; grid-column: 1 !important; }
  .money[data-job-money] dt { margin-top: 16px; padding-bottom: 0; }
  .money[data-job-money] dt:first-child { margin-top: 0; }
}
[data-live-timeline] [data-waiting-reason] { padding: 0; border: 0; border-radius: 0; background: transparent; color: var(--c-text-dim); font-size: var(--fs-xs); margin: 0 0 20px; }

.model-kind { font-size: var(--fs-xs); color: var(--c-text-dim); margin-top: 4px; }

/* Compact composer rhythm: shared baselines, without shrinking body text. */
main:has(.create-layout) { padding-top: 18px; }
main:has(.create-layout) .page-head { margin-bottom: 14px; }
main:has(.create-layout) .page-head h1 { margin-bottom: 6px; }
/* The title and its one line, stacked on one left edge (userbus-studio#35): side by side they sat on two
   baselines that never lined up. */
.create-head { display: block; }
.create-head h1 { margin: 0 0 4px; line-height: 1.15; }
.create-head .lede { font-size: var(--fs-sm); color: var(--c-text-dim); }
.draft-status { display: flex; align-items: baseline; justify-content: space-between; gap: 6px 16px; flex-wrap: wrap; margin-bottom: 12px; }
.draft-status > p { margin: 0; }
.draft-status:has(> :only-child:empty), .draft-status > p:empty { display: none; }
.create-layout .field { margin-bottom: 12px; }
.create-layout .param-grid .field { margin-bottom: 0; }
.create-layout .field > label { display: flex; align-items: center; min-height: 24px; margin-bottom: 6px; }
.create-layout .model-cards { margin-bottom: 12px; }
.create-layout .model-card { padding: 8px 12px; min-height: 42px; }
.create-layout .model-card-body { flex-direction: row; align-items: baseline; gap: 10px; }
.create-layout .model-kind { margin: 0; }
.create-layout .advanced { margin-top: 12px; padding-top: 10px; }
[data-duration-control] { display: grid; grid-template-columns: 148px minmax(0, 1fr); align-items: center; gap: 6px 16px; }
[data-duration-control] > .select { grid-column: 1 / -1; }
.duration-range { min-width: 0; padding-top: 8px; }
.duration-range .duration-slider { margin: 0; }
[data-duration-control] .number-note { grid-column: 1 / -1; margin: 0; }
@media (max-width: 540px) {
  [data-duration-control] { column-gap: 12px; }
}
.booking-panel .arrival-board h3 { margin-bottom: 8px; }
.booking-panel .arrival-message { margin-top: 8px; }
.booking-panel .arrival-meta { margin-top: 8px; }
@media (max-width: 540px) {
  .create-layout .model-card-body { flex-wrap: wrap; gap: 2px 10px; }
}

.booking-panel .budget-total strong { font-size: 28px; line-height: 1.2; }
.booking-panel > .fine { font-size: var(--fs-xs); margin-bottom: 8px; }

.booking-panel .arrival-meta { margin: 8px 0 0; }
.booking-panel .route-preview { margin-bottom: 10px; }
.booking-panel .budget-total { margin-top: 8px; padding-top: 10px; gap: 4px 12px; }
.booking-panel .price-limit-field { margin-bottom: 8px; }
@media (min-width: 901px) {
  .create-layout { align-items: stretch; }
}

/* Job detail: stable route rows, aligned actions and a compact status/arrival card. */
.job-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 12px 24px; margin-bottom: 24px; }
.job-head > div:first-child { min-width: 0; }
.job-head h1 { font-size: clamp(22px, 2.3vw, 28px); line-height: 1.25; margin-bottom: 8px; overflow-wrap: anywhere; }
.job-head .lede { font-size: var(--fs-sm); }
.job-head .head-actions { margin: 0; gap: var(--sp-2); align-items: center; }
.job-journey { padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-5); border: 1px solid var(--c-line); border-radius: var(--r-lg); background: var(--c-bg-raised); }
/* THE ROUTE SPANS THE STRIP: the two steps that lead somewhere share the width (each carries the rule
   to the next stop), and the last stop takes only its own width - so Ready sits at the right end of the
   strip instead of two thirds of the way along it. */
.job-journey .timeline { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: var(--sp-3) var(--sp-5); margin: 0; }
.job-journey .timeline-step { display: grid; grid-template-columns: 14px max-content minmax(0, 1fr); grid-template-rows: 22px 18px; align-items: center; align-content: start; gap: 4px 10px; position: relative; }
.job-journey .timeline-step::before { content: none; }
.job-journey .timeline-dot { grid-area: 1 / 1; }
.job-journey .timeline-label { grid-area: 1 / 2; }
.job-journey .timeline-time { grid-area: 2 / 2 / 3 / 4; line-height: 18px; }
.job-journey .timeline-step:nth-child(-n+2)::after { content: ""; grid-area: 1 / 3; height: 1px; width: calc(100% + 8px); background: var(--c-line-strong); }
.job-journey .timeline-step.is-ended { grid-column: 1 / -1; grid-template-rows: 22px; }
.job-journey .timeline-note { margin: 12px 0 0; padding-top: 12px; border-top: 1px solid var(--c-line); line-height: 1.6; }
.job-journey [data-waiting-reason] { margin: 8px 0 0; }
.journey-body:has(.journey-status) { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); border: 1px solid var(--c-line-strong); border-radius: var(--r-lg); overflow: hidden; background: var(--c-surface); }
.journey-body:has(.journey-status):has([data-live-arrival]:empty) { grid-template-columns: 1fr; }
.journey-body .journey-status { border: 0; border-radius: 0; padding: 24px; gap: 16px; align-items: flex-start; background: transparent; }
.journey-body .journey-symbol { width: 44px; height: 44px; border-radius: var(--r-md); font-size: 20px; }
.journey-body .journey-status > div { min-width: 0; }
.journey-body .journey-status h2 { font-size: 23px; line-height: 1.25; }
.journey-body .journey-status .muted { font-size: 14px; }
.journey-body [data-live-arrival]:not(:empty) { padding: 24px; border: 0; border-left: 1px solid var(--c-line); border-radius: 0; background: var(--c-bg-raised); }
.journey-body [data-live-arrival] .arrival-board { display: block; }
.journey-body .arrival-board h3 { margin-bottom: 8px; }
.journey-body .arrival-figure { font-family: inherit; font-size: 21px; letter-spacing: -0.025em; }
.journey-body .arrival-message { margin: 8px 0 0; }
.journey-body .arrival-meta { margin: 12px 0 0; }
.stage-actions { justify-content: space-between; gap: 12px; }
.stage-actions .card-note { font-size: var(--fs-xs); color: var(--c-text-dim); }
main:has(.job-head) [data-job-prompt] { padding: 20px; }
main:has(.job-head) [data-job-prompt] .card-head { margin-bottom: 12px; }
/* THE VIDEO PAGE IN TWO COLUMNS (2026-09-27, userbus/userbus-studio#43): the video on the left, sized for its
   shape rather than a cinema-wide 16:9 box, and a 300px column on the right with what the customer can do
   with it. A landscape video's facts continue under it; a portrait or square one is narrow, so its column
   is only as wide as the video and the facts run under both columns. One column below 1100px. */
.job-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  grid-template-areas: "stage side" "rest side";
  grid-template-rows: auto 1fr;
  gap: var(--sp-5) var(--sp-6);
  align-items: start;
}
.job-layout[data-shape="portrait"], .job-layout[data-shape="square"] {
  grid-template-columns: auto minmax(300px, 1fr);
  grid-template-areas: "stage side" "rest rest";
  grid-template-rows: auto auto;
}
.job-stage { grid-area: stage; min-width: 0; margin: 0; }
.job-side { grid-area: side; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-4); max-width: 360px; }
.job-rest { grid-area: rest; min-width: 0; }
.job-rest > * + * { margin-top: var(--sp-4); }
/* THE VIDEO DETAILS (2026-09-27, userbus/userbus-studio#44): three short groups - the video, its cost, its
   history - each a row of facts that wraps, and Details for support folded under them. */
.video-details { padding: 20px; }
.video-details .card-head { margin-bottom: var(--sp-2); }
.details-label { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--c-text-dim); }
.facts-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: var(--sp-3) var(--sp-5); margin: 0; font-size: var(--fs-sm); }
.facts-row dt { color: var(--c-text-dim); font-size: var(--fs-xs); margin-bottom: 4px; }
.facts-row dd { margin: 0; overflow-wrap: anywhere; }
.facts-row[data-video-history] { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.video-details [data-live-money] .money { margin: 0; padding: 0; border: 0; }
.video-details .support { margin-top: var(--sp-5); }
.job-side-actions { display: flex; flex-direction: column; gap: var(--sp-2); }
.job-action-form { margin: 0; }
.job-side .job-summary, .job-side .job-side-note { margin: 0; }
.job-side .job-project { margin: 0; padding: var(--sp-4); }
.job-side .project-move-form .job-project-title { flex: 1 0 100%; font-size: var(--fs-sm); }
.job-side .project-move-form .select { flex: 1 1 auto; }
.job-side-end { padding-top: var(--sp-4); border-top: 1px solid var(--c-line); }
.stage-note { margin: var(--sp-3) 0 0; font-size: var(--fs-xs); color: var(--c-text-dim); }
.job-layout[data-shape="portrait"] .stage-player, .job-layout[data-shape="portrait"] .stage-canvas {
  width: auto; height: min(72vh, 720px); aspect-ratio: 9 / 16; max-width: 100%; max-height: none;
}
.job-layout[data-shape="square"] .stage-player, .job-layout[data-shape="square"] .stage-canvas {
  width: auto; height: min(64vh, 600px); aspect-ratio: 1; max-width: 100%; max-height: none;
}
@media (max-width: 1100px) {
  .job-layout, .job-layout[data-shape="portrait"], .job-layout[data-shape="square"] {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "stage" "side" "rest";
    grid-template-rows: auto;
  }
  .job-side { max-width: 480px; }
}
@media (max-width: 540px) {
  .job-side { max-width: none; }
  .job-layout[data-shape="portrait"] .stage-player, .job-layout[data-shape="portrait"] .stage-canvas { height: min(68vh, 600px); margin: 0 auto; }
}
@media (max-width: 1050px) {
  .job-head { grid-template-columns: 1fr; }
  .job-head .head-actions { width: auto; }
}
@media (max-width: 700px) {
  .journey-body:has(.journey-status) { grid-template-columns: 1fr; }
  .journey-body [data-live-arrival]:not(:empty) { border-left: 0; border-top: 1px solid var(--c-line); padding: 20px; }
  .journey-body .journey-status { padding: 20px; }
}
@media (max-width: 540px) {
  .job-head { margin-bottom: var(--sp-4); }
  .job-journey { padding: var(--sp-4); }
  .job-journey .timeline { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
  .job-journey .timeline-step { grid-template-columns: 1fr; grid-template-rows: 14px 20px 18px; gap: 6px; justify-items: center; font-size: var(--fs-xs); }
  .job-journey .timeline-dot { grid-area: 1 / 1; }
  .job-journey .timeline-label { grid-area: 2 / 1; }
  .job-journey .timeline-time { grid-area: 3 / 1; font-size: 11px; }
  .job-journey .timeline-step:nth-child(-n+2)::after { position: absolute; top: 6px; left: calc(50% + 13px); width: calc(100% - 14px); }
  .job-journey .timeline-step.is-ended { grid-template-columns: 14px max-content; grid-template-rows: 22px; justify-content: center; }
  .job-journey .timeline-step.is-ended .timeline-label { grid-area: 1 / 2; }
  .journey-body .journey-status h2 { font-size: 21px; }
}

/* ---------- the workspace shell: sidebar, content header (2026-09-22, userbus/docs#9) ----------
   A signed-in page is a full-height sidebar and a content column. The sidebar carries everything the
   customer navigates by; the slim header carries only the page's ancestors and the balance, which is
   billing's door. The header's inner box and <main> share one width and one gutter, so the breadcrumb
   starts on the same vertical line as the page's title. */

.app-shell--workspace { flex-direction: row; align-items: stretch; }

.sidebar {
  position: sticky;
  top: 0;
  flex: none;
  width: 248px;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: 0 var(--sp-3) var(--sp-3);
  background: var(--c-bg-raised);
  border-right: 1px solid var(--c-line);
  z-index: 40;
}
.sidebar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 56px;
  flex: none;
  padding: 0 var(--sp-1);
  border-bottom: 1px solid var(--c-line);
  margin: 0 calc(-1 * var(--sp-3));
  padding: 0 var(--sp-4);
}
.sidebar .brand { min-height: 0; gap: var(--sp-2); }
.sidebar .brand-name { font-size: 1.25rem; }
.sidebar-top-end { display: flex; align-items: center; gap: var(--sp-2); }
.sidebar-top .theme-toggle { width: 36px; height: 36px; }
.sidebar-top .theme-toggle svg { width: 20px; height: 20px; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--c-text-soft);
  cursor: pointer;
}
.icon-btn:hover { background: var(--c-surface-2); color: var(--c-text); text-decoration: none; }
.icon-btn--small { width: 28px; height: 28px; }
.icon { flex: none; display: block; }
.icon-btn--small .icon { width: 16px; height: 16px; }
.sidebar-close, .menu-btn { display: none; }

.workspace-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
  padding: 3px;
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  flex: none;
}
.workspace-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 30px;
  padding: 0 var(--sp-2);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--c-text-dim);
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
}
.workspace-option[aria-pressed="true"] { background: var(--c-surface-3); color: var(--c-text); }
.workspace-option:disabled { cursor: not-allowed; }
.workspace-option .soon {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  padding: 3px 5px;
  border-radius: var(--r-sm);
  border: 1px solid var(--c-line-strong);
  color: var(--c-text-dim);
}

.sidebar-action { flex: none; }
/* ON THE PAGE IT OPENS, New video is WHERE YOU ARE, not a second yellow button beside Generate: it takes
   the sidebar's own current-item treatment (the accent's quiet fill and an accent icon). */
.sidebar-action .btn-primary[aria-current="page"],
.header-new[aria-current="page"] { background: var(--c-selected); border-color: var(--c-selected-line); color: var(--c-text); }
.sidebar-action .btn-primary[aria-current="page"] .icon,
.header-new[aria-current="page"] .icon { color: var(--c-accent-ink); }

.sidebar-nav, .project-list { display: flex; flex-direction: column; gap: 2px; list-style: none; margin: 0; padding: 0; }
.side-link {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 0 10px;
  border-radius: var(--r-md);
  color: var(--c-text-soft);
  font-size: var(--fs-sm);
  font-weight: 500;
}
.side-link:hover { background: var(--c-surface-2); color: var(--c-text); text-decoration: none; }
.side-link .icon { color: var(--c-text-dim); }
.side-link[aria-current="page"] { background: var(--c-selected); color: var(--c-text); font-weight: 700; }
.side-link[aria-current="page"] .icon { color: var(--c-accent-ink); }
.side-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.side-count { flex: none; font-size: var(--fs-xs); color: var(--c-text-dim); font-variant-numeric: tabular-nums; }

.sidebar-section { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.sidebar-section-head { display: flex; align-items: center; justify-content: space-between; padding: 0 var(--sp-1) 0 10px; flex: none; }
.sidebar-section-title {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-text-dim);
}
.sidebar-section-title:hover, .sidebar-section-title[aria-current="page"] { color: var(--c-text); text-decoration: none; }
.sidebar-section .project-list { overflow-y: auto; min-height: 0; scrollbar-width: thin; }
.sidebar-empty { margin: 0; padding: var(--sp-1) 10px; font-size: var(--fs-xs); color: var(--c-text-dim); }
.inline-form { margin: 0; display: inline-flex; }

/* THE FOOT: Invite, then the account row (Settings with the customer's name, and Sign out). */
.sidebar-foot { flex: none; display: flex; flex-direction: column; gap: 2px; border-top: 1px solid var(--c-line); padding-top: var(--sp-3); }
.sidebar-account { display: flex; align-items: center; gap: var(--sp-1); }
.side-settings { flex: 1; min-width: 0; min-height: 44px; }
.side-settings .side-label { display: flex; flex-direction: column; line-height: 1.2; }
.side-sub { font-size: var(--fs-xs); color: var(--c-text-dim); font-weight: 400; overflow: hidden; text-overflow: ellipsis; }

.workspace-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 100vh; }
.content-header {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--c-bg);
  border-bottom: 1px solid var(--c-line);
}
.content-header .topbar-inner { height: 56px; padding-top: 0; padding-bottom: 0; flex-wrap: nowrap; gap: var(--sp-3); }
.crumbs { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; font-size: var(--fs-sm); color: var(--c-text-dim); }
.crumbs a { color: var(--c-text-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crumbs a:hover { color: var(--c-text); }
.crumb-sep { color: var(--c-line-strong); }
.content-header .topbar-end { flex-wrap: nowrap; }

/* The header balance, with the number and its label as real text. */
.balance-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--ctl-md);
  padding: 0 var(--sp-3);
  border: 1px solid var(--c-line);
  border-radius: var(--r-pill);
  color: var(--c-text);
  font-size: var(--fs-sm);
  text-decoration: none;
  white-space: nowrap;
}
.balance-badge .icon { width: 16px; height: 16px; color: var(--c-accent-ink); }
.balance-badge .balance-label { color: var(--c-text-dim); }
.balance-badge .balance-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.balance-badge:hover { border-color: var(--c-selected-line); text-decoration: none; }
.balance-badge[aria-current="page"] { border-color: var(--c-selected-line); background: var(--c-selected); }

.sidebar-scrim { display: none; }

/* ---------- projects ---------- */

.project-head { align-items: flex-start; flex-direction: column; gap: var(--sp-1); }
.project-title-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; max-width: 100%; }
.project-title-row h1 { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.project-lede { margin: 0; }
.rename-form { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; width: 100%; }
.rename-input {
  flex: 1 1 320px;
  max-width: 560px;
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.03em;
  padding: 2px var(--sp-2);
  min-height: 44px;
}

.grid-contents { display: contents; list-style: none; margin: 0; padding: 0; }
.tile-slot--new { min-height: 220px; }
.new-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 100%;
  padding: var(--sp-5);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--c-text-soft);
  background: transparent;
  border: 2px dashed var(--c-line-strong);
  border-radius: var(--r-md);
  cursor: pointer;
}
.new-tile .icon { width: 28px; height: 28px; }
.new-tile:hover { color: var(--c-text); border-color: var(--c-selected-line); background: var(--c-selected); text-decoration: none; }
.project-empty { margin-top: var(--sp-3); }

.project-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--sp-4);
}
.project-grid > li { display: flex; min-width: 0; }
.new-tile--project { min-height: 132px; }
.project-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  min-height: 132px;
  padding: var(--sp-4);
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  color: var(--c-text);
}
.project-card:hover { border-color: var(--c-selected-line); text-decoration: none; }
.project-card-icon { color: var(--c-accent-ink); margin-bottom: auto; }
.project-card-icon .icon { width: 24px; height: 24px; }
.project-card-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-card-meta { font-size: var(--fs-xs); color: var(--c-text-dim); }
.project-card--unsorted .project-card-icon .icon { color: var(--c-text-dim); }
.project-grid-note { grid-column: 1 / -1; }

/* THE COMPOSER'S PROJECT FIELD: a select that spans the form's own width, since it is one decision. */
.project-field .select { width: 100%; }
.project-field .field-hint { margin-top: 6px; }

/* THE VIDEO'S PROJECT CARD: ONE ROW - the name of the decision, a select at a reading width (a folder
   name is short; a 1,100px select is not a better select) and Move beside it at the same height - and,
   under it, the links to the videos it was made from. */
.project-move-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin: 0; }
.project-move-form .job-project-title { margin: 0 var(--sp-2) 0 0; font-size: var(--fs-md); }
.project-move-form .select { flex: 0 1 320px; width: auto; min-width: 0; }
.job-sources { margin-top: var(--sp-4); border-top: 1px solid var(--c-line); padding-top: var(--sp-3); }
.job-sources .field-label { margin: 0 0 var(--sp-2); }
.job-sources ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }

/* A VARIATION MARKER: a chip like the state's, in its own colour, so the two never read as one. */
.chip--variation { color: var(--c-accent-ink); border-color: var(--c-accent-line); }

/* THE TILE'S PROJECT LINK: one more muted fact on the date line, secondary to the video's state. */
.tile-project { color: var(--c-text-dim); }
.tile-project:hover { color: var(--c-text); }

/* THE DELETE CONFIRMATION: the same shape as the rename form, but stating the consequence. */
.delete-form { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; width: 100%; }
.delete-question { flex: 1 1 320px; margin: 0; }

.settings-card { max-width: 640px; margin-bottom: var(--sp-4); }
.settings-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
/* Date and time (userbus/docs#32): a zone field and two format radios. */
.settings-form { max-width: 420px; }
.settings-form .field { margin-bottom: var(--sp-3); }
.radio-set { border: 0; padding: 0; margin: 0 0 var(--sp-3); min-width: 0; }
.radio-set > .radio-row { display: flex; margin: 0; font-weight: 400; align-items: center; gap: var(--sp-2); padding: var(--sp-1) 0; font-size: var(--fs-sm); cursor: pointer; }
.radio-set > .radio-row input { margin: 0; accent-color: var(--c-accent); }

/* ---------- the drawer: below 900px the sidebar slides over the content ---------- */
@media (max-width: 900px) {
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: min(288px, 86vw);
    height: auto;
    overscroll-behavior: contain;
    transform: translateX(-100%);
    /* visibility waits for the slide, so the drawer is seen leaving and is out of the tab order after */
    transition: transform 200ms ease, visibility 0s linear 200ms;
    visibility: hidden;
  }
  /* THE OPEN STATE IS ITS OWN ATTRIBUTE ON <html>, never `data-sidebar-open`: that one marks the menu
     button, and while <html> carried it every click inside the drawer read as "open", so × did nothing. */
  [data-sidebar-shown] { overflow: hidden; }
  [data-sidebar-shown] .sidebar { transform: none; visibility: visible; transition: transform 200ms ease; }
  /* THE SCRIM IS ALWAYS IN THE LAYOUT HERE and fades; hidden, it takes no taps. A tap on it closes the
     drawer instead of reaching the page underneath. */
  .sidebar-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 35;
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    visibility: hidden;
    transition: opacity 200ms ease, visibility 0s linear 200ms;
  }
  [data-sidebar-shown] .sidebar-scrim { opacity: 1; visibility: visible; transition: opacity 200ms ease; }
  .sidebar-close, .menu-btn { display: inline-flex; width: 44px; height: 44px; }
  .content-header .topbar-end { margin-left: auto; width: auto; }
  /* THE DASHED TILE STAYS FIRST BUT SHORT, so the first video is in view on a phone. */
  .tile-slot--new { min-height: 0; flex-basis: 100%; }
  .tile-slot--new .new-tile { min-height: 112px; flex-direction: row; }
  .content-header .topbar-inner { padding-left: var(--sp-3); padding-right: var(--sp-3); }
  .balance-badge .balance-label { display: none; }
  /* THE DRAWER IS OPENED BY A FINGER here, so its rows are finger-sized too. */
  .side-link { min-height: 44px; }
  .icon-btn--small { width: 44px; height: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar, .sidebar-scrim, [data-sidebar-shown] .sidebar, [data-sidebar-shown] .sidebar-scrim { transition: none; }
}

/* ---------- THE VIDEO COMPOSER (2026-09-23) ----------
   One card: the inputs beside the prompt as a row of tiles, the prompt, and the settings as a row of
   chips. Under it, one strip holds the money (limit and the most this press can cost), the arrival and
   Generate. Every chip is a <details> around native fields, so the form works with no script; the
   script only closes panels and rewrites a chip's value. Tokens only, so both themes follow. */
.composer-stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; max-width: 1040px; }
.composer-stack > .alert { margin: 0; }
.composer-card { position: relative; display: grid; gap: 12px; padding: 14px; border: 1px solid var(--c-line-strong); border-radius: var(--r-lg); background: var(--c-surface); }
.composer-card.is-dragging { border-color: var(--c-accent-ink); outline: 1px solid var(--c-accent); outline-offset: 0; }

.input-tiles { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
.input-tile { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; min-height: 84px; padding: 10px 8px; border: 1px dashed transparent; border-radius: var(--r-lg); background: var(--c-surface-2); color: var(--c-text-soft); font-size: var(--fs-sm); line-height: 1.2; text-align: center; cursor: pointer; transition: background .12s, border-color .12s; }
.input-tile:hover { background: var(--c-surface-3); }
/* INSIDE A CLIPPED ROW (the tiles scroll sideways on a phone) THE RING IS DRAWN INSIDE the control:
   2px, inset, the same accent - an outside ring there would be cut off by the scroller. */
.input-tile:focus-within { outline: 2px solid var(--c-accent-ink); outline-offset: -2px; }
.input-tile.is-over { border-color: var(--c-accent-ink); background: var(--c-selected); }
.input-tile.is-full { border-style: solid; border-color: var(--c-line-strong); }
.input-tile-file { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.input-tile-icon { display: grid; place-items: center; color: var(--c-text-dim); }
.input-tile .icon, .setting-chip .icon { fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.input-tile .icon { width: 20px; height: 20px; }
.input-tile-count { position: absolute; top: 6px; right: 8px; font: 600 11px var(--font-mono); color: var(--c-accent-ink); }
.input-tile-count:empty { display: none; }
.input-tile.is-soon { cursor: not-allowed; color: var(--c-text-dim); background: transparent; border: 1px dashed var(--c-line); }
.input-tile.is-soon:hover { background: transparent; }
/* A TILE THAT IS NOT OFFERED YET SAYS SO IN TEXT (2026-09-26): the page's smallest size, under the label – it
   replaced a 9px uppercase tag and a `title` tooltip no touch screen shows. */
.input-tile-soon { font-size: var(--fs-xs); line-height: var(--lh-tight); color: var(--c-text-dim); }
.input-note { display: block; }
.input-note + .input-note { margin-top: var(--sp-2); }
.inputs-label { margin-bottom: var(--sp-2); }
/* The project select and, for "New project…", its name field on one row (userbus-studio#36). */
.project-picker { display: flex; gap: var(--sp-2); flex-wrap: wrap; min-width: 0; }
.project-picker > .select { flex: 0 1 auto; min-width: 0; }
.project-name { flex: 1 1 220px; min-width: 0; }
.project-name[hidden] { display: none; }
.project-name .input { width: 100%; }

.attachment-tray { display: flex; flex-wrap: wrap; gap: 8px; }
.frame-fit { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.attachment-tray[hidden] { display: none; }
.attachment { position: relative; display: grid; grid-template-columns: 44px auto; align-items: center; gap: 2px 8px; padding: 4px 30px 4px 4px; border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-surface-2); max-width: 240px; }
.attachment-thumb { grid-row: span 2; display: grid; place-items: center; width: 44px; height: 44px; border-radius: var(--r-sm); overflow: hidden; background: var(--c-media, #000); color: var(--c-text-dim); }
.attachment-thumb canvas, .attachment-thumb video, .attachment-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A STORED PHOTO'S EXIF ORIENTATION, applied here (2026-09-25, userbus/docs#11): the store strips the tag from the
   bytes and keeps the number on the record, so /inputs/:id/content draws un-rotated and the tile turns it. The
   box is square, so a quarter turn stays inside it. 2 mirror, 3 half turn, 4 flip, 5 transpose, 6 quarter turn
   clockwise, 7 transverse, 8 quarter turn anticlockwise (EXIF 2.3, tag 0x0112). */
.attachment-thumb img[data-orientation="2"] { transform: scaleX(-1); }
.attachment-thumb img[data-orientation="3"] { transform: rotate(180deg); }
.attachment-thumb img[data-orientation="4"] { transform: scaleY(-1); }
.attachment-thumb img[data-orientation="5"] { transform: rotate(90deg) scaleY(-1); }
.attachment-thumb img[data-orientation="6"] { transform: rotate(90deg); }
.attachment-thumb img[data-orientation="7"] { transform: rotate(-90deg) scaleY(-1); }
.attachment-thumb img[data-orientation="8"] { transform: rotate(-90deg); }
/* AN UPLOAD ON ITS WAY: a thin bar along the item's foot and a dimmed thumbnail, until the id comes back. */
.attachment-progress { position: absolute; left: 6px; right: 30px; bottom: 3px; height: 3px; border: 0; border-radius: var(--r-sm); background: var(--c-surface-3); color: var(--c-accent-ink); -webkit-appearance: none; appearance: none; overflow: hidden; }
.attachment-progress::-webkit-progress-bar { background: var(--c-surface-3); }
.attachment-progress::-webkit-progress-value { background: var(--c-accent-ink); }
.attachment-progress::-moz-progress-bar { background: var(--c-accent-ink); }
.attachment[data-attachment-state="uploading"] .attachment-thumb { opacity: .6; }
.attachment-thumb .icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }
.attachment-mention { padding: 0; border: 0; background: none; font: 600 12px var(--font-mono); color: var(--c-accent-ink); cursor: pointer; text-align: left; }
.attachment-mention:hover { text-decoration: underline; }
.attachment-role { font-size: 11px; color: var(--c-text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 150px; }
.attachment-remove { position: absolute; top: 50%; right: 2px; transform: translateY(-50%); display: grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--c-text-dim); cursor: pointer; font-size: 16px; line-height: 1; }
.attachment-remove:hover { background: var(--c-surface-3); color: var(--c-text); }
.role-chooser { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--c-selected-line); border-radius: var(--r-md); background: var(--c-selected); font-size: var(--fs-sm); }

.prompt-field { position: relative; margin: 0; }
.composer-card .prompt-head { margin-bottom: 4px; }
.composer-card .prompt-head .field-label { font-size: var(--fs-xs); color: var(--c-text-dim); font-weight: 500; }
.composer-card .textarea { min-height: 96px; height: 96px; padding: 4px 2px; border: 0; background: transparent; font-size: 16px; line-height: 1.5; resize: vertical; }
/* THE PROMPT SHOWS WHERE THE CARET IS (WCAG 2.4.7): the borderless field keeps the page's own focus
   ring, so no rule here removes it. It used to set `outline: none`, and the one field every customer
   types into showed nothing. */
.composer-card .prompt-footer { margin-top: 4px; }
.mention-list { position: absolute; left: 0; top: 100%; z-index: 25; display: grid; gap: 2px; min-width: 240px; padding: 6px; border: 1px solid var(--c-line-strong); border-radius: var(--r-md); background: var(--c-surface-3); }
.mention-list[hidden] { display: none; }
.mention-option { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: var(--r-md); cursor: pointer; font-size: var(--fs-sm); }
.mention-option[aria-selected="true"], .mention-option:hover { background: var(--c-surface-2); }
.mention-option .attachment-thumb { width: 28px; height: 28px; grid-row: auto; }
.mention-option code { font: 600 12px var(--font-mono); color: var(--c-accent-ink); }
.prompt-warning { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--c-warn); }

.setting-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding-top: 10px; border-top: 1px solid var(--c-line); }
.setting-chip { position: relative; }
.setting-chip > summary { display: inline-flex; align-items: center; gap: 6px; min-height: var(--ctl-md); padding: 0 var(--sp-3); border: 1px solid transparent; border-radius: var(--r-md); color: var(--c-text-soft); font-size: 14px; white-space: nowrap; cursor: pointer; list-style: none; user-select: none; }
.setting-chip > summary::-webkit-details-marker { display: none; }
.setting-chip > summary:hover, .setting-chip[open] > summary { background: var(--c-surface-2); border-color: var(--c-line); }
.chip-icon { display: inline-grid; color: var(--c-text-dim); }
.chip-value { font-variant-numeric: tabular-nums; }
.chip-caret { display: inline-grid; color: var(--c-text-dim); }
.chip-caret .icon { width: 12px; height: 12px; }
.setting-chip.chip-advanced { margin-left: auto; }
.chip-panel { position: absolute; left: 0; top: calc(100% + 6px); z-index: 20; display: grid; gap: 8px; width: max-content; min-width: 240px; max-width: min(360px, 86vw); padding: 12px; border: 1px solid var(--c-line-strong); border-radius: var(--r-lg); background: var(--c-surface-3); }
.chip-advanced .chip-panel { left: auto; right: 0; }
.chip-panel-title { margin: 0; font-size: var(--fs-xs); color: var(--c-text-dim); text-transform: uppercase; letter-spacing: 0.08em; }
.chip-panel .field { margin: 0; }
.chip-panel .field-hint { margin: 0; font-size: var(--fs-xs); line-height: 1.5; }
/* THE ADD CREDIT AMOUNTS (2026-09-27, userbus/userbus-studio#48): radio buttons dressed as pills - a 1px line at
   rest, the selected one filled - and an Other amount field after them, instead of a bare square select. */
.amount-picker { border: 0; margin: 0 0 var(--sp-4); padding: 0; min-width: 0; }
.amount-picker legend { margin-bottom: var(--sp-2); padding: 0; }
.amount-options { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.amount-option { position: relative; display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--sp-4); border: 1px solid var(--c-line-strong); border-radius: var(--r-pill); background: var(--c-surface); font-weight: 600; font-variant-numeric: tabular-nums; cursor: pointer; }
.amount-option:hover { border-color: var(--c-text-dim); }
.amount-option input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.amount-option:has(input:checked) { background: var(--c-selected); border-color: var(--c-text); }
.amount-option:has(input:focus-visible) { outline: var(--focus); outline-offset: var(--focus-offset); }
.amount-other { margin-top: var(--sp-3); }
.amount-other-field { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 var(--sp-3); border: 1px solid var(--c-line-strong); border-radius: var(--r-pill); background: var(--c-surface); }
.amount-other-field:focus-within { border-color: var(--c-text); }
.amount-other-unit { color: var(--c-text-dim); font-weight: 600; }
.amount-other-field input { width: 9em; border: 0; background: transparent; padding: 0; min-height: 40px; font: inherit; color: inherit; outline: none; }
.amount-picker .field-hint { margin-top: var(--sp-2); }
[data-topup-history] { margin-top: var(--sp-6); }
section[data-payment-method-status] { margin-bottom: var(--sp-5); }
.chip-options { display: grid; gap: 2px; }
.chip-options--row { grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 6px; }
.chip-option { display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 6px 10px; border-radius: var(--r-md); font-size: 14px; cursor: pointer; }
.chip-option:hover { background: var(--c-surface-2); }
.chip-option:has(input:checked) { background: var(--c-selected); }
.chip-option input { width: 16px; height: 16px; margin: 0; accent-color: var(--c-accent-ink); }
.chip-option-main { font-weight: 550; font-variant-numeric: tabular-nums; }
.chip-option-note { margin-left: auto; padding-left: 12px; font-size: var(--fs-xs); color: var(--c-text-dim); }
.chip-option.is-static { cursor: default; background: var(--c-selected); }
.chip-option.is-disabled { cursor: not-allowed; color: var(--c-text-dim); }
.chip-option.is-disabled:hover { background: transparent; }
.chip-option[data-aspect]::before { content: ""; flex: none; border: 1.5px solid currentColor; border-radius: var(--r-sm); }
.chip-option[data-aspect="landscape"]::before { width: 18px; height: 10px; }
.chip-option[data-aspect="portrait"]::before { width: 10px; height: 18px; }
.chip-option[data-aspect="square"]::before { width: 14px; height: 14px; }
/* THE SHAPE MENU IS A TABLE (userbus-studio#38): outline, radio, name, description and ratios each keep one column
   across the rows (subgrid), whichever rows carry a radio. */
.shape-options { grid-template-columns: 18px 16px max-content minmax(0, 1fr) max-content; column-gap: 10px; }
.shape-options > .chip-option { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: center; }
.shape-options > .chip-option::before { grid-column: 1; justify-self: center; }
.shape-options > .chip-option > input { grid-column: 2; }
.shape-options > .chip-option > .chip-option-main { grid-column: 3; }
.shape-options > .chip-option > .chip-option-note { grid-column: 4; margin: 0; padding: 0; }
.shape-options > .chip-option > .shape-ratios { grid-column: 5; font-size: var(--fs-xs); color: var(--c-text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (min-width: 541px) { .setting-chip[data-chip="aspect"] > .chip-panel { min-width: 440px; } }
/* No row to choose (one shape on offer): no radio column either. */
.shape-options:not(:has(input)) { grid-template-columns: 18px max-content minmax(0, 1fr) max-content; }
.shape-options:not(:has(input)) > .chip-option > .chip-option-main { grid-column: 2; }
.shape-options:not(:has(input)) > .chip-option > .chip-option-note { grid-column: 3; }
.shape-options:not(:has(input)) > .chip-option > .shape-ratios { grid-column: 4; }
@media (max-width: 540px) {
  .shape-options { grid-template-columns: 18px 16px max-content minmax(0, 1fr); }
  .shape-options > .chip-option > .shape-ratios { grid-column: 3 / -1; grid-row: 2; }
  .shape-options > .chip-option:has(.shape-ratios:empty) > .shape-ratios { display: none; }
}
.chip-option--compact { justify-content: center; padding: 6px; }
.chip-option--compact input { position: absolute; opacity: 0; }
.chip-option--compact { position: relative; border: 1px solid var(--c-line); }
.chip-option--compact:has(input:focus-visible) { outline: 2px solid var(--c-accent-ink); outline-offset: -2px; }
.chip-panel .model-cards { margin: 0; padding: 0; border: 0; }
.chip-panel .model-cards legend { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.chip-panel .model-card { min-height: 52px; }
.chip-panel .duration-field { width: 280px; max-width: 100%; }
.chip-panel .duration-field > label { font-size: var(--fs-sm); margin-bottom: 6px; }
.chip-panel .param-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

.booking-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 12px 24px; padding: 14px 16px; border: 1px solid var(--c-line); border-radius: var(--r-lg); background: var(--c-bg-raised); }
.booking-price { grid-column: 1; grid-row: 2; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 24px; min-width: 0; }
.booking-bar .price-limit-field { width: 240px; margin: 0; }
.booking-bar .price-limit-label { margin-bottom: 4px; }
.booking-bar .number-control { min-height: 44px; }
.booking-bar .number-value input { font-size: 20px; }
.booking-bar .number-hint { display: none; }
.booking-bar .budget-total { display: grid; grid-template-columns: auto; gap: 2px; margin: 0; padding: 0 0 2px; border: 0; }
.booking-bar .budget-total > span:first-child { font-size: var(--fs-xs); color: var(--c-text-dim); }
.booking-bar .budget-total strong { font-size: var(--fs-xl); line-height: 1.1; }
.booking-bar > .arrival-verdict { grid-column: 1 / -1; grid-row: 1; }
/* THE FOOTER IS CAPPED: the bar's second column is `auto`, so without a cap a long sentence here takes the price limit's room (2026-09-26). */
.booking-footer { grid-column: 2; grid-row: 2; max-width: 30rem; display: flex; align-items: flex-end; justify-content: flex-end; flex-wrap: wrap; gap: 10px 12px; }
.booking-footer .project-field { margin: 0; min-width: 180px; max-width: 240px; }
.booking-footer .project-field .field-label { font-size: var(--fs-xs); color: var(--c-text-dim); margin-bottom: 4px; }
.booking-footer .project-field .select { min-height: 44px; }
.booking-footer .fine { flex-basis: 100%; margin: 0; text-align: right; font-size: var(--fs-xs); }
.booking-footer .primary-action { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; margin: 0; }
.booking-footer .primary-action .field-error { margin: 0; max-width: 360px; text-align: right; }
.generate-button { min-width: 160px; }
.generate-count { font: 600 13px var(--font-mono); opacity: .8; }
.generate-count:empty { display: none; }
.arrival-summary { grid-column: 1 / -1; grid-row: 3; padding-top: 10px; border-top: 1px solid var(--c-line); font-size: var(--fs-sm); }
.arrival-summary > summary { display: flex; align-items: center; gap: var(--sp-3); min-height: 28px; cursor: pointer; list-style: none; color: var(--c-text-soft); }
.arrival-summary > summary::-webkit-details-marker { display: none; }
/* "Details" IS A STANDALONE TEXT LINK: quiet at rest, underlined under the pointer. */
.arrival-summary > summary::after { content: "Details"; margin-left: auto; font-size: var(--fs-xs); color: var(--c-text-dim); text-underline-offset: 0.18em; }
.arrival-summary > summary:hover::after { color: var(--c-text); text-decoration: underline; }
.arrival-summary[open] > summary::after { content: "Hide"; }
.arrival-summary-label { font-size: var(--fs-xs); font-weight: 500; color: var(--c-text-dim); }
.arrival-summary .arrival-preview { margin: 8px 0 0; padding: 0; border: 0; }
.arrival-summary .route-preview { margin: 6px 0 12px; max-width: 360px; }
.arrival-summary .arrival-figure { font-size: var(--fs-lg); }

@media (max-width: 760px) {
  .input-tiles { display: flex; overflow-x: auto; scroll-snap-type: x proximity; padding-bottom: 4px; }
  .input-tile { flex: 0 0 104px; scroll-snap-align: start; }
  .booking-bar { grid-template-columns: minmax(0, 1fr); }
  .booking-price { grid-column: 1; grid-row: auto; }
  .booking-footer { grid-column: 1; grid-row: auto; max-width: none; justify-content: stretch; }
  .arrival-summary { grid-row: auto; }
  .booking-footer .project-field { flex: 1 1 180px; max-width: none; }
  .booking-footer .primary-action { flex: 1 1 100%; align-items: stretch; }
  .booking-footer .primary-action .field-error, .booking-footer .fine { text-align: left; }
  .generate-button { width: 100%; }
  .setting-chip.chip-advanced { margin-left: 0; }
  /* On a phone a chip's panel is a sheet at the bottom of the screen, above everything. */
  .setting-chip[open] > .chip-panel { position: fixed; left: 8px; right: 8px; top: auto; bottom: 8px; width: auto; max-width: none; max-height: 70vh; overflow-y: auto; z-index: 60; }
  .setting-chip[open]::before { content: ""; position: fixed; inset: 0; z-index: 55; background: #0007; }
  .chip-panel .duration-field { width: auto; }
  /* A "?" INSIDE THE SHEET opens over the sheet's own top edge: the sheet scrolls, so a bubble drawn above
     it would be cut off. The field and its label stay visible below the bubble. */
  .setting-chip[open] > .chip-panel .tip { position: static; }
  .setting-chip[open] > .chip-panel .tip-content { top: 8px; bottom: auto; left: 8px; right: 8px; transform: none; width: auto; max-width: none; }
}

.composer-top { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px 24px; flex-wrap: wrap; max-width: 1040px; margin-bottom: 12px; }
.composer-top .draft-status { flex: 1 1 320px; margin: 0; }
.composer-top .project-field { display: flex; align-items: center; gap: 10px; margin: 0; }
.composer-top .project-field .field-label { margin: 0; font-size: var(--fs-sm); color: var(--c-text-dim); white-space: nowrap; }
.composer-top .project-field .select { min-height: 36px; width: auto; min-width: 180px; max-width: 280px; padding-top: 4px; padding-bottom: 4px; }
.composer-top .project-name .input { min-height: 36px; padding-top: 4px; padding-bottom: 4px; min-width: 220px; }
.composer-top .project-field > p { flex-basis: 100%; margin: 4px 0 0; }
.composer-top .project-field { flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 760px) {
  .composer-top .project-field { width: 100%; justify-content: flex-start; }
  .composer-top .project-field .select { flex: 1; max-width: none; }
  .composer-top .project-picker { flex: 1 1 100%; }
  .composer-top .project-name .input { min-width: 0; }
}

/* THE PROJECT'S VIDEOS UNDER THE COMPOSER: the project page's own tiles, at the composer's width. */
.create-feed { max-width: 1040px; margin-top: 32px; }
.create-feed-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.create-feed-head h2 { margin: 0; font-size: var(--fs-lg); letter-spacing: -0.02em; }
.create-feed-head .text-link { font-size: var(--fs-sm); color: var(--c-text-dim); }
.create-feed-head .text-link:hover { color: var(--c-text); }
.create-feed-note { margin: 0; padding: 20px; border: 1px dashed var(--c-line); border-radius: var(--r-lg); }
.create-feed-more { margin: 16px 0 0; font-size: var(--fs-sm); }
.create-feed[aria-busy="true"] .create-feed-grid { opacity: .6; transition: opacity .15s; }

/* ---------- ONE SHAPE PER CONCERN (2026-09-25) ----------
   The rules that make a component look the same wherever a page uses it. They sit after the page
   sections they align, so an older page rule cannot win over them by coming later in the file. */

/* FIELDS AT BUTTON HEIGHT: an input or a select is 36px like the button beside it (Move, Send, Save),
   44px where the pointer is a finger; the height is exact for the same reason a button's is. */
.input, .select { min-height: var(--ctl-md); padding-block: 0; line-height: 20px; }
.rename-input { line-height: 1.25; }

/* THE HEADER'S NEW VIDEO: rendered only while the sidebar is a drawer (see the drawer block) - a label
   beside the icon on a tablet, the icon alone (with the words for a screen reader) on a phone. */
/* THE CRUMBS GIVE WAY, NOT THE CONTROLS: the crumbs take only the room the header's controls leave, and
   a long project name ends in an ellipsis instead of pushing the balance past a phone's edge. */
.content-header .crumbs { flex: 1 1 0; }
.crumbs a { min-width: 0; }
.crumb-sep { flex: none; }
.header-new { display: none; flex: none; }
@media (max-width: 900px) {
  .header-new { display: inline-flex; }
  /* WHILE THE DRAWER IS OPEN its own New video is on screen, so the header's steps aside: still one New
     video in view and in the tab order (hidden, not removed, so the header does not reflow under the
     scrim). */
  [data-sidebar-shown] .header-new { visibility: hidden; }
}
@media (max-width: 720px) {
  .header-new { width: var(--ctl-touch); padding: 0; }
  .header-new .header-new-label { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  /* A HEADER WITH MORE TO SAY THAN ONE ROW HOLDS (the service is down and the balance cannot be
     confirmed) takes a second row for the service notice, rather than pushing the balance off a phone. */
  .content-header .topbar-inner:has([data-service-state]) { height: auto; min-height: 56px; padding-block: var(--sp-2); }
  .content-header .topbar-end:has([data-service-state]) { flex-wrap: wrap; justify-content: flex-end; }
  .content-header [data-service-state] { order: 1; }
}

/* A FINGER-SIZED TARGET FOR EVERY STANDALONE CONTROL where the pointer is a finger - by width AND by
   pointer, because a tablet is a finger at 820px. The ≤720px block above keeps its own pinned line. */
@media (max-width: 720px), (pointer: coarse) {
  .btn { min-height: var(--ctl-touch); }
  .btn-lg, .btn-xl { min-height: var(--ctl-touch-lg); }
  .input, .select, .composer-top .project-field .select { min-height: var(--ctl-touch); }
  .icon-btn, .icon-btn--small { width: var(--ctl-touch); height: var(--ctl-touch); }
  .setting-chip > summary, .arrival-summary > summary, .side-link { min-height: var(--ctl-touch); }
  .attachment { padding-right: 48px; }
  .attachment-remove { width: var(--ctl-touch); height: var(--ctl-touch); right: 0; }
  .text-link { display: inline-flex; align-items: center; min-height: var(--ctl-touch); }
  .crumbs a { line-height: var(--ctl-touch); }
  .advanced > summary { padding-block: var(--sp-3); }
  .balance-badge { height: var(--ctl-touch); }
}

/* A GROUP SPLITS ITS ROW ON A PHONE: one button spans the row, two share it, a third starts the next
   row - never a stack of full-width bars, and never two buttons touching. */
@media (max-width: 720px) {
  .btn-group > .btn, .primary-action > .btn, .head-actions > .btn, .invite-actions > .btn,
  .rename-form > .btn, .delete-form > .btn, .row > .btn { flex: 1 1 calc(50% - var(--sp-1)); }
  .booking-footer .primary-action > .btn { flex: none; }
}

/* THE DELIVERED VIDEO'S ONE ACTION SITS ON THE PLAYER'S FOOT: the facts line (length · frame · size)
   and Download share the row directly under the picture (`.stage-foot`, views.ex `stage/2`), so the
   answer to "is it ready, and what can I do with it" is one glance. On a phone Download takes the row. */
.stage-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-4); margin-top: var(--sp-3); }
.stage-foot > p { margin: 0; }
.stage-foot > p:first-child { flex: 1 1 0; min-width: 0; }
.stage-foot > p:last-child { flex: 0 0 auto; }
@media (max-width: 720px) {
  .stage-foot > p:last-child { flex: 1 1 100%; }
  .stage-foot > p > .btn-primary { width: 100%; }
}
/* Play and Pause swap in one place, so the button keeps one width and the progress bar does not jump. */
.stage-transport .btn { min-width: 88px; }

/* A SIGNED-OUT PAGE IS ONE TASK IN ONE CENTRED COLUMN: the brand, the page and the footer's words all
   start on the same line, and the header's and footer's rules still run the full width of the window. */
.app-shell:not(.app-shell--workspace) { --public-col: 640px; }
.app-shell:not(.app-shell--workspace) .topbar-inner,
.app-shell:not(.app-shell--workspace) > main { max-width: calc(var(--public-col) + 2 * var(--sp-5)); }
.app-shell:not(.app-shell--workspace) > .footer { max-width: none; padding-inline: max(var(--sp-5), calc((100% - var(--public-col)) / 2)); }
.app-shell:not(.app-shell--workspace) .signin { max-width: none; margin: var(--sp-6) 0; }
@media (max-width: 720px) {
  .app-shell:not(.app-shell--workspace) > .footer { padding-inline: var(--sp-3); }
}

/* A DETAIL CARD UNDER THE BILLING TABS IS AS WIDE AS ITS CONTENT NEEDS: short values on a 1,100px card
   leave the reader's eye travelling across empty space (Settings keeps 640px for the same reason). */
.tabs ~ .card { max-width: 720px; }

/* A CHECKBOX AND ITS SENTENCE: the box on the sentence's first line, the sentence wrapping beside it
   rather than under the box, and room before the action that follows. */
label.row:has(> input[type="checkbox"]:first-child) {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  align-items: start;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
  cursor: pointer;
}
label.row:has(> input[type="checkbox"]:first-child) > input { width: 20px; height: 20px; margin: 2px 0 0; }

/* A TABLE'S FIRST COLUMN STARTS ON THE CARD'S OWN EDGE, under the card's heading. */
.invite-table th:first-child, .invite-table td:first-child { padding-left: 0; }


/* THE BOOKING STRIP'S LABELS ARE ONE STYLE: 12px, medium, dim, in sentence case. Uppercase tracking is
   kept for eyebrow labels only (PROJECTS, IN THE QUEUE, a panel's title). */
.booking-bar .field-label, .booking-bar .budget-total > span:first-child, .arrival-summary-label {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--c-text-dim);
  text-transform: none;
  letter-spacing: 0;
}

/* ---- MEMBER INVITATIONS (specs/invitations.md): the page a link opens, the activation page, and the
   member's Invite page. Tokens only, so both themes follow. ---- */
.invite-card { text-align: left; }
.invite-from { color: var(--c-text-dim); font-size: var(--fs-sm); margin: 0; }
.invite-inviter { font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.01em; margin: var(--sp-1) 0 var(--sp-5); color: var(--c-accent-ink); overflow-wrap: anywhere; }
.invite-card h1 { font-size: var(--fs-lg); margin-bottom: var(--sp-2); }
.invite-card .btn-block { margin-top: var(--sp-5); }
.invite-code { font-family: var(--font-mono); font-weight: 700; letter-spacing: 0.12em; }
.invite-code-row { display: flex; gap: var(--sp-2); }
.invite-code-input { font-family: var(--font-mono); font-size: var(--fs-md); letter-spacing: 0.14em; text-transform: uppercase; }
.activation-switch { margin-top: var(--sp-4); }
/* THE WAITLIST (specs/access-requests.md §5): "or" between the two ways forward (userbus-design's Divider), the
   form's own heading one step below the card's, and the code field folded away once the person is on the list. */
.divider { display: flex; align-items: center; gap: var(--sp-3); margin: var(--sp-5) 0; color: var(--c-text-dim); font-size: var(--fs-sm); }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--c-line); }
.waitlist-form h2 { font-size: var(--fs-md); margin: 0 0 var(--sp-2); }
.waitlist-note { min-height: 0; }
.waitlist-code { margin-top: var(--sp-4); }
.waitlist-code > summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 550; color: var(--c-text-soft); }
.waitlist-code > summary:hover { color: var(--c-text); }
.waitlist-code[open] > summary { margin-bottom: var(--sp-3); }
.invite-table td { min-width: 0; }
.invite-table td:last-child { width: 1%; white-space: nowrap; }
.invite-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.invite-send { display: flex; gap: var(--sp-2); min-width: 0; }
.invite-send .input { width: 14rem; }
/* THE REWARDS (2026-09-26): how an invitation pays, on the Invite page; what joining earns, on the page a link
   opens; and where each used code's reward stands, under its status. */
.invite-steps { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); display: grid; gap: var(--sp-2); }
.invite-steps li { padding-left: var(--sp-1); }
.invite-reward { margin: var(--sp-3) 0 0; }
.invite-reward strong { color: var(--c-accent-ink); }
.invite-reward-state { display: block; margin-top: var(--sp-1); font-size: var(--fs-sm); }
/* ONE-PRESS SHARING AND THE REWARDS' PROGRESS (2026-09-28, userbus/docs#38). */
.invite-share-buttons { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.invite-share [data-invite-plain] { margin-top: var(--sp-3); }
.invite-share-result { margin-top: var(--sp-4); }
.invite-share-result label { display: block; font-size: var(--fs-sm); font-weight: 600; margin-bottom: var(--sp-1); }
.invite-share-link { font-family: var(--font-mono); font-size: var(--fs-sm); min-width: 0; flex: 1 1 auto; }
.invite-progress { margin: 0 0 var(--sp-4); }
.invite-progress .meter-fill { background: var(--c-accent); }
.invite-progress-count { font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-sm); }
.invite-progress-words { margin: var(--sp-2) 0 0; font-size: var(--fs-sm); }
.invite-faq-item { border-top: 1px solid var(--c-line); padding: var(--sp-3) 0; }
.invite-faq-item:first-of-type { border-top: 0; padding-top: 0; }
.invite-faq-item > summary { cursor: pointer; font-weight: 600; }
.invite-faq-item > p { margin: var(--sp-2) 0 0; color: var(--c-text-dim); }
@media (max-width: 720px) {
  .invite-table td:last-child { width: 100%; white-space: normal; }
  .invite-table td:last-child::before { display: none; }
  .invite-send, .invite-actions { width: 100%; }
  .invite-share-buttons > .btn { flex: 1 1 calc(50% - var(--sp-2)); justify-content: center; }
  .invite-send .input { width: auto; flex: 1 1 auto; }
}

/* ---- values: units, price field ---- */
/* A value is its NUMBER in the figure face and its UNIT in the reading face, joined by a no-break
   space (`<span class="mono">10</span>&nbsp;<span class="unit">s</span>`): a unit set in the
   monospaced face opened a digit-wide gap between "1" and "s". */
.unit { font-family: var(--font-sans); font-size: inherit; font-weight: 400; letter-spacing: 0; color: var(--c-text-dim); }
/* The price limit: "$ 0.05 /s", the symbol before the digits and the per-second mark right after them. */
.cap-control .number-value { gap: 2px; }
.cap-control .cap-prefix { font: 600 26px/1.25 var(--font-mono); color: var(--c-text-dim); }
.cap-control .cap-unit { margin-left: 2px; font-size: var(--fs-sm); }
.cap-control input[data-cap-field] { width: 4.75ch; min-width: 3.75ch; }
.booking-bar .cap-control .cap-prefix { font-size: 20px; }
.booking-bar .price-limit-field .number-hint { display: block; margin: 4px 0 0; font-size: var(--fs-xs); line-height: 1.45; }
.cap-warning { margin: 4px 0 0; font-size: var(--fs-xs); line-height: 1.45; color: var(--c-accent-ink); }
.cap-warning[hidden] { display: none; }
/* Steppers a thumb can hit: on a touch screen the two buttons sit side by side, 44 × 44 each. */
@media (pointer: coarse) {
  .number-steps { grid-template-rows: none; grid-template-columns: 44px 44px; flex-basis: 88px; }
  .number-step { width: 44px; min-height: 44px; }
  .number-step + .number-step { border-top: 0; }
  .number-step[data-number-step="-1"] { order: -1; }
  .number-step[data-number-step="1"] { border-left: 1px solid var(--c-line); }
}

/* ---- A FILM: THE FLOW VIEW, THE NEXT SHOT AND THE PROJECT'S FILM (2026-09-27) ----------------------------------
   `userbus-specs/projects.md` section 5. The Flow view is the composer's own form in another arrangement: its
   wrappers are `display: contents` so the same controls take places on one grid - references above, the start
   frame and the end frame on either side of the shot, the planned output below. Connectors are rules drawn by the
   sheet, never elements a keyboard reaches. */
.plate { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: var(--r-sm); background: var(--c-surface-3); color: var(--c-text-dim); font: 600 10px var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; line-height: 1; vertical-align: middle; }
.plate-accent { background: var(--c-accent-quiet); color: var(--c-accent-ink); }
.view-tabs, .project-tabs { align-items: flex-end; }
/* A VIEW TAB THAT SUBMITS THE FORM (`POST /create/view`) looks exactly like the link tabs beside it. */
.view-tabs button { appearance: none; background: none; border: 0; border-bottom: 3px solid transparent; margin: 0 0 -1px; padding: var(--sp-2) 0; color: var(--c-text-soft); font: inherit; font-size: var(--fs-sm); font-weight: 700; cursor: pointer; }
.view-tabs button:hover { color: var(--c-text); }
.view-tabs button[aria-current="page"] { color: var(--c-text); border-bottom-color: var(--c-accent); }
.view-tabs-note { margin-left: auto; padding-bottom: var(--sp-2); }

.flow-canvas { grid-template-columns: minmax(140px, 1fr) minmax(0, 3fr) minmax(140px, 1fr); grid-template-areas: "r1 r2 r3" "start shot end" ". out ."; gap: 24px; padding: 24px; background: var(--c-bg-raised); }
.flow-canvas .input-tiles { display: contents; }
.flow-canvas [data-input-tile="reference_images"] { grid-area: r1; }
.flow-canvas [data-input-tile="reference_videos"] { grid-area: r2; }
.flow-canvas [data-input-tile="reference_audio"] { grid-area: r3; }
.flow-canvas [data-input-tile="start_frame"] { grid-area: start; }
.flow-canvas [data-input-tile="end_frame"] { grid-area: end; }
.flow-canvas [data-input-tile="start_frame"], .flow-canvas [data-input-tile="end_frame"] { align-self: center; min-height: 168px; border-color: var(--c-accent-line); background: var(--c-bg); }
.flow-canvas [data-input-tile="start_frame"].is-soon, .flow-canvas [data-input-tile="end_frame"].is-soon { border-color: var(--c-line); background: transparent; }
.flow-canvas [data-input-tile="start_frame"]::after, .flow-canvas [data-input-tile="end_frame"]::after { content: ""; position: absolute; top: 50%; width: 24px; border-top: 2px dashed var(--c-line-strong); }
.flow-canvas [data-input-tile="start_frame"]::after { right: -25px; }
.flow-canvas [data-input-tile="end_frame"]::after { left: -25px; }
.flow-canvas [data-input-tile="start_frame"].is-full::after, .flow-canvas [data-input-tile="end_frame"].is-full::after { border-top-style: solid; border-top-color: var(--c-accent-ink); }
.flow-canvas > .input-note { grid-column: 1 / -1; grid-row: 4; margin: 0; }
.flow-canvas > .clone-dropped { grid-column: 1 / -1; }
.flow-frame-thumb { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-md); background: var(--c-media); display: block; }
.flow-shot { grid-area: shot; position: relative; display: grid; gap: 12px; min-width: 0; padding: 14px; border: 1px solid var(--c-line-strong); border-radius: var(--r-lg); background: var(--c-surface); }
.flow-shot::after { content: ""; position: absolute; left: 50%; bottom: -25px; height: 24px; border-left: 2px solid var(--c-line-strong); }
.flow-shot-head { display: flex; align-items: center; gap: var(--sp-3); }
.flow-timeline { display: flex; align-items: center; gap: var(--sp-2); flex: 1; font-size: var(--fs-xs); color: var(--c-text-dim); }
.flow-rail { flex: 1; border-top: 2px solid var(--c-line-strong); }
.flow-output { grid-area: out; display: grid; gap: var(--sp-1); padding: var(--sp-3) var(--sp-4); border: 1px dashed var(--c-line-strong); border-radius: var(--r-lg); }
.flow-output p { margin: 0; }
.idea-card { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 1px dashed var(--c-line); border-radius: var(--r-md); color: var(--c-text-dim); }
.idea-card[hidden] { display: none; }
.idea-text { margin: 0; font-size: var(--fs-sm); color: var(--c-text-dim); }
.idea-actions { display: flex; gap: var(--sp-1); }

@media (max-width: 760px) {
  .flow-canvas { grid-template-columns: minmax(0, 1fr); grid-template-areas: "r1" "r2" "r3" "start" "shot" "end" "out"; gap: 16px; padding: 14px; }
  .flow-canvas [data-input-tile="start_frame"], .flow-canvas [data-input-tile="end_frame"] { min-height: 96px; }
  .flow-canvas [data-input-tile="start_frame"]::after, .flow-canvas [data-input-tile="end_frame"]::after, .flow-shot::after { display: none; }
  .flow-canvas > .input-note { grid-row: auto; }
  .view-tabs-note { margin-left: 0; flex-basis: 100%; }
}

/* THE NEXT SHOT: the frame it starts from, large, beside what it continues. */
.continue-panel { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: var(--sp-5); margin-bottom: var(--sp-4); padding: var(--sp-4); border: 1px solid var(--c-accent-line); border-radius: var(--r-lg); background: var(--c-bg-raised); }
.continue-panel--wait { grid-template-columns: minmax(0, 1fr); border-color: var(--c-line-strong); }
.continue-panel h2 { margin: 0 0 var(--sp-2); font-size: var(--fs-lg); }
.continue-panel p { margin: 0 0 var(--sp-2); }
.continue-still { margin: 0; display: grid; gap: var(--sp-2); }
.continue-still img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; border-radius: var(--r-md); background: var(--c-media); display: block; }
.continue-still figcaption { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--c-text-dim); }
.continue-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.join-player { width: 100%; aspect-ratio: 16 / 9; background: var(--c-media); border-radius: var(--r-md); display: block; margin-top: var(--sp-2); }
.join-player[hidden] { display: none; }
.previous-prompt { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--c-text-dim); }
.previous-prompt summary { cursor: pointer; }
.previous-prompt p { margin: var(--sp-2) 0; white-space: pre-wrap; }
.matches-note { margin: 0; }
@media (max-width: 760px) {
  .continue-panel { grid-template-columns: minmax(0, 1fr); }
}

/* A DELIVERED VIDEO'S NEXT STEP, under the player, beside nothing yellow. */
.continue-action { display: grid; gap: var(--sp-1); margin-top: var(--sp-2); }
.continue-action .field-hint { margin: 0; }
.continue-button span { font-family: var(--font-mono); font-weight: 700; }
.job-film { display: grid; gap: var(--sp-2); }
.film-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin: 0; }
.film-subtitle { margin: var(--sp-2) 0; font-size: var(--fs-sm); color: var(--c-text-dim); }
.take-strip { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: 0; padding: 0; list-style: none; }
.take-link { display: grid; gap: var(--sp-1); width: 160px; color: var(--c-text-soft); font-size: var(--fs-sm); }
.take-link:hover { text-decoration: none; color: var(--c-text); }
.take-thumb { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-md); background: var(--c-media); display: block; }
.take-thumb--empty { border: 1px dashed var(--c-line); background: transparent; }

/* THE PROJECT'S FILM: one line of numbered stops - the brand's route - under a player that plays it in order. */
.film-spend { display: block; margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--c-text-dim); }
.film-stage { margin: 0 0 var(--sp-5); }
.film-transport { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); }
.film-transport .field-hint { flex-basis: 100%; margin: 0; }
.film-segments { display: flex; flex: 1; gap: 2px; min-width: 200px; }
.film-segment { flex: 1; min-height: 32px; border: 0; border-top: 4px solid var(--c-line-strong); background: transparent; color: var(--c-text-dim); font: 600 11px var(--font-mono); cursor: pointer; }
.film-segment:hover, .film-segment[aria-current="true"] { border-top-color: var(--c-accent); color: var(--c-text); }
.film-route { display: flex; gap: 0; margin: 0 0 var(--sp-5); padding: var(--sp-2) 0 var(--sp-4); list-style: none; overflow-x: auto; scroll-snap-type: x proximity; }
.film-stop { position: relative; flex: 0 0 260px; display: grid; grid-template-rows: auto 1fr; padding-right: var(--sp-5); scroll-snap-align: start; }
.film-stop::before { content: ""; position: absolute; top: 22px; left: 0; right: 0; border-top: 6px solid var(--c-line-strong); }
.film-stop:last-child::before { right: 50%; }
.film-join { position: relative; min-height: 44px; margin: 0; padding: 36px 0 var(--sp-2); font-size: var(--fs-xs); color: var(--c-text-dim); }
.film-join--joined { color: var(--c-accent-ink); }
.film-join--mismatch { color: var(--c-failed); }
.film-stop:first-child .film-join, .film-stop:first-child { padding-top: 0; }
.film-stop:first-child .film-card { margin-top: 44px; }
.film-card { position: relative; display: grid; gap: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--c-line-strong); border-radius: var(--r-lg); background: var(--c-surface); }
.film-number { position: absolute; top: -34px; left: var(--sp-3); display: grid; place-items: center; width: 30px; height: 30px; border: 4px solid var(--c-text); border-radius: 50%; background: var(--c-bg); color: var(--c-text); font-size: 11px; font-weight: 700; }
.film-stop[data-state="succeeded"] .film-number { border-color: var(--c-accent); }
.film-stop[data-state="running"] .film-number, .film-stop[data-state="queued"] .film-number, .film-stop[data-state="leased"] .film-number { border-color: var(--c-running); }
.film-media { display: block; }
.film-media:hover { text-decoration: none; }
.film-thumb { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-md); background: var(--c-media); display: grid; place-items: center; color: var(--c-text-dim); font-size: var(--fs-xs); }
.film-thumb--empty { border: 1px dashed var(--c-line); background: transparent; }
.film-body p { margin: 0; }
.film-title { font-weight: 700; font-size: var(--fs-sm); line-height: var(--lh-tight); }
.film-title a { color: var(--c-text); }
.film-actions { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }
.film-op { display: inline; margin: 0; }
.film-takes-menu { font-size: var(--fs-xs); color: var(--c-text-dim); margin-top: var(--sp-1); }
.film-takes-menu summary { cursor: pointer; }
.film-takes-menu ul { margin: var(--sp-2) 0 0; padding: 0; list-style: none; display: grid; gap: var(--sp-1); }
.film-next { align-content: start; padding-top: 44px; }
.film-next::before { border-top-style: dashed; right: 50%; }
.film-next-link { display: grid; place-items: center; min-height: 120px; border: 1px dashed var(--c-accent-line); border-radius: var(--r-lg); color: var(--c-accent-ink); font-weight: 700; }
.film-next-link:hover { text-decoration: none; background: var(--c-surface-2); border-color: var(--c-accent); }
.film-next--wait p { padding-top: var(--sp-3); }
.film-empty { margin: 0 0 var(--sp-3); }
.film-shelf { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--sp-4); margin: var(--sp-3) 0 0; padding: 0; list-style: none; }
.film-other { display: grid; gap: var(--sp-2); align-content: start; }
.film-other p { margin: 0; }
@media (max-width: 760px) {
  /* ON A PHONE THE LINE RUNS DOWN THE PAGE: numbered stops, one under the other. */
  .film-route { flex-direction: column; overflow-x: visible; }
  .film-stop { flex: 1 1 auto; padding: 0 0 0 44px; }
  .film-stop::before { top: 0; bottom: 0; left: 15px; right: auto; border-top: 0; border-left: 6px solid var(--c-line-strong); }
  .film-stop:first-child .film-card { margin-top: 0; }
  .film-number { top: var(--sp-3); left: -44px; }
  .film-join { padding: var(--sp-2) 0; min-height: 0; }
  .film-next { padding-top: var(--sp-3); }
}
