/*
 * Volare app shell.
 *
 * Only the shell and the surfaces his prototype did not have live here:
 * sidebar/topbar chrome, popovers, the navigation sheet, toasts, dialogs,
 * tooltips, the create flow, and the video workspace. Every component a page
 * uses comes from styles.css or css/components.css — this file never redefines
 * a card, a pill, a field, a button, or a page head.
 *
 * Three rules this file obeys with the rest of the app:
 *   - no font-size that is not a --text-* token, and no media query that
 *     changes one;
 *   - no translucent component surface (scrims excepted: an opaque scrim
 *     cannot do its job);
 *   - no page scales itself. Layout reflows; the page scrolls when it must.
 */

body.app .shell { height: auto; overflow: visible; }
body.app .main { display: block; padding: var(--s4) var(--page-gutter) var(--s6); }
body.app.is-locked { overflow: hidden; }

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: var(--s4); top: -3rem; z-index: 40;
  background: var(--tile); border: 1px solid var(--line-2); border-radius: var(--r-sm);
  padding: var(--s2) var(--s3); font-weight: var(--w-medium); transition: top .15s;
}
.skip-link:focus { top: var(--s3); }
:focus-visible { outline: 2px solid var(--dk-tx-accent, var(--accent)); outline-offset: 2px; }

.outlet { display: grid; gap: var(--gap-card); align-content: start; padding-bottom: var(--s6); }
.outlet:focus { outline: none; }
.muted { color: var(--muted); }

/* ---------- Sidebar ---------- */
.side-create { position: relative; z-index: 1; margin-bottom: var(--s4); }
/* Collapse: the same icon rail the sidebar becomes below 1020px, chosen. */
.sidebar-inner { display: flex; flex-direction: column; }
.side-toggle { position: relative; z-index: 1; margin-top: auto; align-self: flex-start; color: var(--muted); }
.side-toggle:hover { color: var(--ink-strong); }
body.app .shell { transition: grid-template-columns var(--motion) ease; }
.tip.tip--right { transform: translateY(-50%); }
@media (min-width: 1020px) {
  :root[data-sidebar="collapsed"] body.app .shell { grid-template-columns: 4.5rem minmax(0, 1fr); }
  :root[data-sidebar="collapsed"] .sidebar .side-label { display: none; }
  :root[data-sidebar="collapsed"] .sidebar .logo { justify-content: center; padding-left: 0; }
  :root[data-sidebar="collapsed"] .sidebar .nav-item,
  :root[data-sidebar="collapsed"] .sidebar .btn--create { justify-content: center; padding: 0; }
  :root[data-sidebar="collapsed"] .side-toggle { align-self: center; }
}
@media (max-width: 1019px) { .side-toggle { display: none; } }
.sidebar .btn--create { width: 100%; margin-top: 0; }
.nav-item.is-active { background: var(--dk-b-efede7, #EFEDE7); font-weight: var(--w-medium); box-shadow: inset 0 0 0 1px var(--line-2); }

/* ---------- Topbar ---------- */
/* Above the hero artwork so search and popovers stay opaque. */
body.app .topbar { position: relative; z-index: 30; justify-content: flex-end; gap: var(--s5); margin-bottom: var(--s4); }
.topbar-menu { display: none; margin-right: auto; }
.gsearch { position: relative; }
.gsearch .search { width: 20rem; }
.gsearch-panel {
  position: absolute; top: calc(100% + var(--s2)); right: 0; width: 26rem; max-width: 90vw;
  background: var(--tile); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: 0 1px 2px rgba(31,31,33,.06), 0 1rem 2.5rem -.75rem rgba(31,31,33,.24);
  padding: var(--s2); z-index: 20; max-height: 22rem; overflow: auto;
}
.gs-head { padding: var(--s2) var(--s2) var(--s1); font: var(--w-medium) var(--text-2xs)/1.2 var(--sans); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--muted); }
.gs-empty { padding: var(--s2); font-size: var(--text-sm); color: var(--muted); }
.gsearch-panel .estate--card, .popover .estate--card { padding: var(--s5) var(--s4) var(--s6); }
.gs-row { display: flex; align-items: center; gap: var(--s3); min-height: var(--control); padding: var(--s2); border-radius: var(--r-xs); }
.gs-row:hover, .gs-row:focus-visible { background: var(--accent-soft); outline: none; }
.gs-title { font-size: var(--text-md); color: var(--ink-strong); }
.gs-meta { margin-left: auto; font-size: var(--text-xs); font-variant-numeric: var(--nums-tabular); }

.pop { position: relative; }
#bellBtn { position: relative; }
.bell-dot { position: absolute; top: .15rem; right: .15rem; min-width: 1.125rem; height: 1.125rem; padding: 0 .25rem; border-radius: .5625rem; background: var(--st-attn); border: 2px solid var(--bg); color: #fff; font: var(--w-semibold) var(--text-xs)/1 var(--sans); display: grid; place-items: center; font-variant-numeric: var(--nums-tabular); }
/* `display: grid` above would otherwise beat the UA's [hidden] rule. */
.bell-dot[hidden] { display: none; }

.popover {
  position: absolute; top: calc(100% + var(--s2)); right: 0; z-index: 25;
  background: var(--tile); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: 0 1px 2px rgba(31,31,33,.06), 0 1rem 2.5rem -.75rem rgba(31,31,33,.24);
  padding: var(--s2);
}
.popover--bell { width: 23rem; max-width: 92vw; }
.popover--menu { width: 14rem; }
.popover--anchored { position: absolute; width: 12.5rem; }
.pop-head { display: flex; align-items: center; justify-content: space-between; padding: var(--s2); }
.pop-row { display: grid; grid-template-columns: 1fr auto; gap: .125rem var(--s2); padding: var(--s2); border-radius: var(--r-xs); }
.pop-row:hover { background: var(--accent-soft); }
.pop-type { font: var(--w-medium) var(--text-2xs)/1.2 var(--sans); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--dk-tx-accent, var(--accent)); }
.pop-when { grid-column: 2; grid-row: 1; font-size: var(--text-xs); color: var(--muted); font-variant-numeric: var(--nums-tabular); }
.pop-title { grid-column: 1 / -1; font-size: var(--text-md); color: var(--ink-strong); }
.pop-text { grid-column: 1 / -1; font-size: var(--text-sm); color: var(--muted); }
.pop-act { grid-column: 1 / -1; font-size: var(--text-sm); }
.pop-empty:not(.estate) { padding: var(--s4) var(--s2); font-size: var(--text-sm); color: var(--muted); text-align: center; }
/* A long list scrolls inside the panel; long titles wrap; a keyboard user sees which row is focused;
   unread rows carry a small dot so read and unread differ by more than tint. */
.popover--bell { max-height: min(34rem, calc(100dvh - 6rem)); overflow: auto; overscroll-behavior: contain; }
.pop-title, .pop-text { overflow-wrap: anywhere; }
.pop-row:focus-visible { background: var(--accent-soft); outline: 2px solid var(--dk-tx-accent, var(--accent)); outline-offset: -2px; }
.pop-row:not(.is-read) .pop-type { display: inline-flex; align-items: center; gap: .375rem; }
.pop-row:not(.is-read) .pop-type::before { content: ''; width: .4375rem; height: .4375rem; border-radius: 50%; background: currentColor; }
/* Search and the bell waiting on results: skeleton rows hold the panel's height. */
.gs-loading { padding: 0 var(--s2); }
.menu-row { display: flex; align-items: center; gap: var(--s2); width: 100%; height: var(--control); padding: 0 var(--s2); border-radius: var(--r-xs); font-size: var(--text-md); color: var(--ink); text-align: left; }
.menu-row:hover, .menu-row:focus-visible { background: var(--accent-soft); outline: none; }
.menu-row--danger { color: var(--dk-t-8c3a3a, #8C3A3A); }
.menu-rule, .sheet-rule { border: 0; border-top: 1px solid var(--line); margin: var(--s2) 0; }
/* Phone: menu, search, bell and avatar share one row; search takes whatever
   the three fixed controls leave, and the row keeps clear of the page title.
   Popovers anchor to the topbar's full width rather than their button, so
   the search and notifications panels never run off the left edge. */
@media (max-width: 680px) {
  body.app .topbar { gap: var(--s2); margin-bottom: var(--s5); }
  body.app .topbar-menu { margin-right: 0; flex: none; }
  body.app .topbar .pop { position: static; flex: none; }
  body.app .gsearch { position: static; min-width: 0; }
  body.app .gsearch-panel,
  body.app .popover--bell { left: 0; right: 0; width: auto; max-width: none; }
}

/* ---------- Page head in app context ---------- */
/* page heads line up with Home's hero (styles.css .hero) */

/* One page-title role: every route's title is the same size and lands on the
   same baseline as Home's greeting. */
body.app .page-head h1,
body.app .page-head .page-title,
body.app .hero--brand h1 {
  font: var(--type-title);
  letter-spacing: var(--track-display, -0.02em);
  color: var(--ink-strong);
}

/* One head block on every route: title + subtitle on the left, the page action
   on the same row, so content below the header starts at the same y as Home's. */
body.app .page-head,
body.app .hero--brand {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  column-gap: var(--s4);
}
body.app .page-head h1,
body.app .hero--brand h1 { grid-column: 1; }
body.app .page-head .page-sub,
body.app .hero--brand .hero-sub { grid-column: 1; }
body.app .page-head > .btn,
body.app .page-head > .head-action,
body.app .hero--brand .hero-actions {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: end;
  margin: 0;
}
/* Home's hero sets the baseline (title top = 68px at 1440); other heads carry
   an extra row gap above them, so pull them back onto the same line. */
body.app .page-head { margin-top: -0.75rem; padding-bottom: calc(var(--rhythm-head) - var(--gap-card)); }
/* Titles wrap, never cut; a very long word breaks rather than pushing the page wide. */
body.app .page-head h1, body.app .page-head .page-title { overflow-wrap: anywhere; }
/* On a phone the action drops below the title and subtitle instead of squeezing them. */
@media (max-width: 680px) {
  body.app .page-head { grid-template-columns: minmax(0, 1fr); }
  body.app .page-head > .btn,
  body.app .page-head > .head-action { grid-column: 1; grid-row: auto; justify-self: start; margin-top: var(--s4); }
}
.page-head--ws { display: grid; gap: var(--s2); }
.ws-title-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3); }
.ws-title-row h1 { font: var(--type-title); letter-spacing: var(--track-heading); color: var(--ink-strong); border-radius: var(--r-xs); padding: 0 var(--s1); margin-left: calc(-1 * var(--s1)); }
.ws-title-row h1:focus { outline: 2px solid var(--dk-tx-accent, var(--accent)); outline-offset: 2px; }
.ws-title-row .more-btn { margin-left: auto; }
/* Below desktop the title gets the whole row and the status drops beneath it,
   so a long title is not cut short beside the pill and menu. */
@media (max-width: 1100px) { .ws-title-row > .ws-h1 { flex-basis: 100%; } }
.link--back { gap: var(--s1); }
.btn--headaction { margin-top: var(--s4); }

/* ---------- Home additions ----------
   Home keeps his original grid (.row--2 / .row--3 / .assistant from
   styles.css). These rules only cover state his static page did not have. */
.project { cursor: pointer; transition: background var(--motion); }
.project:hover { background: var(--hover-card); }
a.stat { text-decoration: none; }
a.stat:hover strong { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .2em; }
/* Cards size to their content; nothing stretches to fill a fixed row. */
.row--3 > .card > .card-body { flex: 0 0 auto; }
.perf .stat { min-height: 0; }
.perf .spark { margin-top: 0; }
.thumb--placeholder, .player-stage--empty {
  display: grid; place-items: center; color: var(--dk-t-7e8a99, #7E8A99);
  background: linear-gradient(180deg, var(--dk-b-f2f4f7, #F2F4F7), var(--dk-b-e7ebf0, #E7EBF0));
}
/* An empty video has no frame to show: a dashed, obviously-empty box says so
   rather than a finished-looking landscape. */
.thumb--empty {
  display: grid; place-items: center; gap: var(--s1);
  background: var(--fill-faint); border: 1px dashed var(--dashed); color: var(--muted);
}
.thumb--processing { border-style: solid; }
.thumb--empty .thumb-empty-label { font: var(--type-meta); color: var(--muted); }
.thumb--lg { display: grid; place-items: center; }
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb--placeholder > .i, .player-stage--empty > .i, .vthumb--placeholder .i, .thumb--empty > .i { width: 1.75rem; height: 1.75rem; }
.attn-list { display: grid; gap: var(--gap-row); }
.current-extra .stepper { margin: 0; }

/* ---------- Empty states ----------
   Every empty state is the shared block in css/states.css (js/states.js). The
   class names below are the old ones; they stay for any markup that still
   writes them by hand, at the same sizes as the shared block. */
.empty-wrap:not(.estate) { display: grid; justify-items: center; text-align: center; gap: var(--s2); padding: var(--s9) var(--s4) var(--s10); }
.empty-title:not(.estate-title) { font: var(--type-section); letter-spacing: var(--track-title); color: var(--ink-strong); }
.empty-body:not(.estate-body) { max-width: min(52ch, 100%); font: var(--type-body); color: var(--muted); }
.empty-actions:not(.estate-actions) { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--s3); margin-top: var(--s2); }
.empty-note { font: var(--type-meta); color: var(--muted); }
.vgrid > .empty-wrap { grid-column: 1 / -1; }
/* A card whose only content is a page-sized empty state gives up its own
   surface: the state sits on the page, never in a box (and never in a box in a box). */
.card:has(> .estate--page), .card:has(> .empty-art) {
  background: none; border-color: transparent; box-shadow: none; padding: 0;
}
html[data-look] .card:has(> .estate--page), html[data-look] .card:has(> .empty-art) { background: none; box-shadow: none; padding: 0; }
/* A group inside a card (Brand's tiles) is set off by space and one hairline above it,
   not by a frame of its own. */
html[data-look] .card .tile { background: none; border: 0; border-top: 1px solid var(--line-2); border-radius: 0; box-shadow: none; }

/* ---------- Videos toolbar additions ---------- */
.sort-inline { margin-left: var(--s2); }
.sort-inline .field { gap: 0; }
.sort-inline .field-label { display: none; }
.search--block { width: 100%; margin-left: 0; }
/* With nothing made yet the toolbar and the head's button step aside (js/views.js mountVideos). */
body[data-route="videos"] .filters[hidden], body[data-route="videos"] .page-head > .btn[hidden] { display: none; }
/* The scene art is drawn at 400 x 126: the frame takes that shape so no empty
   band sits above it, and every thumbnail (poster, art, none) matches. */
.vgrid .vthumb { aspect-ratio: 400 / 126; }
.vgrid .vthumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Status on one line, its detail on the next, on every card: feet line up
   across a row whatever the detail's length. */
.vgrid .vstat { flex-direction: column; align-items: flex-start; flex-wrap: nowrap; }
.vgrid .vstat .when, .vgrid .vstat .proc { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vgrid .vfoot { align-items: flex-end; }
.vgrid .vnote { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* ---------- Create flow ---------- */
/* 24px above and below: the stepper is its own row, never touching the card. */
.fsteps { display: flex; align-items: center; list-style: none; margin: var(--s2) 0 var(--s6); padding: 0 0 0 var(--s1); max-width: 30rem; }
.fstep {
  display: flex; align-items: center; gap: var(--s2); flex: none;
  font: var(--type-meta); color: var(--muted);
}
/* The rule between steps is what makes this read as progress, not tabs. */
.fstep + .fstep { flex: 1 1 auto; }
.fstep + .fstep::before { content: ''; flex: 1 1 auto; min-width: var(--s4); height: 1px; margin: 0 var(--s1); background: var(--line-2); }
.fstep.is-done + .fstep::before { background: var(--positive); }
.fstep-n { flex: none; display: grid; place-items: center; width: 1.5rem; height: 1.5rem; border-radius: 50%; border: 1px solid var(--line-2); background: var(--tile); font: var(--type-meta); font-weight: var(--fw-strong); line-height: 1; color: var(--muted); font-variant-numeric: var(--nums-tabular); }
.fstep.is-on { color: var(--ink-strong); font-weight: var(--fw-strong); }
.fstep.is-on .fstep-n { background: var(--ink-900); border-color: var(--ink-900); color: var(--pearl); }
.fstep.is-done { color: var(--ink); }
.fstep.is-done .fstep-n { background: var(--positive); border-color: var(--dk-tx-positive, var(--positive)); color: var(--pearl); }

.set-card .form { display: grid; gap: var(--s4); margin-top: var(--s4); }
.form--tight { gap: var(--s3); margin-top: var(--s3); }
.form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.fields--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.input--file { padding: var(--s2) var(--s3); height: auto; }
.specs { margin-top: var(--s5); }
.ack { margin-top: var(--s3); max-width: var(--measure); }

.drop {
  margin-top: var(--s2); display: flex; align-items: center; gap: var(--s4);
  padding: var(--s4) var(--s5); border: 1px dashed var(--dashed); border-radius: var(--r);
  background: var(--fill-faint); cursor: pointer; text-align: left;
  transition: background var(--motion), border-color var(--motion), box-shadow var(--motion);
}
.drop:hover { border-color: var(--dashed-hover); background: var(--fill-faint-hover); }
.drop:focus-visible { outline: 2px solid var(--ink-strong); outline-offset: 3px; }
/* A file held over the zone: unmistakable in both looks. The frame turns solid ink with a ring around it,
   the label turns to ink, and the button steps aside, so the only thing left to do is let go. */
html[data-look] body .drop.is-over { border: 1px solid var(--ink-900); background: var(--hover-bg);
  box-shadow: 0 0 0 3px var(--card), 0 0 0 5px var(--ink-900); }
html[data-look] .drop.is-over .drop-text { background: var(--ink-900); color: var(--pearl); box-shadow: none; }
html[data-look] .drop.is-over .new-title, html[data-look] .drop.is-over .new-sub { color: var(--pearl); }
html[data-look] .drop.is-over .new-plus { background: var(--ink-900); color: var(--pearl); }
html[data-look] .drop.is-over .btn { visibility: hidden; }
.drop .drop-text { transition: background var(--motion), color var(--motion); }
/* Busy is a colour change, never a blanket opacity. */
.drop.is-busy { cursor: default; pointer-events: none; background: var(--soft); border-color: var(--line-2); color: var(--faint); }
.drop[hidden] { display: none; }
.drop .new-plus { margin: 0; flex: none; }
.drop-text { display: grid; gap: var(--s1); flex: 1 1 auto; min-width: 0; }
.drop .btn { flex: none; margin-left: auto; }
@media (max-width: 680px) {
  .drop { flex-wrap: wrap; padding: var(--s4); }
  .drop-text { flex-basis: calc(100% - 2.125rem - var(--s4)); }
  .drop .btn { margin-left: 0; width: 100%; justify-content: center; }
}
/* A refused file: said once above the zone, in a hairline row, with the way forward beside it. */
.up-refusal { margin: 0 0 var(--s3); padding: 0 0 var(--s3); border-bottom: 1px solid var(--line); }

/* The upload under way: the working field where the drop zone was, then a quiet way to stop. */
.uploading { display: grid; justify-items: center; gap: var(--s2); margin-top: var(--s2); padding-bottom: var(--s4); border-bottom: 1px solid var(--line); }
.uploading .wstate { padding-bottom: 0; }
.uploading .wstate-title { overflow-wrap: anywhere; }
.uploading-foot { display: grid; justify-items: center; gap: var(--s2); }
#uploadProgress[hidden] { display: none; }
/* Setup: fields keep a readable width, and two fields side by side stay level when one shows an error. */
#setupForm { max-width: 56rem; }
#setupForm .fields--2 { align-items: start; }
/* Supporting files: one list, rows split by a hairline; only a file that is too large is marked. */
.asset-list { list-style: none; margin: 0; padding: 0; display: grid; }
.asset-list:empty { display: none; }
.asset-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); padding: var(--s2) 0; border-top: 1px solid var(--line); }
.asset-row:first-child { border-top: 0; }
.asset-row.is-bad .asset-name { color: var(--dk-tx-st-fail, var(--st-fail)); }
.asset-name { min-width: 0; overflow-wrap: anywhere; font: var(--type-body); }
.asset-row .btn { flex: none; }

/* ---------- Workspace ---------- */
.ws-grid { display: grid; grid-template-columns: minmax(0, 25rem) minmax(0, 1fr); gap: var(--gap-card); align-items: start; }
.ws-grid--review { grid-template-columns: minmax(0, 27rem) minmax(0, 1fr); }
.ws-side, .ws-main { display: grid; gap: var(--gap-card); align-content: start; }
.player { padding: var(--s3); }
.player-stage { position: relative; aspect-ratio: 16/9; border-radius: var(--r-sm); overflow: hidden; }
.player-stage img { width: 100%; height: 100%; object-fit: cover; }
.player-note { position: absolute; left: var(--s4); right: var(--s4); top: 58%; text-align: center; font: var(--type-meta); color: var(--muted); }
.stepper--4 { grid-template-columns: repeat(4, 1fr); }
.stepper--5 { grid-template-columns: repeat(5, 1fr); }
.stepper--6 { grid-template-columns: repeat(6, 1fr); }
.summary-line { font: var(--type-body); color: var(--ink); max-width: var(--measure); }
.export-facts { margin-top: var(--s4); }
.status-line--unknown { color: var(--ink-strong); font-weight: var(--w-medium); }
/* Player-first layouts (review, export ready): the video is the wide, first
   column; everything else is a narrower rail beside it, and under it on phones. */
.ws-grid.ws-grid--player { grid-template-columns: minmax(0, 1fr) minmax(0, 24rem); }
/* Processing: the step it is on, in dots (js/processing-art.js). The canvas fills the 16:9 stage, so nothing moves
   when it arrives; the note sits in the band the art leaves clear. Classic colours here, Volare's in looks.css. */
.player-stage--art { --pa-dot: 94, 107, 125; --pa-hi: 38, 48, 66; }
.player-stage--art > .pa-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.player-stage--art > .player-note { top: auto; bottom: var(--s4); margin: 0; }
.player-stage--still > svg { display: block; width: 100%; height: 100%; }
.player-stage video { display: block; width: 100%; height: 100%; background: #000; }
.player-play { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: grid; place-items: center; width: 3.5rem; height: 3.5rem; border-radius: 50%; background: var(--tile); color: var(--ink-strong); box-shadow: 0 .5rem 1.5rem -.5rem rgba(31,31,33,.35); }
.ws-approve { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.ws-approve .field-note { margin: 0; }
.ws-export-actions { margin-top: 0; }
/* Failed: one focused column, nothing beside it. */
.ws-solo { max-width: 40rem; }
/* Workspace stepper: room between the stage labels and the sentence under
   them, and finished stages read as finished, not disabled. */
.ws-steps + .status-line { margin-top: var(--s5); }
.ws-steps .step.done { color: var(--ink); }
.ws-steps .step.done .dot { background: var(--st-done-dot); border-color: var(--st-done-dot); color: #fff; }
.ws-steps .step.done::before, .ws-steps .step.active::before { background: var(--st-done-dot); }
@media (max-width: 1280px) {
  .ws-grid.ws-grid--player { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); }
}
@media (max-width: 1019px) {
  .ws-grid.ws-grid--player { grid-template-columns: 1fr; }
}
@media (max-width: 680px) {
  .ws-approve .btn { width: 100%; justify-content: center; }
  .ws-steps .label { font: var(--type-meta); }
}

.details { margin-top: var(--s3); border-top: 1px solid var(--line); }
.details summary { min-height: var(--control); display: flex; align-items: center; padding: var(--s2) 0; font: var(--type-meta); font-weight: var(--fw-strong); color: var(--ink-strong); cursor: pointer; }
.details > :not(summary) { padding: 0 0 var(--s3); }

.glist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s1); }
.gitem { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: .125rem var(--s2); width: 100%; min-height: var(--control); padding: var(--s2) var(--s3); border-radius: var(--r-sm); border: 1px solid transparent; text-align: left; transition: background var(--motion), border-color var(--motion); }
.gitem:hover { background: var(--hover-card); }
.gitem.is-sel { background: var(--accent-soft); border-color: var(--ink-900); }
.gitem-label { font: var(--type-body-strong); color: var(--ink-strong); }
.gitem-at { font: var(--type-meta); color: var(--muted); font-variant-numeric: var(--nums-tabular); }
.gitem-says { grid-column: 1 / -1; font: var(--type-meta); color: var(--muted); }

.sel-actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s4); }
.compare { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); margin-top: var(--s4); }
.compare-pane { padding: var(--s3); }
.compare-pane--current { border-color: var(--ink-900); }
.compare-pane--proposed { border-style: dashed; }
.compare-frame { aspect-ratio: 16/9; margin: var(--s2) 0; border-radius: .375rem; background: var(--alabaster); display: grid; place-items: center; color: var(--dk-t-7e8a99, #7E8A99); }
.compare-frame--empty { font-size: var(--text-xs); color: var(--muted); background: repeating-linear-gradient(45deg, var(--dk-b-f4f5f7, #F4F5F7), var(--dk-b-f4f5f7, #F4F5F7) 6px, var(--dk-b-edeff2, #EDEFF2) 6px, var(--dk-b-edeff2, #EDEFF2) 12px); }

/* ---------- Settings additions ---------- */
.int-list, .pref-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
/* Hairline rows on the card's own surface (see .attn in styles.css). */
.int, .pref {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--row-h); padding: var(--rhythm-rows) 0;
}
.int + .int, .pref + .pref { border-top: 1px solid var(--line); }
.int-icon { display: grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: var(--r-sm); background: var(--accent-soft); color: var(--dk-tx-accent, var(--accent)); flex: none; }
.int-text, .pref-label span { display: grid; min-width: 0; }
.int-text strong, .pref-label strong { font: var(--w-medium) var(--text-md)/1.4 var(--sans); color: var(--ink-strong); }
.int-text small, .pref-label small { font-size: var(--text-sm); color: var(--muted); }
.int .pill { margin-left: auto; }
.pref-label { display: flex; align-items: center; gap: var(--s3); cursor: pointer; }
.pref-label input[type="checkbox"] { width: 1.05rem; height: 1.05rem; flex: none; margin: 0; accent-color: var(--ink-strong); cursor: pointer; }
.pref-ch { margin-left: auto; font-size: var(--text-xs); color: var(--muted); }
.delivery-note { margin-top: var(--s4); }
/* Third-party marks keep their own colours, so they sit on a plain tile. */
.int-icon--brand { background: var(--tile); border: 1px solid var(--line); }
.pref-field { display: grid; gap: var(--s2); align-content: start; min-width: 0; }
@media (max-width: 680px) {
  .int { flex-wrap: wrap; }
  .int-text { flex: 1 1 10rem; }
}

/* ---------- Toasts, dialog, tooltip, sheet ---------- */
.toasts { position: fixed; left: 50%; bottom: var(--s5); transform: translateX(-50%); display: grid; gap: var(--s2); z-index: 60; }
.toast { padding: var(--s2) var(--s4); border-radius: var(--r-sm); background: var(--ink-900); color: var(--dk-oninv, #fff); font-size: var(--text-sm); box-shadow: 0 .5rem 1.5rem -.5rem rgba(31,31,33,.4); transition: visibility .2s, transform .2s; }
/* A leaving toast slides out and is gone: it never renders half-transparent. */
.toast.is-out { visibility: hidden; transform: translateY(.5rem); }
/* Toasts never run wider than the screen; on a phone they sit clear of the home bar. */
.toasts { width: max-content; max-width: calc(100vw - 2 * var(--s4)); }
@media (max-width: 680px) { .toasts { bottom: calc(var(--s4) + env(safe-area-inset-bottom, 0px)); } }

/* Scrims are the one non-artwork translucency left in the app: an opaque
   scrim would hide the page it is dimming. */
.modal-scrim { position: fixed; inset: 0; background: var(--dk-s-1f1f21a34, rgba(31,31,33,.34)); z-index: 70; }
.modal {
  position: fixed; z-index: 71; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(30rem, 92vw); background: var(--tile); border-radius: var(--r); padding: var(--s6);
  box-shadow: 0 2rem 4rem -1rem rgba(31,31,33,.4); display: grid; gap: var(--s3);
}
.modal h2 { font: var(--type-section); letter-spacing: var(--track-title); color: var(--ink-strong); }
.modal-body { font: var(--w-regular) var(--text-md)/var(--lh-body) var(--sans); color: var(--ink); }
.modal-check { display: flex; align-items: center; gap: var(--s2); font-size: var(--text-sm); }
.modal-actions { display: flex; justify-content: flex-end; gap: var(--gap-inline); margin-top: var(--s2); }
/* A tall dialog scrolls inside itself; on a phone its buttons stack full width, the main one on top. */
.modal { max-height: calc(100dvh - 2 * var(--s4)); overflow: auto; }
@media (max-width: 480px) {
  .modal { padding: var(--s5); }
  .modal-actions { flex-direction: column-reverse; }
  .modal-actions .btn { width: 100%; justify-content: center; }
}

.tip { position: absolute; z-index: 80; transform: translateX(-50%); padding: var(--s1) var(--s2); border-radius: var(--r-xs); background: var(--ink-900); color: var(--dk-oninv, #fff); font-size: var(--text-xs); pointer-events: none; white-space: nowrap; }

.sheet { position: fixed; inset: 0; z-index: 65; }
.sheet-scrim { position: absolute; inset: 0; background: var(--dk-s-1f1f21a34, rgba(31,31,33,.34)); }
.sheet-panel { position: absolute; left: 0; top: 0; bottom: 0; width: min(18rem, 86vw); background: var(--side); padding: var(--s4); overflow: auto; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s4); }
.sheet-title { font: var(--w-regular) var(--text-2xl)/1.25 var(--serif); color: var(--ink-strong); }
.sheet-panel .side-label, .sheet-panel .nav-item span { display: inline; }
.sheet-panel .nav { display: grid; gap: var(--s1); margin-left: 0; }
.sheet-panel .nav-item { width: auto; justify-content: flex-start; padding: 0 var(--s3); gap: var(--s3); }
.sheet-panel .btn--create { justify-content: center; gap: var(--s2); padding: 0 var(--s4); }

/* ---------- Responsive (layout only) ---------- */
@media (max-width: 1280px) {
  .gsearch .search { width: 17rem; }
  .ws-grid, .ws-grid--review { grid-template-columns: minmax(0, 21rem) minmax(0, 1fr); }
}
@media (max-width: 1019px) {
  body.app .shell { grid-template-columns: 4.5rem minmax(0,1fr); }
  .sidebar .side-label { display: none; }
  .sidebar .logo { justify-content: center; padding-left: 0; }
  .sidebar .nav-item, .sidebar .btn--create { justify-content: center; padding: 0; }
  .ws-grid, .ws-grid--review { grid-template-columns: 1fr; }
  .vgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .filters { flex-wrap: wrap; }
  .compare { grid-template-columns: 1fr; }
}
@media (max-width: 680px) {
  body.app .shell { grid-template-columns: 1fr; }
  body.app .sidebar { display: none; }
  .topbar-menu { display: grid; margin-right: auto; }
  .gsearch { margin-right: 0; flex: 1; }
  .gsearch .search { width: 100%; }
  body.app .main { padding: var(--s3) var(--s4) var(--s6); }
  .vgrid { grid-template-columns: 1fr; }
  .fields--2, .fields { grid-template-columns: 1fr; }
  .search--videos { width: auto; flex: 1; margin-left: 0; }
  .sort-inline { margin-left: 0; width: 100%; }
  .int, .pref { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0ms !important; animation-duration: 0ms !important; }
}
:root[data-motion="reduce"] * { transition-duration: 0ms !important; animation-duration: 0ms !important; }

/* ---------- Home: per-status blocks ------------------------------------- *
 * Home has a designed state for every status in the vocabulary. These are the
 * pieces the generic card components did not already cover: a real byte-count
 * bar, a blocking question, the fixed delivery facts, and the quiet in-card
 * empty states. */

/* Home's subtitle can name a video, so it is clamped to one line; on a phone
   it wraps instead of cutting the sentence off. */
body[data-route="home"] .hero-sub { max-width: var(--measure-subtitle); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 1279px) { body[data-route="home"] .hero-sub { white-space: normal; } }
/* Home's sections are items of the outlet grid; without this a one-line
   subtitle or a wide card sets the column's minimum and pushes the page
   past the viewport. */
body[data-route="home"] .outlet > * { min-width: 0; }

/* A page-level condition (the processing service being unreachable) is stated
   at the top of the page, not buried in one card. */
.page-banner {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--control); padding: var(--s2) var(--s4);
  background: var(--st-attn-bg); border: 0; border-radius: var(--r-sm);
  color: var(--ink-strong);
}
.page-banner .i { flex: none; color: var(--dk-tx-st-attn, var(--st-attn)); }
.page-banner p { font: var(--type-body); min-width: 0; }
.page-banner .btn { margin-left: auto; flex: none; }
/* The greeting keeps its own air below the banner at every height tier. */
.page-banner + .hero { margin-top: var(--s4); }

/* One quiet explanatory line under a status. */
.cur-note { font: var(--type-meta); color: var(--muted); max-width: var(--measure); }
.cur-note--stale { color: var(--dk-tx-st-attn, var(--st-attn)); }

/* Fixed delivery facts: what comes out, and where it goes. */
.cur-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s1) var(--s4); margin: 0; }
.cur-facts dt { font: var(--type-meta); color: var(--muted); }
.cur-facts dd { margin: 0; font: var(--type-body); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: var(--nums-tabular); }

/* Upload: the one bar in the product, and only because the byte count is real. */
.uprog { display: grid; gap: var(--s2); }
.uprog-bar { position: relative; height: 0.375rem; border-radius: 999px; background: var(--line-2); overflow: hidden; }
.uprog-bar span { display: block; height: 100%; border-radius: 999px; background: var(--st-busy-dot); }
.uprog-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); }
.uprog-pct { font: var(--type-body-strong); color: var(--ink-strong); font-variant-numeric: var(--nums-tabular); }
.uprog-left, .uprog-read { font: var(--type-meta); color: var(--muted); font-variant-numeric: var(--nums-tabular); }
/* A file name keeps the size of the line it sits in, stays on one line, and truncates at the tail it can spare. */
.filename { font: inherit; color: var(--ink); font-variant-numeric: var(--nums-tabular); direction: ltr; unicode-bidi: plaintext; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; max-width: 18rem; vertical-align: bottom; }

/* The blocking question, said on Home rather than only in the workspace. */
.blocker { display: flex; align-items: flex-start; gap: var(--s2); padding: var(--s3); border-radius: var(--r-sm); background: var(--st-attn-bg); }
.blocker-icon { flex: none; color: var(--dk-tx-st-attn, var(--st-attn)); margin-top: 0.0625rem; }
.blocker p { font: var(--type-body); color: var(--ink-strong); }

/* Current video keeps a consistent rhythm whichever block a status brings. */
.current-extra { margin-top: var(--gap-head); display: grid; gap: var(--gap-stack); }
.current .note { padding: var(--s3) var(--s4); }
.current .actions { display: flex; align-items: center; gap: var(--gap-inline); margin-top: auto; padding-top: var(--gap-head); flex-wrap: wrap; }

/* Nothing to show is a state, not a blank card: the shared block at card size (css/states.css). The rules here
   only cover a .card-empty written by hand. */
.card-empty:not(.estate) { display: grid; justify-items: center; align-content: center; gap: var(--s2); min-height: 6rem; padding: var(--s4) var(--s2); text-align: center; }
.card-empty-title:not(.estate-title) { font: var(--type-body-strong); color: var(--ink-strong); max-width: 40ch; }
.card-empty-body:not(.estate-body) { max-width: 40ch; font: var(--type-meta); color: var(--muted); }

.projects--empty { display: block; }

/* Avatar menu: the state switcher. */
.popover--wide { width: 19rem; }
.menu-label { padding: var(--s2) var(--s2) 0.1875rem; font: var(--w-medium) var(--text-2xs)/1.2 var(--sans); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--muted); }
.menu-states { max-height: 16rem; overflow: auto; margin: 0 -0.125rem; padding: 0 0.125rem; }
.menu-group { padding: var(--s2) var(--s2) 0.125rem; font: var(--w-medium) var(--text-2xs)/1.2 var(--sans); letter-spacing: var(--track-eyebrow); text-transform: uppercase; color: var(--faint); }
.menu-row--state { height: 2rem; font-size: var(--text-sm); }
.menu-row--state.is-on { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--ink-900); font-weight: var(--w-medium); color: var(--ink-strong); }

/* Help (the avatar menu's Help row, at #/support/details). */
.faq { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s5) var(--s6); }
.faq-q { font: var(--w-medium) var(--text-md)/1.4 var(--sans); color: var(--ink-strong); }
.faq-a { margin-top: var(--s1); font: var(--w-regular) var(--text-sm)/var(--lh-body) var(--sans); color: var(--muted); max-width: var(--measure-body); }
.faq-foot { margin-top: var(--s5); padding-top: var(--s3); border-top: 1px solid var(--line); }
@media (max-width: 680px) { .faq { grid-template-columns: 1fr; } }

/* The pipeline line belongs under the steps, not beside them. */
.auto-line { text-align: center; margin: 0 auto; }
.cur-step { margin: 0 0 var(--s3); text-align: center; font: var(--w-medium) var(--text-md)/1.3 var(--sans); color: var(--ink-strong); }

/* A recommendation is a headline, never a paragraph. */
.assistant-rec p { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
/* The three cards in a row share one height, so the row reads as one band. */
body[data-route="home"] .row--3 { align-items: stretch; }
/* Titles in Home's lists get two lines before they are cut, so a phone shows
   enough of a title to tell videos apart. */
body[data-route="home"] .project h4 {
  white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
@media (max-width: 1019px) {
  body[data-route="home"] .attn strong { white-space: normal; }
  body[data-route="home"] .cur-facts dd { white-space: normal; }
  body[data-route="home"] .attn small {
    white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  }
}
/* Above phone width the upload action sits beside the greeting, the way other
   pages put their action beside the title, so Home fits one screen at 1440x900. */
@media (min-width: 681px) {
  body[data-route="home"] .hero {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--s5); align-items: end;
  }
  body[data-route="home"] .hero > :not(.hero-actions) { grid-column: 1; }
  body[data-route="home"] .hero-actions { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }
}
/* Both looks: Home's spacing is tightened so the common states fit 1440x900
   without scrolling; the type scale is unchanged. */
html[data-look] body[data-route="home"] .hero { padding-top: 0; }
html[data-look] body[data-route="home"] .outlet { row-gap: var(--s4); }
html[data-look] body[data-route="home"] .card.current,
html[data-look] body[data-route="home"] .row--3 > .card { padding-top: var(--s5); padding-bottom: var(--s5); }
html[data-look] body[data-route="home"] .card.assistant { padding-top: var(--s3); padding-bottom: var(--s3); }
html[data-look] body.app[data-route="home"] .main { padding-bottom: var(--s4); }
/* The page's own bottom air is the .main padding above; the outlet adds none on Home. */
body[data-route="home"] .outlet { padding-bottom: 0; }
/* Step tracker: finished steps step back so the one in progress carries the
   emphasis (the Volare look otherwise draws done steps darkest). */
html[data-look="volare"] .cur-progress:has(.step.active) .step.done .dot { background: color-mix(in srgb, var(--v-charcoal) 14%, var(--v-salt)); color: var(--v-charcoal); }
/* A long one-word name breaks rather than pushing the greeting off screen. */
body[data-route="home"] .hero h1 { overflow-wrap: break-word; }
/* Urgency is said by the icon shape and the task name as well as the edge
   colour; the icon picks up the same tone. */
.attn--fail > .i:first-child { color: var(--dk-tx-st-fail, var(--st-fail)); }
.attn--attn > .i:first-child { color: var(--dk-tx-st-attn, var(--st-attn)); }
/* Sparklines sit on one baseline across tiles, and a tile without history
   keeps the same height. */
.perf .stat .spark { margin-top: auto; }
.perf .spark--none { height: 1.5rem; }
.perf .spark-range { min-height: 1.2em; }
/* Every clickable thing on Home shows keyboard focus. A recent-video row is
   reached through its title link, and the whole row lights up. */
.project-link { color: inherit; text-decoration: none; outline: none; }
.project:has(.project-link:focus-visible) { background: var(--hover-card); box-shadow: 0 0 0 2px var(--accent); }
a.stat:focus-visible { outline: 2px solid var(--dk-tx-accent, var(--accent)); outline-offset: 2px; }
/* Phone order: the current video and what waits on the creator first,
   performance last. */
@media (max-width: 680px) {
  body[data-route="home"] .row--3 { display: contents; }
  body[data-route="home"] .row--3 > .perf { order: 1; }
}
.assistant-rec h3 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* First run: hero on top, the one empty state centred on the page in the space under it, with no frame. */
body.app .main--solo { display: flex; flex-direction: column; }
/* Full width, so the greeting starts where every page title starts; only the empty state is centred. */
body.app .main--solo > .outlet--solo { flex: 1; width: 100%; grid-template-rows: auto 1fr; }
.estate.firstrun { align-self: center; justify-self: center; width: 100%; max-width: 44rem; padding-top: var(--s4); }
.estate.firstrun .estate-body { max-width: min(48ch, 100%); }

/* The workspace head is a back link stacked over a title row, not the
   title-plus-action pair the shared `.page-head` grid above lays out, so it
   opts back into a single column rather than being split into two. */
body.app .page-head--ws {
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  row-gap: var(--s2);
  margin-top: 0; padding-bottom: 0;
}
body.app .page-head--ws > * { grid-column: 1; }
body.app .page-head--ws .ws-title-row h1 {
  font: var(--w-medium) var(--text-3xl)/var(--lh-heading) var(--font-serif);
  letter-spacing: var(--track-heading);
}

/* Help keeps questions and contact actions in one readable column. */
.support-page { width: 100%; max-width: 680px; display: grid; gap: var(--gap-card); }
.support-page .faq { grid-template-columns: 1fr; }
.support-page .faq-a { max-width: none; }
.support-page .form-actions { margin-top: var(--s3); flex-wrap: wrap; }
.support-page { min-width: 0; }
.support-page > * { min-width: 0; max-width: 100%; }
.support-page .help-toc { flex-wrap: wrap; }
.support-page .help-toc .fpill { white-space: normal; text-align: left; height: auto; min-height: 2.25rem; }
.support-page .faq-link { margin-top: var(--s2); font: var(--w-medium) var(--text-sm)/1.4 var(--sans); }
.support-page #askVolare:empty { display: none; }
.support-page .set-surface > .set-card { scroll-margin-top: var(--s5); }
.support-page .set-card h2:focus { outline: none; }

/* ---------- Settings and Help: one surface ----------
   Each section inside it is a group: its title, one line, its rows; a hairline between groups.
   The group title steps down to the strong body size so the pane title above stays the heading. */
.card.set-surface, html[data-look] .card.set-surface { display: block; padding: 0 var(--pad-card); }
.set-surface > .set-card,
html[data-look] .set-surface > .card.set-card {
  display: block; background: none; border: 0; border-radius: 0; box-shadow: none; padding: 0; margin: 0; outline: 0;
}
html[data-look] .set-surface > .set-card + .set-card { border-top: 1px solid var(--line-2); }
.set-surface .set-rule { display: none; }
html[data-look] .set-surface .set-head { padding: var(--s6) 0 0; gap: var(--s4); align-items: center; }
html[data-look] .set-surface .set-body { padding: var(--s4) 0 var(--s6); }
html[data-look] .set-surface .set-body--tight { padding-top: var(--s4); }
html[data-look] .set-surface .set-head-text h2 { font: var(--type-body-strong); letter-spacing: 0; color: var(--ink-strong); }
html[data-look] .set-surface .set-head-text p { margin-top: var(--s1); font: var(--type-meta); color: var(--muted); max-width: var(--measure); }
.set-surface .field-note, .set-surface .footnote { font: var(--type-meta); color: var(--muted); max-width: var(--measure); }
.set-surface .field-label { font: var(--type-meta); color: var(--muted); }
.set-surface .field-value { margin-top: var(--s1); font: var(--type-body-strong); color: var(--ink-strong); font-variant-numeric: var(--nums-tabular); }
.set-surface .int-text strong, .set-surface .pref-label strong { font: var(--type-body-strong); }
.set-surface .int-text small, .set-surface .pref-label small { font: var(--type-meta); color: var(--muted); }
/* rows run edge to edge of the group: the first row needs no extra air above it */
.set-surface .int-list > :first-child, .set-surface .pref-list > .pref:first-child { padding-top: 0; }
.set-surface .int-list > :last-child, .set-surface .pref-list > .pref:last-child { padding-bottom: 0; }

/* Advanced: "Delete this workspace" is last and set apart by its words and its red title, not a red box. */
.set-surface > .trust-danger { margin-top: 0; outline: 0; }
html[data-look] .set-surface > .trust-danger .set-head-text h2 { color: var(--dk-tx-st-fail, var(--st-fail)); }

/* Held back while a route's own stylesheet and script load (js/router.js). If that takes longer than a blink, the
   page's own skeleton (js/states.js) stands over the hidden page, so nothing sits blank and nothing jumps. */
.outlet.is-loading { position: relative; min-height: 60vh; }
.outlet.is-loading > :not(.outlet-skel) { visibility: hidden; }
.outlet-skel { position: absolute; inset: 0; overflow: hidden; }

/* Home: the upload action sits on a plain card surface, not on the header pattern behind it. */
html[data-look]:not([data-look="stage"]) body[data-route="home"] .hero-actions .btn--outline { background: var(--card); }
/* Billing: a plain page, so its note and buttons get the room a form would. */
.billing-page .field-note { margin: var(--s4) 0; max-width: var(--measure); }
.billing-page .fields { gap: var(--s4) var(--s8); }

/* ---- Home progress, one position for every width: the dots on a wide card, "Step N of M: name" and a bar on a phone ---- */
.cur-progress .cur-bar { display: none; margin: var(--s2) 0 var(--s3); }
@media (max-width: 768px) {
  html[data-look] .cur-progress .stepper { display: none; }
  html[data-look] .cur-progress .cur-bar { display: block; }
  .cur-step { text-align: left; }
  /* Recent videos on a phone: title on line 1 (cut with an ellipsis), status and time on line 2, the menu pinned right. */
  body[data-route="home"] .project { grid-template-columns: 4.5rem minmax(0, 1fr) auto; align-items: center; }
  body[data-route="home"] .project h4 { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: unset; }
  body[data-route="home"] .project-sub { flex-wrap: nowrap; justify-content: space-between; gap: var(--s2); }
  body[data-route="home"] .project .thumb-more { grid-column: 3; align-self: center; justify-self: end; }
}

/* ---- The video page header (js/views.js videoHead): preview frame, then title + status chip + menu ---- */
.vhead-row { display: flex; align-items: flex-start; gap: var(--s4); min-width: 0; }
.vhead-body { flex: 1 1 auto; min-width: 0; display: grid; gap: var(--s1); }
.vhead-thumb { flex: none; position: relative; width: 7.5rem; aspect-ratio: 16 / 9; border-radius: var(--r-sm); overflow: hidden; background: var(--soft); box-shadow: inset 0 0 0 1px var(--line-2); }
.vhead-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.vhead-thumb--empty { display: grid; place-content: center; justify-items: center; gap: 2px; color: var(--muted); }
.vhead-thumb-label { font: var(--w-medium) 12px/1.2 var(--sans); }
.vhead-sub { margin: 0; }
@media (max-width: 768px) { .vhead-thumb { width: 5.5rem; } .vhead-row { gap: var(--s3); } }

/* ---- A wide dialog (Brand: Custom graphics style): scrolls inside itself, close button in the corner ---- */
.modal--wide { width: min(44rem, 94vw); max-height: calc(100dvh - 2 * var(--s4)); overflow: auto; overscroll-behavior: contain; align-content: start; }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); }
.modal-x { flex: none; display: grid; place-items: center; width: 2.75rem; height: 2.75rem; margin: calc(-1 * var(--s2)) calc(-1 * var(--s2)) 0 0; border: 0; border-radius: 50%; background: transparent; color: var(--ink); cursor: pointer; }
.modal-x:hover { background: var(--soft); }
.modal-x:focus-visible, .modal:focus-visible { outline: 2px solid var(--dk-tx-accent, var(--accent)); outline-offset: 2px; }
.modal:focus { outline: none; }
.be-modal .be-custom-acts { background: transparent; }

/* ---- Insights with no channel: one centred group (picture, words, button, then a plain caption), in the space under the header ---- */
body[data-route="insights"] .estate.insights-empty { min-height: calc(100dvh - 17rem); display: grid; place-content: center; justify-items: center; text-align: center; gap: var(--s3); }
body[data-route="insights"] .estate.insights-empty > * { margin-top: 0; margin-bottom: 0; }
.estate-caption { flex: 0 0 100%; margin: var(--s2) 0 0; font: var(--type-meta); color: var(--muted); text-align: center; }
body[data-route="insights"] .estate.insights-empty .estate-actions, body[data-route="insights"] .estate.insights-empty .estate-act { flex-wrap: wrap; justify-content: center; }

/* ---- The "?" help button floats over the page: the page always ends clear of it, inside any scroll container ---- */
html:has(.ask-fab) .outlet::after { content: ''; display: block; height: calc(48px + var(--s5, 24px)); }
