:root {
  /* ===== Night theme design tokens (semantic — restyle by changing values) ===== */
  /* Surfaces & lines */
  --bg:#0F0E13;              /* app canvas */
  --surface:#17161C;         /* cards, inputs, popovers */
  --surface-2:#1C1B22;       /* insets, secondary fills */
  --sidebar:#0B0A0F;         /* ink nav rail (darkest) */
  --sidebar-raised:#22212A;  /* active nav row, chips */
  --border:#26242E;          /* default hairline */
  --border-strong:#302E3A;   /* inputs, dividers */

  /* Text */
  --text:#F1EFF5;            /* primary text */
  --text-muted:#A29DAC;      /* secondary copy */
  --text-faint:#6C6775;      /* meta, disabled */
  --on-ink:#948F9C;          /* text on --sidebar */
  --on-ink-active:#FFFFFF;

  /* Accent — single hue, interactive only */
  --accent:#5B7CFF;
  --accent-deep:#33499E;     /* past-the-estimate progress — same hue, clearly darker */
  --accent-weak:#1A2140;     /* selected / active bg */
  --accent-border:#2E3A6B;
  --on-accent:#fff;          /* text on an accent fill (dark under the light tones below) */

  /* Brain — reserved for the voice / Brain feature ONLY */
  --brain:#9B6BFF;
  --brain-weak:#241A3A;

  /* Status */
  --ok:#34C88A;     --ok-weak:#12271E;
  --warn:#E0A93A;   --warn-weak:#2C2410;
  --danger:#FF6B76; --danger-weak:#31191C;

  /* Radius & elevation (soft — no neon glow) */
  --r-sm:9px; --r-md:12px; --r-lg:18px; --r-pill:999px;
  --shadow-card:0 12px 34px rgba(0,0,0,.5);
  --shadow-pop:0 16px 40px rgba(0,0,0,.6);
  --shadow-accent:0 8px 20px color-mix(in srgb, var(--accent) 35%, transparent);

  /* Type families */
  --font-display:'Bricolage Grotesque',sans-serif;  /* headlines, big numbers */
  --font-sans:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;  /* body, labels, UI */
  --font-mono:'Space Mono',ui-monospace,monospace;  /* kickers, values, meta */

  /* ===== compat aliases: old names → palette (existing CSS keeps working) ===== */
  --bg-2:        var(--surface-2);
  --card:        var(--surface);
  --card-2:      var(--surface-2);
  --border-hi:   var(--border-strong);
  --muted:       var(--text-muted);
  --faint:       var(--text-faint);
  --cyan:        var(--accent);
  --cyan-dim:    var(--accent);
  --magenta:     var(--accent);     /* one accent hue only — no second color */
  --magenta-dim: var(--accent);
  --err:         var(--danger);
  --glow-cyan:    0 0 0 1.5px var(--accent);   /* was neon glow → crisp accent ring */
  --glow-magenta: 0 0 0 1.5px var(--accent);
  --grad:  var(--accent);            /* was cyan→magenta gradient → solid accent */
  --radius: var(--r-lg);
  --shadow: var(--shadow-card);

  --header-bg: rgba(15,14,19,.82);   /* frosted top bar */
  --sidebar-w: 220px;
  --sidebar-w-collapsed: 64px;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--bg);            /* Daylight: paper canvas, no photo overlay */
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
h1 { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.022em; font-size: 1.7rem; margin: 0 0 18px; }
h2 { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.015em; font-size: 1.2rem; margin: 0 0 6px; }
h3 { font-family: var(--font-display); font-weight: 700; font-size: 1rem; }
.muted { color: var(--muted); }
.small { font-size: 0.82rem; }
.hidden { display: none !important; }

/* ============================== LAYOUT ============================== */
.app { display: flex; min-height: 100vh; }
/* whole app fades in when you enter it (after login / on load) */
.app:not(.hidden) { animation: appIn .45s ease both; }
@keyframes appIn { from { opacity: 0; } to { opacity: 1; } }

/* ----------------------------- SIDEBAR ----------------------------- */
.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--sidebar);          /* Daylight: dark ink rail on the light app */
  border-right: 1px solid var(--sidebar-raised);
  display: flex;
  flex-direction: column;
  padding: 18px 12px;
  transition: width .2s ease;
  position: sticky; top: 0; height: 100vh;
}
.app.collapsed .sidebar { width: var(--sidebar-w-collapsed); }
.app.collapsed .lbl,
.app.collapsed .brand-name,
.app.collapsed .nav-group-lbl,
.app.collapsed .pill-text { display: none; }

/* A <button> now, so it needs the browser's button chrome stripped and the affordance put
   back deliberately — width:100% and text-align keep it laid out exactly as the <div> was. */
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 22px;
  width: 100%; background: none; border: 0; font: inherit; color: inherit;
  text-align: left; cursor: pointer; }
.brand:hover .brand-glyph { filter: brightness(1.25); }
.brand:focus-visible { outline: 2px solid var(--cyan-dim); outline-offset: 2px; border-radius: 8px; }
/* The Muse mark (web/logo-mark.svg, 2026-10-13): the M with a play button in its valley. */
.brand-glyph { width: 30px; height: auto; flex: none; display: block; }
.brand-name { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.01em; color: var(--on-ink-active); }

.nav { display: flex; flex-direction: column; gap: 4px; }
/* Admin sits apart from the everyday pages: a rule and a quiet label, so it reads as a different
   kind of thing rather than a seventh destination. */
.nav-group { display: flex; flex-direction: column; gap: 4px;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--sidebar-line, rgba(255,255,255,.07)); }
.nav-group-lbl { padding: 0 12px 4px; font-size: .64rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
/* Collapsed, the label is gone and the rule alone would read as a stray line. */
.app.collapsed .nav-group { margin-top: 10px; padding-top: 10px; }
.nav-item {
  display: flex; align-items: center; gap: 12px;
  background: transparent; border: none; color: var(--on-ink);
  padding: 11px 12px; border-radius: 10px; cursor: pointer;
  font-size: 0.92rem; text-align: left; width: 100%;
  position: relative; transition: background .15s, color .15s;
}
.nav-item .ico { width: 20px; display: inline-flex; align-items: center; justify-content: center; text-align: center; font-size: 1rem; }
.nav-item .ico svg { width: 19px; height: 19px; display: block; }
.nav-item:hover { background: var(--sidebar-raised); color: var(--on-ink-active); }
.nav-item.active { color: var(--on-ink-active); background: var(--sidebar-raised); }
/* No accent rail on the active item — the raised background already marks it, and the bar was a
   second marker for the same thing, colliding with the Manage group's divider on the way. The
   mobile bottom-bar variant below is a different layout and keeps its own indicator. */
.nav-item.active .ico { color: var(--accent); }
/* Workspaces icon glows green while ANY workspace is running */
.nav-item.running .ico { color: #22c55e; animation: navRunGlow 2.2s ease-in-out infinite; }
@keyframes navRunGlow {
  0%, 100% { filter: drop-shadow(0 0 2px rgba(34,197,94,.55)); }
  50%      { filter: drop-shadow(0 0 8px rgba(34,197,94,.95)); }
}

.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }
.status-pill {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--card);
  font-size: 0.78rem; color: var(--muted);
}
.orb-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--faint); flex-shrink: 0; }
.status-pill.running { color: var(--text); border-color: var(--ok); }
.status-pill.running .orb-dot { background: var(--ok); box-shadow: 0 0 8px var(--ok); animation: pulse 1.4s ease-in-out infinite; }
.status-pill.capped .orb-dot { background: var(--warn); box-shadow: 0 0 8px var(--warn); }
.collapse-btn {
  background: var(--card); border: 1px solid var(--border); color: var(--muted);
  border-radius: 8px; padding: 6px; cursor: pointer; font-size: 0.9rem;
}
.collapse-btn:hover { color: var(--text); }
.app.collapsed .collapse-btn { transform: rotate(180deg); }

/* ------------------------------ MAIN ------------------------------ */
/* Content fills ~95% of the available width (minus the sidebar) across the whole app:
   2.5% horizontal padding each side. These are dense, multi-column pages — grids, split
   views, side panels — and the old 10% gutters cost them a whole column. */
.main { flex: 1; min-width: 0; padding: 72px 2.5% 80px; width: 100%; }
.app.wide-main .main { max-width: none; }

/* ----------------------------- TOPBAR ----------------------------- */
.topbar {
  position: fixed; top: 0; left: var(--sidebar-w); right: 0; height: 52px; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; padding: 0 26px;
  background: var(--header-bg); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border); transition: left .2s ease;
}
.app.collapsed .topbar { left: var(--sidebar-w-collapsed); }
/* The workspace switcher used to hold the left half of this bar; with it gone, `space-between`
   had nothing to space and the notifications + account group slid to the left edge. */
.topbar-right { display: flex; align-items: center; gap: 10px; margin-left: auto; }
/* Phones only — the desktop sidebar is always visible, so neither has a job there. Declared
   HERE, above the phone media query: at equal specificity the later rule wins, and a base
   `display:none` placed after it would switch the hamburger back off on the one screen that
   needs it. */
.nav-toggle, .nav-scrim, .notif-x, .wsp-more, .ws-more, .ref-list-caret, .tabbar,
.ref-head-sel, .pe-act-lbl { display: none; }
/* Dissolved, so .ref-list-col stays a two-child flex column: list that scrolls, pager
   pinned under it. On a phone this same element becomes the dropdown panel. */
.ref-drop { display: contents; }
/* ---- admin user-logs ---- */
.log-detail { font-size: .8rem; color: var(--muted); max-width: 560px; }
.admin-table tr.log-err .log-detail { color: var(--err); }
.log-badge { font-size: .72rem; padding: 2px 9px; border-radius: 999px; border: 1px solid var(--border-hi); }
.log-badge.ok { color: var(--ok); border-color: var(--ok); }
.log-badge.err { color: var(--err); border-color: rgba(255,93,108,.5); background: rgba(255,93,108,.08); }
.admin-table tr.log-row { cursor: pointer; }
/* Credits pricing: tap/click a row to highlight it (easier to read across the wide columns) */
#credPricing .admin-table tbody tr { cursor: pointer; }
#credPricing .admin-table tbody tr:hover td { background: var(--card-2); }
.admin-table tbody tr.row-sel td { background: rgba(0, 229, 255, .12); }
.admin-table tr.log-row:hover td { background: var(--card-2); }
.log-modal { width: 100%; box-sizing: border-box; padding: 22px 22px 24px; }
.log-modal-title { margin: 0 0 2px; font-size: 1.15rem; }
.log-modal-meta { color: var(--muted); font-size: .8rem; margin-bottom: 14px; }
.log-modal-label { font-size: .72rem; font-weight: 700; color: var(--muted); text-transform: uppercase;
  letter-spacing: .05em; margin: 14px 0 5px; }
.log-summary { display: flex; align-items: center; gap: 9px; padding: 11px 13px; border-radius: 10px;
  background: rgba(255,93,108,.08); border: 1px solid rgba(255,93,108,.35); color: #ffd0d5;
  font-size: .9rem; font-weight: 600; }
.log-summary-tag { font-size: .66rem; font-weight: 800; letter-spacing: .05em; padding: 3px 8px; border-radius: 6px;
  background: var(--err); color: #fff; flex: none; }
.log-pre-prefix { font-size: .82rem; color: var(--muted); margin-bottom: 6px; }
.log-pre { white-space: pre-wrap; word-break: break-word; background: var(--card-2); border: 1px solid var(--border);
  border-radius: 9px; padding: 11px 13px; font-size: .8rem; line-height: 1.5; color: var(--text);
  max-height: 320px; overflow: auto; margin: 0; }
.log-pre.err { color: #ffc2c8; border-color: rgba(255,93,108,.35); background: rgba(255,93,108,.05); }
.log-thumbs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.log-thumb { width: 34px; height: 46px; object-fit: cover; border-radius: 5px; border: 1px solid var(--border-hi); }
.log-thumb.lg { width: 70px; height: 94px; }
.kind-badge { font-size: .68rem; font-weight: 700; padding: 2px 8px; border-radius: 6px; border: 1px solid var(--border-hi); }
.kind-badge.t2v { color: var(--cyan); border-color: rgba(0,229,255,.4); }
.kind-badge.ref { color: var(--magenta); border-color: rgba(255,43,214,.4); }   /* i2v + r2v need a reference */
.log-scroll { max-height: 320px; overflow: auto; border: 1px solid var(--border); border-radius: 10px; }
.log-scroll .admin-table { margin: 0; }
.log-scroll thead th { position: sticky; top: 0; background: var(--card); z-index: 1; }
.log-pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 12px 0 4px; }
.log-settings { width: 100%; border-collapse: collapse; font-size: .82rem; }
.log-settings td { padding: 5px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
.log-settings td:first-child { width: 130px; white-space: nowrap; }
.img-zoom { position: fixed; inset: 0; z-index: 300; display: flex; align-items: center; justify-content: center;
  background: rgba(2,3,6,.85); backdrop-filter: blur(4px); cursor: zoom-out; padding: 30px; }
.img-zoom img { max-width: 92vw; max-height: 92vh; border-radius: 10px; box-shadow: var(--shadow); }
.log-thumb { cursor: zoom-in; }
.log-ref-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.log-ref-view { display: inline-flex; align-items: center; gap: 7px; padding: 7px 12px; border-radius: 9px;
  cursor: pointer; font: inherit; font-size: .8rem; background: var(--card-2); border: 1px solid var(--border-hi);
  color: var(--text); }
.log-ref-view:hover { border-color: var(--cyan); color: var(--cyan); }
.log-ref-view svg { width: 15px; height: 15px; }
.log-ref-loaded { display: inline-block; }
/* ---- new-version banner ---- */
.update-bar { position: fixed; top: 76px; left: 50%; transform: translateX(-50%); z-index: 200;
  display: flex; align-items: center; gap: 10px; padding: 9px 12px 9px 14px; border-radius: 999px;
  background: var(--card-2); border: 1px solid var(--cyan); box-shadow: var(--shadow);
  font-size: .85rem; color: var(--text); }
.update-bar.hidden { display: none; }
.update-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--cyan);
  box-shadow: 0 0 8px var(--cyan); flex: none; }
.update-reload { cursor: pointer; border: none; border-radius: 999px; padding: 5px 14px; font: inherit;
  font-weight: 700; color: #0a0c12; background: var(--grad); }
.update-reload:hover { filter: brightness(1.08); }
.update-close { cursor: pointer; background: none; border: none; color: var(--muted); font-size: .8rem; padding: 2px 4px; }
.update-close:hover { color: var(--text); }
/* ---- notifications bell ---- */
.notif { position: relative; }
.notif-btn { position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 10px; cursor: pointer; background: var(--card);
  border: none; color: var(--text); padding: 0; }
.notif-btn:hover { background: var(--card-2); }
.notif-btn svg { width: 19px; height: 19px; }
.notif-badge { position: absolute; top: -3px; right: -3px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: var(--err); color: #fff; font-size: .64rem; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; border: 2px solid var(--bg); }
.notif-drop { position: absolute; top: 46px; right: 0; width: 320px; max-height: 70vh; overflow-y: auto; z-index: 60;
  padding: 0; background: var(--card); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow); }
/* NOT space-between: with three children (title, Allow, ✕) it spreads the free space across
   BOTH gaps, so the toggle floats in the middle of the header instead of sitting with the
   control it belongs beside. The title takes the slack instead, which also keeps the spacing
   from shifting when the ✕ is absent — it is phones only. */
.notif-head { display: flex; align-items: center; justify-content: flex-start; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--border); }
.notif-title { flex: 1 1 auto; min-width: 0; font-weight: 700; }
.notif-allow { display: inline-flex; align-items: center; gap: 8px; }
.notif-list { padding: 6px; }
.notif-item { display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: none; color: var(--text); padding: 9px 10px; border-radius: 8px; }
.notif-item:hover { background: var(--card-2); }
.notif-item-ws { font-weight: 600; font-size: .82rem; }
.notif-item-cap { color: var(--muted); font-size: .74rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notif-empty { padding: 18px 14px; text-align: center; }
/* Read, but still pending. Dimmed rather than removed: the clip has not been dealt with, and
   hiding it would make the bell disagree with the Library. */
.notif-item.seen .notif-item-ws { font-weight: 500; color: var(--muted); }
.notif-item.seen .notif-item-cap { color: var(--faint); }
/* A strip under the header rather than a block at the end. Right-aligned and sized to its
   label: full width directly beneath the title would read as the panel's subject, and the
   subject is the list. */
.notif-foot { display: flex; justify-content: flex-end; flex: none;
  padding: 8px 10px; border-bottom: 1px solid var(--border); }
.notif-clear {
  padding: 5px 11px; border-radius: var(--r-pill); cursor: pointer;
  background: transparent; border: 1px solid var(--border); color: var(--muted);
  font-size: .74rem; font-weight: 600; font-family: inherit;
}
.notif-clear:hover { background: var(--card-2); color: var(--text); }
/* ---- library: editable caption on pending cards ---- */
.lib-badge-ico { width: 13px; height: 13px; vertical-align: -2px; margin-right: 2px; }
.lib-cap-label { display: block; margin-bottom: 4px; }
.lib-cap-box { position: relative; }
.lib-cap-edit { width: 100%; resize: none; background: var(--card-2); border: 1px solid var(--border-hi);
  border-radius: 8px; color: var(--text); font-size: .82rem; padding: 7px 30px 7px 9px; font-family: inherit; outline: none; }
.lib-cap-edit[readonly] { cursor: default; }
.lib-cap-edit.editing { resize: vertical; border-color: var(--cyan); box-shadow: 0 0 0 3px rgba(0,229,255,.12); }
.lib-cap-pencil { position: absolute; right: 6px; bottom: 7px; width: 24px; height: 24px; border-radius: 7px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  background: rgba(8,9,14,.7); border: 1px solid var(--border-hi); color: var(--muted); }
.lib-cap-pencil:hover { color: var(--cyan); border-color: var(--cyan); }
.lib-cap-pencil svg { width: 13px; height: 13px; }
.acct-menu { position: relative; }
.acct-btn {
  display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: .9rem;
  background: var(--card); border: none; color: var(--text);
  padding: 6px 10px; border-radius: 10px;
}
.acct-btn:hover { background: var(--card-2); }
.acct-avatar {
  width: 24px; height: 24px; border-radius: 50%; background: var(--grad); color: var(--on-accent);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .72rem; font-weight: 700; text-transform: uppercase; flex-shrink: 0;
}
.acct-caret { color: var(--muted); font-size: .7rem; }
.acct-drop {
  position: absolute; top: 46px; right: 0; min-width: 210px; z-index: 60; padding: 8px;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow);
}
.acct-drop-head {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px 10px; margin-bottom: 6px;
  border-bottom: 1px solid var(--border); font-weight: 600;
}
.acct-drop-item {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: none; color: var(--text); padding: 9px 10px; border-radius: 8px; font-size: .9rem;
}
.acct-drop-item .drop-ico { width: 16px; height: 16px; flex: none; }
.acct-drop-item:hover { background: var(--card-2); }
.acct-drop-item.danger { color: var(--err); }
.acct-drop-item.danger:hover { background: rgba(255,93,108,.12); }

/* accounts tabs (mirror admin tabs) + table action buttons */
.acct-tab {
  background: transparent; border: none; border-bottom: 2px solid transparent;
  color: var(--muted); padding: 10px 14px; cursor: pointer; font-size: .92rem; margin-bottom: -1px;
}
.acct-tab:hover { color: var(--text); }
.acct-tab.on { color: var(--text); border-bottom-color: var(--cyan); }
.row-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
.btn-ghost.sm { padding: 5px 10px; font-size: .8rem; }
#accRedirect { font-size: .8rem; }

/* sidebar credits (bottom-left) */
.side-credits {
  display: flex; align-items: center; gap: 10px; width: 100%; cursor: pointer; font-size: .85rem;
  background: var(--card); border: none; color: var(--text);
  padding: 9px 12px; border-radius: 10px;
}
.side-credits:hover { background: var(--card-2); }
.side-credits .ico { font-size: .95rem; display: inline-flex; align-items: center; }
.side-credits .ico svg { width: 16px; height: 16px; }
.side-credits-val { margin-left: auto; font-weight: 700; color: var(--cyan); }
.app.collapsed .side-credits .lbl { display: none; }
/* Collapsed sidebar: stack the coin over the value so it fits the narrow rail */
.app.collapsed .side-credits { flex-direction: column; gap: 2px; padding: 8px 2px; justify-content: center; }
.app.collapsed .side-credits-val { margin-left: 0; font-size: .72rem; line-height: 1; }
.view { display: none; }
.view.active { display: block; animation: pageIn .32s cubic-bezier(.22,.61,.36,1); }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
/* opacity-only (no transform) so it never creates a containing block that breaks position:sticky */
@keyframes pageIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
@keyframes breathe { 0%,100% { transform: scale(1); } 50% { transform: scale(1.06); } }
@keyframes glowWarm {
  0%,100% { box-shadow: 0 0 14px rgba(255,181,71,.4); }
  50% { box-shadow: 0 0 26px rgba(255,181,71,.7); }
}

/* ============================== ATOMS ============================== */
.card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 22px; margin-bottom: 18px;
}
.card.danger { border-color: rgba(255,93,108,.3); }

/* ---- Settings: compact row layout ---- */
.set-group-label { font-size: 0.72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 22px 4px 10px; }
/* 720px was set when Settings was a short list of toggles. It now sits on the same wide canvas
   as every other page, and a column that stops at 720 leaves two thirds of the screen empty
   while the rows inside it stay cramped. Capped rather than unbounded: a settings row whose
   label and control are a metre apart is no easier to read than one that is too narrow. */
.set-card { padding: 0; max-width: 980px; }
.view-settings .set-group-label { max-width: 980px; }
.set-row { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 16px 20px; }
.set-row-info { min-width: 0; }
.set-row-title { font-weight: 600; font-size: 0.95rem; margin-bottom: 2px; }
.set-row-title.set-danger { color: var(--err); }
.set-row-desc { line-height: 1.4; max-width: 46ch; }
.set-divider { height: 1px; background: var(--border); }
.set-btn { flex: none; }
.set-profile { display: flex; align-items: center; gap: 8px; flex: none; }
.set-profile input { max-width: 190px; }
.set-msg { display: block; padding: 0 20px 14px; }
.set-msg:empty { display: none; }

label { display: block; font-size: 0.85rem; color: var(--muted); margin-bottom: 6px; }
.field { margin: 18px 0; }
.field-head { display: flex; justify-content: space-between; align-items: baseline; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
/* First post time is the decision; timezone is just its reference frame → narrower, on the right */
.grid-start { display: grid; grid-template-columns: 1fr auto; gap: 14px; align-items: start; }
.grid-start #wTz { min-width: 118px; }
#wStartHint { display: block; margin-top: 6px; line-height: 1.4; }

textarea, .select, input[type="text"], input[type="number"],
input[type="password"], input[type="email"] {
  width: 100%; padding: 11px 13px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--bg);
  color: var(--text); font-size: 0.95rem; font-family: inherit;
  transition: border-color .15s, box-shadow .15s;
}
/* kill Chrome's white/yellow autofill background on dark inputs (incl. the
   bright preview highlight shown while hovering an autofill suggestion) */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
input:autofill {
  -webkit-text-fill-color: var(--text) !important;
  -webkit-box-shadow: 0 0 0 1000px var(--bg) inset !important;
  box-shadow: 0 0 0 1000px var(--bg) inset !important;
  caret-color: var(--text) !important;
  /* defeat Chrome's autofill-preview background flash */
  transition: background-color 9999s ease-in-out 0s !important;
}
textarea { resize: vertical; }
.story-field { margin-top: 14px; }

/* Output picker — Single clip vs Story reel (radio cards) */
/* The stacked radio-card picker is gone — both places that used it (Content style,
   dialogue mode) are segmented glass pills now. */

/* pill toggle switch */
.toggle-row { display: flex; align-items: center; gap: 10px; }
.toggle-label { margin: 0; font-weight: 600; color: var(--text); cursor: pointer; font-size: .92rem; }
.switch { position: relative; display: inline-flex; width: 40px; height: 22px; flex-shrink: 0; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track { position: absolute; inset: 0; border-radius: 999px; background: var(--border-hi); transition: background .18s; }
.switch .track::before {
  content: ""; position: absolute; left: 3px; top: 3px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; transition: transform .18s; box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.switch input:checked + .track { background: var(--cyan); box-shadow: 0 0 8px rgba(0,229,255,.45); }
.switch input:checked + .track::before { transform: translateX(18px); }
.switch input:focus-visible + .track { outline: 2px solid var(--cyan-dim); outline-offset: 2px; }

/* Nudge the "+ New workspace" button when driver.js isn't available (fallback) */
.nudge { animation: nudgePulse 1s ease-in-out infinite; }
@keyframes nudgePulse { 0%,100% { box-shadow: 0 0 0 0 rgba(0,229,255,.5); } 50% { box-shadow: 0 0 0 6px rgba(0,229,255,0); } }

/* ---- Prompts builder (two embedded columns: left config · right editable preview) ---- */
/* Preset editor is a 2-column workspace: the configure/prompt pane and the live prompt
   preview it feeds. Version history is a right-hand drawer, not a column — as a fixed
   300px rail it squeezed the preview to a few words per line, and inline it collided
   with the sticky preview pane. */
/* The two-column layout moved from the view to #presetEditor: the view now also holds the
   index, and grid areas only bind to DIRECT children. */
#presetEditor:not(.hidden) {
  display: grid; align-items: start;
  grid-template-columns: minmax(0,1fr) minmax(0,1.1fr);
  column-gap: 32px;
  grid-template-areas:
    "back  back"
    "head  head"
    "tools tools"
    "pane  prompt"
    "foot  foot";
}
#presetEditor > #presetBack { grid-area: back; justify-self: start; margin-bottom: 6px; }
#presetEditor > .ref-head { grid-area: head; }
#presetEditor > .pe-tools { grid-area: tools; }
#presetEditor > .pe-pane { grid-area: pane; min-width: 0; }
#presetEditor > .prompt-preview { grid-area: prompt; }
#presetEditor > .pe-foot { grid-area: foot; }
.prompt-config, .prompt-manual, .prompt-preview { background: transparent; border: 0; box-shadow: none; margin: 0; }

/* -- toolbar: mode tabs + save state -- */
.pe-tools {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  flex-wrap: wrap; margin: 4px 0 18px;
}
.pe-tabs { display: flex; gap: 4px; padding: 4px; border-radius: var(--r-md); background: var(--surface-2); }
.pe-tab {
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 8px 16px; border: none; border-radius: var(--r-sm);
  background: none; color: var(--text-muted); font: inherit; font-size: .88rem; font-weight: 600;
  transition: background .16s ease, color .16s ease;
}
.pe-tab .ico { width: 16px; height: 16px; }
.pe-tab:hover { color: var(--text); }
.pe-tab.on { background: var(--surface); color: var(--text); box-shadow: var(--shadow-card); }
.pe-tools-right { display: flex; align-items: center; gap: 10px; }
.pe-dirty { display: flex; align-items: center; gap: 7px; font-size: .82rem; color: var(--warn); }
.pe-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.pe-dot.warn { color: var(--warn); }

/* -- panes -- */
.pe-pane-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.pe-pane-sub { margin: 0 0 16px; }
.prompt-config h2, .prompt-manual h2, .prompt-preview h2 { font-size: 1.05rem; margin: 0 0 4px; }
.prompt-manual .pe-manual-body textarea { min-height: 260px; resize: vertical; }

/* -- live preview -- */
.prompt-preview {
  position: sticky; top: 64px; align-self: start;
  max-height: calc(100vh - 96px); display: flex; flex-direction: column;
  padding: 0 0 0 28px; border-left: 1px solid var(--border);
}
.pe-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.pe-live { display: flex; align-items: center; gap: 7px; font-size: .76rem; color: var(--ok); }
.pe-scroll { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding-right: 4px; }
.pe-rows { display: grid; gap: 6px; }
.pe-row {
  display: grid; grid-template-columns: 116px minmax(0,1fr); gap: 12px; cursor: pointer;
  padding: 10px 12px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--surface); transition: border-color .16s ease, background .16s ease;
}
.pe-row:hover { border-color: var(--border-strong); }
.pe-row-key {
  font-family: var(--font-mono); font-size: .66rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-faint); padding-top: 2px;
}
.pe-row-val { font-size: .86rem; color: var(--text); line-height: 1.45; }
.pe-row.on { border-color: var(--accent); background: var(--accent-weak); }
.pe-row.on .pe-row-key { color: var(--accent); }

.pe-full { margin-top: 16px; }
.pe-full-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px;
  font-family: var(--font-mono); font-size: .66rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-faint);
}
.pe-tag {
  font-size: .62rem; padding: 2px 7px; border-radius: var(--r-pill);
  background: var(--warn-weak); border: 1px solid var(--warn); color: var(--warn); letter-spacing: .02em;
}
.pe-full-body {
  padding: 14px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); font-family: var(--font-mono); font-size: .78rem;
  line-height: 1.7; white-space: pre-wrap; word-break: break-word; color: var(--text-muted);
}
.pe-seg { cursor: pointer; border-radius: 3px; transition: background .16s ease, color .16s ease; }
.pe-seg:hover { background: var(--surface); color: var(--text); }
.pe-seg.fixed { cursor: default; color: var(--text-faint); }   /* house boilerplate — no field */
.pe-seg.fixed:hover { background: none; color: var(--text-faint); }
.pe-seg.on { background: var(--accent-weak); color: var(--text); box-shadow: 0 0 0 1px var(--accent-border); }
.pe-empty { margin: 10px 0; }

/* The config field a highlight points at */
/* -- version history: right-hand drawer, closed by default (mirrors .guide-dock) -- */
.pe-history {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 150;
  width: min(92vw, 400px); display: flex; flex-direction: column;
  background: var(--card); border-left: 1px solid var(--border-hi);
  box-shadow: -12px 0 40px rgba(0,0,0,.5);
  transform: translateX(100%); transition: transform .28s ease; will-change: transform;
}
.pe-history.open { transform: translateX(0); }
.pe-history-head {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.pe-history-head h2 { display: flex; align-items: center; gap: 8px; font-size: 1rem; margin: 0; }
.pe-hico { width: 16px; height: 16px; color: var(--text-muted); flex: none; }
.pe-drawer-x {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: none; color: var(--text-muted); transition: color .16s ease, border-color .16s ease;
}
.pe-drawer-x svg { width: 15px; height: 15px; }
.pe-drawer-x:hover { color: var(--text); border-color: var(--border-hi); }
.pe-vlist { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding: 12px 16px 16px; }

/* Count badge on the toolbar trigger */
.pe-vcount {
  font-family: var(--font-mono); font-size: .68rem; line-height: 1;
  padding: 3px 7px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
}
#peHistoryBtn { display: inline-flex; align-items: center; gap: 7px; }

/* Click-off layer behind the drawer */
.pe-scrim {
  position: fixed; inset: 0; z-index: 149; background: rgba(0,0,0,.5);
  opacity: 0; transition: opacity .28s ease;
}
.pe-scrim.open { opacity: 1; }
.pe-vgroup {
  font-family: var(--font-mono); font-size: .64rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-faint); margin: 12px 0 6px;
}
.pe-vgroup:first-child { margin-top: 0; }
.pe-ver {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border: 1px solid transparent; border-radius: var(--r-sm);
}
.pe-ver:hover { background: var(--surface-2); }
.pe-ver.current { border-color: var(--border-strong); background: var(--surface-2); }
.pe-ver.current.unsaved { border-color: var(--warn); }
.pe-ver.current.unsaved .pe-ver-top b { color: var(--warn); }
.pe-ver-main { flex: 1; min-width: 0; }
.pe-ver-top { font-size: .84rem; display: flex; align-items: baseline; gap: 6px; }
.pe-ver-time { font-family: var(--font-mono); font-size: .74rem; color: var(--text-muted); }
.pe-ver-sub { font-size: .74rem; color: var(--text-faint); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pe-ver-btn {
  flex: none; cursor: pointer; padding: 4px 9px; font: inherit; font-size: .76rem;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: none; color: var(--text-muted); opacity: 0; transition: opacity .16s ease;
}
/* The whole action group reveals together — three controls fading in one at a time reads as
   the row twitching. */
.pe-ver-acts { display: flex; align-items: center; gap: 4px; flex: none;
  opacity: 0; transition: opacity .16s ease; }
.pe-ver:hover .pe-ver-acts, .pe-ver:focus-within .pe-ver-acts { opacity: 1; }
.pe-ver-btn { opacity: 1; }          /* the group owns the reveal now */
.pe-ver-btn:hover { border-color: var(--accent); color: var(--accent); }
.pe-ver-ico {
  display: grid; place-items: center; width: 26px; height: 26px; padding: 0;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: none; color: var(--text-muted); cursor: pointer;
}
.pe-ver-ico svg { width: 14px; height: 14px; }
.pe-ver-ico:hover { border-color: var(--accent); color: var(--accent); }

/* -- footer actions -- */
/* Sticks to the bottom of the viewport: the editor is taller than the screen, so Save used
   to sit below the fold and needed a scroll to the very end to reach. */
.pe-foot {
  position: sticky; bottom: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  margin-top: 22px; padding: 14px 0; border-top: 1px solid var(--border);
  background: var(--bg);
}
.pe-foot-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* Enhance button lights up + relabels when a polished prompt has pending setting changes */
.btn-ghost.apply { border-color: var(--cyan); color: var(--cyan);
  box-shadow: 0 0 0 1px var(--cyan) inset, 0 0 14px rgba(0,229,255,.22); }

/* Stack the two editor columns once they'd get too narrow to read. */
@media (max-width: 1024px) {
  #presetEditor:not(.hidden) {
    grid-template-columns: 1fr;
    grid-template-areas: "back" "head" "tools" "pane" "prompt" "history" "foot";
  }
  .prompt-preview { padding: 22px 0 0; border-left: 0; border-top: 1px solid var(--border);
    position: static; max-height: none; }
}
.help-q { position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: 5px; border-radius: 50%; border: 1px solid var(--border-hi);
  color: var(--muted); font-size: 0.7rem; font-weight: 700; cursor: help; vertical-align: middle; outline: none; }
.help-q:hover { color: var(--text); border-color: var(--cyan-dim); }
.help-q::after {
  content: attr(data-tip);
  position: absolute; bottom: 150%; right: -4px; width: 230px; padding: 9px 11px;
  border-radius: 8px; background: var(--card-2); border: 1px solid var(--border-hi);
  color: var(--text); font-size: 0.78rem; font-weight: 400; line-height: 1.4; white-space: normal;
  text-align: left; box-shadow: 0 6px 20px rgba(0,0,0,.5);
  opacity: 0; pointer-events: none; transform: translateY(4px); transition: opacity .15s, transform .15s; z-index: 1000;
}
/* hover-only (no click/focus latch — that left the bubble stuck open) */
.help-q:hover::after { opacity: 1; transform: translateY(0); }
/* on the Home control card, drop the bubble BELOW the icon so it doesn't collide with the title */
.setup-label .help-q::after { top: calc(100% + 8px); bottom: auto; transform: translateY(-4px); }
.setup-label .help-q:hover::after { transform: translateY(0); }
/* In the Prompts builder, pop the tooltip to the RIGHT of the icon (not above/left) */
.prompt-config .help-q::after, .prompt-preview .help-q::after {
  bottom: auto; top: 50%; right: auto; left: calc(100% + 8px); transform: translate(-4px, -50%); }
.prompt-config .help-q:hover::after, .prompt-preview .help-q:hover::after { transform: translate(0, -50%); }
.brain-field { display: block; margin-top: 22px; }
/* Labels read as labels — small, uppercase, muted — so they don't compete with the input value */
.brain-field .brain-label { display: block; font-weight: 600; font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); margin-bottom: 8px; }
/* keep the inline hint/(i) inside a label in normal case, not shouty uppercase */
.brain-field .brain-label .muted, .brain-field .brain-label .help-q { text-transform: none; letter-spacing: normal; }
.brain-field textarea { margin-top: 6px; font-family: ui-monospace, monospace; font-size: 0.82rem; }
.select.narrow { width: auto; }
/* Your idea: paragraph ⇄ list (guided) mode toggle */
.pf-mode-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.pf-mode-toggle { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--border); border-radius: 9px; background: var(--card); }
.pf-mode-btn { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 28px;
  border: none; background: transparent; color: var(--muted); border-radius: 7px; cursor: pointer; transition: background .15s, color .15s; }
.pf-mode-btn svg { width: 17px; height: 17px; }
.pf-mode-btn:hover { color: var(--text); }
.pf-mode-btn.on { background: var(--card-2); color: var(--cyan); }
#pfIdea { min-height: 84px; resize: vertical; line-height: 1.5; }
.dir-hint { font-size: .72rem; font-weight: 400; text-transform: none; color: var(--muted); margin-left: 4px; }
.dir-hint .link-inline { font-size: .72rem; }
#npMsg { color: #ff6b6b; text-align: center; }
/* styled confirm (replaces native confirm) — compact card, no close × */
.modal-card:has(.confirm-box) { max-width: 400px; }
.modal-card:has(.confirm-box) .modal-close { display: none; }
.confirm-box { padding: 24px 24px 20px; }
.confirm-msg { font-size: .95rem; line-height: 1.55; margin: 0 0 22px; color: var(--text); }
.confirm-title { margin: 0 0 12px; font-size: 1.05rem; font-weight: 650; color: var(--text); }
.confirm-msg p { margin: 0 0 10px; }
.confirm-msg p:last-child { margin-bottom: 0; }
.confirm-msg .cyan { color: var(--cyan); }
.confirm-note { margin-top: 14px !important; color: var(--muted); font-size: .88rem; }
.confirm-acts { display: flex; justify-content: flex-end; gap: 10px; }
.confirm-acts .btn-ghost, .confirm-acts .btn-neon { padding: 9px 18px; }
.btn-neon.danger { background: #ff5670; box-shadow: 0 0 14px rgba(255,86,112,.4); }
.btn-neon.danger:hover { background: #ff4060; }
/* global data-loading indicator: a thin bar along the very top (not a floating header spinner) */
.load-spin { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 300; pointer-events: none; overflow: hidden; }
.load-spin::before { content: ""; position: absolute; top: 0; height: 100%; width: 35%; border-radius: 3px;
  background: linear-gradient(90deg, transparent, var(--cyan, #00e5ff), transparent);
  animation: loadBar 1.05s ease-in-out infinite; }
@keyframes loadBar { 0% { left: -35%; } 100% { left: 100%; } }
/* consistent custom chevron on real <select>s (native one looks off on the dark theme) */
select.select {
  -webkit-appearance: none; appearance: none;
  padding-right: 34px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238b94a8' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
select.select:focus { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2300e5ff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>"); }
textarea:focus, .select:focus, input:focus { outline: none; border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }

.btn-neon {
  background: var(--accent); color: var(--on-accent); font-weight: 700;
  border: none; border-radius: 12px; padding: 12px 20px; cursor: pointer;
  font-size: 0.95rem; box-shadow: var(--shadow-accent); transition: box-shadow .15s, transform .1s, filter .15s;
}
.btn-neon:hover { filter: brightness(1.06); box-shadow: var(--shadow-accent); }
.btn-neon:active { transform: translateY(1px); }
.btn-neon:disabled { opacity: .4; cursor: not-allowed; box-shadow: none; }
.btn-ghost:disabled { opacity: .4; cursor: not-allowed; box-shadow: none; }

/* ---- References view (left: clips · right: video preview + tabbed reference grid) ---- */
/* Three columns: clip list · the clip · its references. */
/* One row height for all three columns. `align-items: start` let each shrink to its own
   content, so a clip with two reference images left the right panel half the height of the list
   beside it and the page looked broken rather than sparse. The height lives here so the columns
   cannot disagree about it. */
/* The references page is a three-column workspace, not a document: it should fit the viewport
   exactly. It used to set `height: calc(100vh - 190px)` — a guess — on top of .main's own 72px
   top and 80px bottom padding, so the page came out taller than a screen. It scrolled, which
   pulled the "References for" heading up under the sticky top bar and left a screenful of dead
   space below the columns. The height is computed now instead of guessed: the view is exactly
   the room .main leaves it, and the columns take whatever the header does not. */
.view-references.active { display: flex; flex-direction: column; height: calc(100vh - 96px); }
.ref-split {
  display: grid; grid-template-columns: 186px minmax(0, 1fr) 390px;
  gap: 24px; margin-top: 18px; align-items: stretch;
  flex: 1 1 auto; min-height: 420px;
}
.ref-split > * { min-height: 0; }        /* let the children scroll instead of stretching the row */
/* Two columns and three children — the references panel wraps to a second row, so the fixed
   row height has to go or BOTH rows try to be a full screen tall. */
@media (max-width: 1200px) {
  .ref-split { grid-template-columns: 186px minmax(0, 1fr); height: auto; }
  .ref-list-col, .ref-detail { height: calc(100vh - 190px); }
  .ref-refs { height: auto; max-height: 60vh; grid-column: 1 / -1; }
}
/* PICTURES, IN A GRID. Each row used to be a 50px sliver of the clip beside four lines of
   text — workspace, caption, model, date — and the column's one job is "which clip do I
   want", which the first frame answers before any of that is read. The facts did not go
   anywhere: the workspace is the tile's own hue along its top, the length sits in the corner,
   and the whole card's title attribute carries the rest for a hover. */
.ref-list { display: grid; grid-template-columns: minmax(0, 1fr); grid-auto-rows: max-content;
  gap: 10px; max-height: calc(100vh - 220px); overflow-y: auto; padding-right: 4px;
  align-content: start; }
.ref-item { display: block; padding: 0; overflow: hidden; border: 1px solid var(--border);
  border-radius: 12px; background: #05070c; cursor: pointer; transition: border-color .15s, transform .12s; }
.ref-item:hover { border-color: var(--muted); transform: translateY(-1px); }
.ref-item.on { border-color: var(--cyan); box-shadow: 0 0 0 1px var(--cyan) inset; }
.ref-thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  background: #000; display: block; }
.ref-meta { min-width: 0; }
/* The workspace name, not the word "CLIP" — in the All-workspaces view every card said the
   same thing, so the one label with room to identify the clip was spending itself on nothing.
   Coloured by the same per-workspace hue as the Home tiles, so a workspace is recognisable
   before the name is even read. */
.ref-shot { display: flex; align-items: center; gap: 6px; font-size: 0.7rem; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; margin-bottom: 3px;
  color: hsl(var(--ws-hue, 190) 90% 74%); }
.ref-ws-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The workspace that produced a clip, in the Library card footer (already a flex row). */
.lib-ws {
  max-width: 100%; padding: 3px 9px; border-radius: var(--r-pill);
  /* Two layers: an opaque near-black base so the text survives a bright thumbnail, then the
     workspace tint over it. A translucent tint alone was unreadable on a sunlit interior. */
  background: linear-gradient(hsl(var(--ws-hue, 190) 70% 60% / .22),
                              hsl(var(--ws-hue, 190) 70% 60% / .22)), rgba(7, 8, 13, .82);
  border: 1px solid hsl(var(--ws-hue, 190) 70% 60% / .45);
  color: hsl(var(--ws-hue, 190) 92% 82%);
  font-size: .66rem; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ref-part { flex: none; padding: 1px 7px; border-radius: var(--r-pill);
  background: rgba(255,255,255,.06); border: 1px solid var(--border);
  color: var(--muted); font-size: .62rem; font-weight: 700; }
.ref-cap { font-size: 0.82rem; color: var(--text); line-height: 1.3; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }

/* The middle column scrolls too — a long prompt or a tall reference sheet must not push the
   row past the other two. */
.ref-detail { display: flex; flex-direction: column; gap: 16px; height: 100%; overflow-y: auto; }
/* -- references page header + clip list -- */
.ref-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
/* One right-hand group, so the actions stay pinned to the edge whether or not the DEV_MODE
   mask toggle beside them is rendered. */
.ref-head-right { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.ref-head .lib-title { margin: 0; }
.ref-sub { margin: 6px 0 18px; }
.view-references > .btn-back { margin-bottom: 10px; }
/* Both side panels are capped to the same height and scroll internally, so neither can run
   off the bottom of the page and they stay level with each other.
   The subtraction is only the page chrome above them — 280px was cutting the clip list to two
   and a half rows on a laptop while the video beside it ran a hundred pixels further down. */
.ref-list-col, .ref-refs { height: 100%; }
.ref-list-col {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--card); overflow: hidden;
}
/* The list scrolls inside the panel, so the panel's header stays put. */
.ref-list-col .ref-list { flex: 1 1 auto; min-height: 0; max-height: none; padding: 10px; }
/* Pinned to the bottom of the panel rather than scrolling with the clips — a pager you have to
   scroll to the end of the list to find is a pager you will not use. */
.ref-list-col .pager { flex: 0 0 auto; margin: 0; padding: 8px 10px;
  border-top: 1px solid var(--border); background: var(--card); }
.ref-list-head {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 13px 14px; border: 0; border-bottom: 1px solid var(--border);
  background: none; color: var(--text); text-align: left; cursor: default;
  font-family: inherit; font-size: .86rem; font-weight: 600;
}
.ref-count {
  font-family: var(--font-mono); font-size: .7rem; padding: 2px 7px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--muted);
}
/* PERCENTAGE PADDING, NOT aspect-ratio. Measured in a headless Chrome against this very
   stylesheet: with `aspect-ratio: 3/4` the wrap came out 182x243 inside a tile that was
   184x166 — the tile's own height did not see its child, because an aspect-ratio box whose
   width comes from its parent contributes nothing to that parent's content height, and the
   grid row then sized the tile without it. The result was a 3px hue bar over a 40px sliver of
   video. `padding-top: 133.33%` resolves against the parent's width, which IS definite, so
   the tile is 4:3 tall before anything inside it loads. */
.ref-thumb-wrap { position: relative; display: block; padding-top: 133.33%; }
/* The workspace, as a colour rather than a line of text. */
.ref-thumb-wrap::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; z-index: 1;
  background: hsl(var(--ws-hue, 190) 90% 62%); }
.ref-item .ref-nrefs { position: absolute; top: 8px; right: 6px; }
.ref-item .ref-part { position: absolute; right: 6px; bottom: 6px; background: rgba(0,0,0,.72); }
.ref-dur {
  position: absolute; left: 4px; bottom: 4px;
  padding: 1px 5px; border-radius: 5px; background: rgba(0,0,0,.72);
  font-family: var(--font-mono); font-size: .6rem; color: #fff;
}
.ref-nrefs {
  flex: none; padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--accent-weak); border: 1px solid var(--accent-border);
  color: var(--accent); font-size: .62rem; font-weight: 700;
}
.ref-sub-line { margin-top: 4px; font-size: .72rem; color: var(--faint); }

/* -- clip detail -- */
.ref-clip-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 12px;
}
.ref-clip-title { font-size: .95rem; font-weight: 700; }
/* The detail title IS the workspace, and clicking it filters the list to that workspace —
   the fastest way to say "show me the rest of this one" from the All-workspaces view. */
.ref-ws-pill {
  padding: 0; border: 0; background: none; cursor: pointer; font: inherit;
  color: hsl(var(--ws-hue, 190) 90% 74%);
  border-bottom: 1px dashed hsl(var(--ws-hue, 190) 70% 60% / .45);
}
.ref-ws-pill:hover { border-bottom-style: solid; }
.ref-clip-model {
  flex: none; padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: .72rem; color: var(--muted);
}
/* -- right column: one section per category, 2 images then "Show all" -- */
.ref-refs {
  display: flex; flex-direction: column; gap: 16px; min-width: 0; overflow-y: auto;
  padding: 16px; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--card);
}
/* Two questions, two tabs: "what did the run draw" and "what did I upload". Stacked, the
   uploads sat under eight storyboard frames and their prompts — off-screen on every product
   film, which is exactly when someone wants to compare a frame against the pack. */
.ref-tabs { position: sticky; top: -16px; z-index: 3; display: flex; gap: 4px; flex: 0 0 auto;
  margin: -16px -16px 0; padding: 12px 16px 10px; background: var(--card); }
.ref-tab { flex: 1 1 0; display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 10px; border: 1px solid transparent; border-radius: 10px; background: none;
  color: var(--muted); font: inherit; font-size: .78rem; font-weight: 650; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s; }
.ref-tab:hover { color: var(--text); }
.ref-tab.on { background: var(--surface-2); border-color: var(--border); color: var(--text); }
.ref-pane { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
/* Beats the global .hidden, which is the same specificity and defined earlier. */
.ref-pane.hidden { display: none; }
.ref-pane .gen-sec { margin-top: 0; }
/* Category headers stay visible while their images scroll past. */
/* Sticky so a category header stays visible while its images scroll past. top:-16px
   cancels the panel's own padding, and the negative margins keep the original spacing. */
.ref-sec-top {
  position: sticky; top: -16px; z-index: 1; background: var(--card);
  display: flex; align-items: center; gap: 8px;
  padding: 6px 0; margin: -6px 0 8px;
}
.ref-sec-name { font-size: .86rem; font-weight: 600; }
.ref-sec-n {
  font-family: var(--font-mono); font-size: .68rem; padding: 2px 7px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--muted);
}
.ref-refs .ref-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
/* Clips the corner ribbon to the thumbnail's rounded corner — without this the ribbon's
   square edge juts past the image. Radius matches .ref-img below. */
.ref-cell { position: relative; min-width: 0; overflow: hidden; border-radius: 10px; }
.ref-refs .ref-img { width: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: 10px; cursor: zoom-in; display: block; }
.ref-cell.ai .ref-img { border: 1px solid var(--warn); }
/* Corner marker: two facts can be true of one image — the AI drew it, and THIS clip used it.
   They stack instead of fighting for the corner: a gold AI triangle at the very tip, with a
   blue "used" band outside it. Either can appear alone, in which case it takes the whole
   triangle. */
.ref-mark {
  position: absolute; top: 0; right: 0;
  /* A single state says one thing and doesn't need the room — at 66px a solid "USED" triangle
     ate a quarter of the thumbnail. Only the stacked state earns the bigger corner, because it
     has to fit a band around a tip. */
  width: 46px; height: 46px;
  pointer-events: none;                          /* labels, not targets */
}
.ref-mark.used.ai { width: 66px; height: 66px; }
.ref-mark i {
  position: absolute; inset: 0;
  display: block; font-style: normal;
}
.ref-mark i b {
  position: absolute;
  transform: translate(-50%, -50%) rotate(45deg);
  font-weight: 800; letter-spacing: .06em; line-height: 1; white-space: nowrap;
}
/* --- single state: the whole corner --- */
.ref-mark .rm-ai   { background: linear-gradient(135deg, var(--warn), #ffd089); }
.ref-mark .rm-used { background: linear-gradient(135deg, var(--accent), #8aa2ff); }
.ref-mark i { clip-path: polygon(0 0, 100% 0, 100% 100%); }
.ref-mark .rm-ai b   { color: #0a0c12; font-size: .5rem; top: 33%; left: 66%; }
.ref-mark .rm-used b { color: #fff;    font-size: .5rem; top: 33%; left: 66%; }

/* --- both: the AI triangle keeps the tip, "used" becomes the band around it --- */
.ref-mark.used.ai .rm-ai   { clip-path: polygon(50% 0, 100% 0, 100% 50%); }
.ref-mark.used.ai .rm-used { clip-path: polygon(0 0, 50% 0, 100% 50%, 100% 100%); }
.ref-mark.used.ai .rm-ai b   { font-size: .5rem;  top: 17%; left: 83%; }
/* the trapezium's area-weighted centroid — big triangle minus the AI tip works out at
   (61%, 39%); centring on the box instead would push the word half outside the ink */
.ref-mark.used.ai .rm-used b { font-size: .52rem; top: 39%; left: 61%; }

/* The used image is the answer to "which one did this clip pick" — the outline says it from
   across the panel, before any label is read. */
/* used = blue outline on the OUTSIDE, ai = gold border on the inside. Same nesting as the
   corner marker (ai at the tip, used wrapping it), so the two encodings agree. Both can show
   on one image, which is the point. */
.ref-cell.is-used { outline: 2px solid var(--accent); outline-offset: -2px; }
.ref-cell:not(.is-used) { opacity: .62; }        /* present, but not what this clip used */
.ref-cell:not(.is-used):hover { opacity: 1; }

.ref-used-tag {
  margin-left: auto; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--accent-weak); border: 1px solid var(--accent-border); color: var(--accent);
  font-size: .62rem; font-weight: 700;
}
/* -- the i2v first-frame stage, above the categories it collapses -- */
.ref-chain { padding-bottom: 14px; border-bottom: 1px solid var(--border); }
.ref-chain-tag {
  margin-left: auto; padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--muted);
  font-size: .62rem; font-weight: 700;
}
/* The sheet is a tall multi-row composite and the frame is a normal still, so this row does
   NOT use .ref-grid's fixed 3-up cells — each keeps its own shape and the arrow sits between. */
.ref-chain-flow { display: flex; align-items: center; gap: 10px; }
.ref-chain-step { flex: 1 1 0; min-width: 0; margin: 0; }
/* Overrides .ref-refs .ref-img's 3/4 crop: cropping the sheet cuts off its bottom rows, which
   are exactly the categories the user is here to check. */
.ref-chain-step .ref-img { aspect-ratio: auto; max-height: 220px; object-fit: contain; background: var(--surface-2); }
.ref-chain-step figcaption { margin-top: 5px; font-size: .68rem; color: var(--muted); text-align: center; }
.ref-chain-arrow { flex: 0 0 auto; color: var(--muted); font-size: 1.1rem; }
.ref-chain-note { margin: 10px 0 0; line-height: 1.45; }

.ref-refs .ref-empty { text-align: center; padding: 20px 4px; }

/* A DEFINITE HEIGHT, AND flex: 0 0 auto. This sat in a column (.ref-detail, a fixed-height
   flex container) beside "What the run drew" with `flex: 1 1 auto; min-height: 0` — which
   means "take what is left, and give up everything if the column runs short". That was fine
   while the storyboard section was two sheet thumbnails. The day product films started
   drawing every frame on its own canvas it became one figure per shot, eight of them with
   their prompts, and the deficit is absorbed by the only item allowed to shrink to nothing:
   the clip itself collapsed to zero height and the page showed a gap where the film had been.
   The film is what this page is for. It keeps its height and the storyboard scrolls. */
.ref-preview { background: none; border-radius: 14px; flex: 0 0 auto; max-width: 100%;
  display: flex; justify-content: center; }
/* THE VIDEO SIZES ITSELF. It used to fill a fixed black box, which pillarboxed every clip
   that was not the box's shape — black down both sides of a 4:3 film, black above and below a
   9:16 one — and read as if the letterboxing were baked into the file. (It is not: cropdetect
   on both test reels comes back 960x720 and 854x480, full frame.) No box, no background: the
   element is the picture, and the picture is whatever shape the clip is. */
.ref-preview video { display: block; width: auto; height: auto;
  max-width: 100%; max-height: min(66vh, 680px); border-radius: 14px; }
/* (the per-category tabs were replaced by the stacked sections in .ref-refs) */
.ref-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; }
.ref-img { width: 100%; aspect-ratio: 9 / 16; object-fit: cover; border-radius: 12px; border: 1px solid var(--border);
  cursor: zoom-in; background: #000; transition: border-color .15s, transform .12s; }
.ref-img:hover { border-color: var(--cyan); transform: translateY(-2px); }
.ref-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  text-align: center; padding: 48px 20px; border: 1px dashed var(--border); border-radius: 14px; }
/* A line-art frame of text, matching the rest of the UI's stroke icons. The emoji here rendered
   at whatever the OS felt like — on this machine a lime-green puzzle piece that read as a
   broken plugin badge rather than as an empty state. */
.ref-empty-ico { width: 30px; height: 30px; color: var(--faint); opacity: .8; }
.ref-raw {
  position: absolute; left: 6px; bottom: 6px; z-index: 2;
  padding: 2px 7px; border-radius: var(--r-pill);
  background: rgba(7,8,13,.85); border: 1px solid var(--err); color: var(--err);
  font-size: .58rem; font-weight: 800; letter-spacing: .06em;
}
@media (max-width: 760px) {
  .ref-split { grid-template-columns: 1fr; height: auto; }
  .ref-list { max-height: none; }
  .ref-list-col, .ref-refs, .ref-detail { height: auto; max-height: 70vh; }
}

/* ---- heading dropdown ("Library for [workspace ▾]") — smaller pill, themed ---- */
.lib-title { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.head-dd { position: relative; display: inline-block; }
.head-dd-btn { font-family: inherit; font-size: 1.05rem; font-weight: 600; color: var(--cyan);
  background: var(--card); border: 1px solid var(--border-hi); border-radius: 999px; cursor: pointer;
  padding: 6px 14px; display: inline-flex; align-items: center; gap: 8px; max-width: 50vw;
  transition: border-color .15s; }
.head-dd-btn:hover { border-color: var(--cyan); }
.head-dd-btn > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.head-dd-caret { font-size: 0.7rem; opacity: .8; }
.head-dd-menu { top: calc(100% + 8px); left: 0; }   /* uses .ws-drop styling for the panel */

.btn-ghost {
  background: transparent; color: var(--muted);
  border: 1px solid var(--border-hi); border-radius: 12px;
  padding: 11px 18px; cursor: pointer; font-size: 0.9rem;
  transition: all .15s;
}
.btn-ghost:hover { color: var(--text); border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }
.btn-ghost.danger { border-color: rgba(255,93,108,.4); color: var(--err); }
.btn-ghost.danger:hover { box-shadow: 0 0 16px rgba(255,93,108,.3); }

.btn-stop {
  background: rgba(255,43,214,.08); color: var(--magenta);
  border: 1px solid var(--magenta-dim); border-radius: 12px;
  padding: 12px 22px; cursor: pointer; font-weight: 700; font-size: 0.95rem;
  transition: box-shadow .15s;
}
.btn-stop:hover { box-shadow: var(--glow-magenta); }
.btn-stop.is-busy {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  opacity: .8; cursor: default;
}
.btn-stop.is-busy .spinner { border-color: rgba(255,43,214,.35); border-top-color: var(--magenta); }

.link-ghost {
  background: none; border: none; color: var(--cyan); cursor: pointer;
  font-size: 0.85rem; padding: 4px; opacity: .85;
}
.link-ghost:hover { opacity: 1; text-shadow: 0 0 8px rgba(0,229,255,.5); }

/* NOTE: there used to be a bare `.warn { …box… }` utility here — background, border,
   padding and a 10px top margin. Nothing in the SPA used it as a box (guide.html is
   standalone and defines its own), but every element using `warn` as a state MODIFIER
   silently inherited it: .lib-tab.warn sat 10px lower than its siblings, and
   .acct-status.warn got a second layer of padding. Colour-only modifiers live on their
   own components. Don't reintroduce a single-word utility with box styling. */
.section-h { color: var(--muted); margin: 26px 0 12px; font-weight: 600; }

/* chips */
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.chip {
  padding: 7px 14px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border-hi); background: var(--card-2);
  color: var(--muted); font-size: 0.85rem; transition: all .15s;
}
.chip:hover { color: var(--text); }
.chip-hint { color: var(--muted); font-size: 0.82rem; font-style: italic; padding: 8px 2px; display: inline-block; }
.chip.on { color: #07080d; background: var(--grad); border-color: transparent; box-shadow: var(--glow-cyan); }
.chip .chip-x { margin-left: 5px; opacity: .7; font-size: .8em; cursor: pointer; }
.chip .chip-x:hover { opacity: 1; }

/* switch row */
.switch-row { display: flex; align-items: center; gap: 10px; color: var(--text); font-size: 0.92rem; margin-top: 14px; cursor: pointer; }
.switch-row input { width: auto; accent-color: var(--cyan); }

/* ============================== ASK ============================== */
.view-ask.active { display: flex; }
/* Full-bleed (see wide-main in router.js). The action bar is position:fixed, so the view no longer
   needs a viewport-tall min-height to floor it — that only forced the page past one screen. Content
   flows from the top and the fixed bar always rides the viewport bottom. */
.view-ask { align-items: flex-start; justify-content: center; }
.ask-wrap { position: relative; width: 100%; text-align: left; display: flex; flex-direction: column; }

/* ---- Step 0: workspace picker. .picking shows it and hides the Setup flow ---- */
.ws-picker { display: none; position: relative; z-index: 1; }
.view-ask.picking .ws-picker { display: block; }
/* hide the Setup-flow siblings (the picker has its own title/sub inside #wsPicker) */
/* The picker hides the Setup-flow siblings; it has its own title/sub inside #wsPicker. The step
   nav goes too — belt and braces with renderStepNav, which hides the row itself, so a stale bar
   can never be left over the home page by a paint that did not run. */
.view-ask.picking .home-steps-row,
.view-ask.picking > .ask-wrap > .ask-title,
.view-ask.picking > .ask-wrap > .ask-sub,
.view-ask.picking .home-grid,
.view-ask.picking .setup-foot { display: none; }
/* ---- Home hero ---- */

/* ---- Stats strip ---- */
/* scrollIntoView aligns to the viewport, which the 52px fixed header is sitting on top of — so
   the heading it scrolls to lands underneath it. This is the room it needs to clear. */
.ws-head-title, .ws-head { scroll-margin-top: 76px; }

/* ---- "Your workspaces" header ---- */
/* One height for the whole toolbar. Each control reached ~38px by a different route — a fixed
   height here, padding + a child's height there, line-height somewhere else — so they only
   agreed by accident and stopped agreeing the moment any of them changed. */
.ws-head { --ws-tool-h: 40px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 14px; }
.ws-head-title { font-family: var(--font-display); font-size: 1.35rem; font-weight: 700; margin: 0; }
/* The New button lives in the titles group so a phone can put it beside the title. On a desktop
   that group dissolves — `display: contents` drops the wrapper and lets the title, the tools and
   the button lay out as the header's own flex children, which is where they were. */
.ws-head { justify-content: flex-start; }
.ws-head-titles { display: contents; }
.ws-head-title { order: 1; }
.ws-head-tools { order: 2; margin-left: auto; }
.ws-head-new { order: 3; }
/* This row had NO display of its own, so the controls laid out as inline boxes on a text
   baseline — boxes of different heights aligned by baseline is exactly the staggered look. It is
   a flex row now, and `stretch` sets the height ONCE for both: matching numbers on separate
   rules only ever agree by arithmetic, and drift apart the moment one of them changes. */
.ws-head-tools { display: flex; align-items: stretch; gap: 10px; flex-wrap: wrap;
  min-height: var(--ws-tool-h, 40px); }
.ws-search { display: inline-flex; align-items: center; gap: 8px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--card-2, rgba(255,255,255,.03)); color: var(--muted);
  transition: border-color .12s, box-shadow .12s, color .12s; }
/* ONE focus ring, on the wrapper. The global `input:focus` rule adds a border colour AND a glow
   to every input on the page; inside this pill that glow drew a second rectangle around the
   field itself, so the box appeared to be outlined twice. The field gives up both and the
   wrapper carries the state for the pair. */
.ws-search:focus-within { border-color: var(--cyan-dim, var(--cyan)); color: var(--text);
  box-shadow: 0 0 0 3px rgba(0,229,255,.10); }
.ws-search svg { width: 15px; height: 15px; flex: 0 0 auto; }
.ws-search input { width: 190px; border: 0; background: transparent;
  color: var(--text); font: inherit; font-size: .88rem; }
.ws-search input:focus { outline: none; border: 0; box-shadow: none; }
.ws-search input::placeholder { color: var(--faint); }
.ws-search input::-webkit-search-cancel-button { filter: invert(.6); }

/* Running / paused filter — a segmented control, so the current state is always visible
   rather than hidden behind a dropdown. */
.ws-filter { display: inline-flex; align-items: stretch; padding: 3px; gap: 2px;
  border-radius: 10px;
  border: 1px solid var(--border); background: var(--card-2, rgba(255,255,255,.03)); }
.ws-filter-b { padding: 0 12px; height: 100%; border: 0; border-radius: 7px; cursor: pointer;
  background: transparent; color: var(--muted); font: inherit; font-size: .82rem; font-weight: 600;
  transition: color .12s, background .12s; }
.ws-filter-b:hover { color: var(--text); }
.ws-filter-b.is-on { color: var(--text); background: rgba(255,255,255,.08); }

/* Same --ws-tool-h as the search box and the filter group beside it. The header centres its
   children rather than stretching them, so with no height of its own this sat at text height —
   a visibly shorter pill next to a 40px segmented control. The token, not a number: it is the
   one the tools row already reads, so the three cannot drift apart. */
.ws-head-new { display: inline-flex; align-items: center; gap: 7px; padding: 0 16px;
  min-height: var(--ws-tool-h, 40px);
  border: 0; border-radius: 10px; cursor: pointer; font: inherit; font-size: .88rem;
  font-weight: 700; color: #fff; background: linear-gradient(135deg, #6d7cff, #4453e8);
  box-shadow: 0 2px 10px rgba(77,90,232,.22); transition: filter .12s, transform .12s; }
.ws-head-new:hover { filter: brightness(1.08); transform: translateY(-1px); }
.ws-head-new svg { width: 15px; height: 15px; }

/* ONE rectangle. Unfiltered, this element is itself the create button — the reason and the
   action are the same box, so the whole thing lights up on hover and there is a single target
   for a single action. It spans the grid because a message sitting in one column reads as a
   card that failed to load. */
.ws-empty {
  grid-column: 1 / -1; margin: 4px 0 0; color: var(--muted); font-size: .88rem;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 44px 16px; border: 1px dashed var(--border); border-radius: 14px;
  background: none; width: 100%; font-family: inherit; text-align: center;
}
.ws-empty-msg { margin: 0; }
.ws-empty.is-new { cursor: pointer; transition: border-color .15s, background .15s; }
.ws-empty.is-new:hover { border-color: var(--accent); background: var(--accent-weak); }
.ws-empty.is-new:focus-visible { outline: none; border-color: var(--accent); background: var(--accent-weak); }
/* The plus keeps its own emphasis; the labels are plain text inside the one button. */
.ws-empty .wsp-new-plus { margin-bottom: 2px; }
.ws-empty-lbl { font-size: 1rem; font-weight: 700; color: var(--text); }

.ws-picker-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px; margin-top: 8px;
}
.wsp-card {
  display: flex; flex-direction: column; gap: 10px; padding: 16px 18px; cursor: pointer;
  min-height: 150px; text-align: left; font: inherit; color: var(--text);
  background: linear-gradient(180deg, rgba(22,25,39,.66), rgba(17,19,28,.5));
  border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow);
  transition: border-color .15s, transform .12s, box-shadow .15s;
}
.wsp-card:hover { border-color: var(--cyan-dim); transform: translateY(-2px); box-shadow: var(--glow-cyan); }
.wsp-status { display: inline-flex; align-items: center; gap: 7px; align-self: flex-start;
  font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px; }
.wsp-status .orb-dot { width: 7px; height: 7px; border-radius: 50%; }
.wsp-status.running { color: #22c55e; background: rgba(34,197,94,.12); }
.wsp-status.running .orb-dot { background: #22c55e; box-shadow: 0 0 6px rgba(34,197,94,.8); }
.wsp-status.paused { color: var(--muted); background: rgba(255,255,255,.05); }
.wsp-status.paused .orb-dot { background: var(--faint); }
/* A clip rendering right now outranks the on/off switch: a paused workspace can still be
   finishing the clip it started, and that is the more urgent thing to say. */
.wsp-status.generating { color: #5cc8ff; background: rgba(92,200,255,.13); }
.wsp-status.generating .orb-dot { background: #5cc8ff; box-shadow: 0 0 6px rgba(92,200,255,.85);
  animation: wspPulse 1.4s ease-in-out infinite; }
@keyframes wspPulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
.wsp-id { display: flex; align-items: center; gap: 11px; min-width: 0; }
.wsp-avatar { flex: 0 0 auto; display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: 11px; font-family: var(--font-display); font-weight: 800; font-size: 1.05rem;
  color: hsl(var(--wsp-hue, 258) 90% 78%);
  background: hsl(var(--wsp-hue, 258) 70% 60% / .16);
  border: 1px solid hsl(var(--wsp-hue, 258) 70% 60% / .28); }
.wsp-idtext { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.wsp-name { font-family: var(--font-display); font-size: 1.02rem; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wsp-meta { font-size: .76rem; color: var(--muted); }
/* Progress toward the daily cap — the same number as .wsp-meta, read at a glance. */
.wsp-bar { display: block; height: 3px; margin: 2px 0 4px; border-radius: 3px;
  background: rgba(255,255,255,.07); overflow: hidden; }
/* Two different bars wearing one skin was the bug: a workspace that had posted 1 of 5 today
   showed a bright, live-looking sliver and read as "generating right now". Quota is a static
   fact, so it gets a flat, quiet fill; only a clip actually rendering animates. */
.wsp-bar i { display: block; height: 100%; border-radius: 3px;
  background: rgba(255,255,255,.22); }
.wsp-bar.gen { background: rgba(92,200,255,.12); }
/* Determinate: the model has run before, so there is a real estimate to measure against. The
   shimmer above is only for a run whose model has no history yet — an animated stripe says
   "working", a number says how much longer, and guessing a number would be worse than either. */
.wsp-bar.gen.live { position: relative; height: 6px; overflow: visible; }
.wsp-bar.gen.live i {
  background: linear-gradient(90deg, #5cc8ff, #a78bfa); animation: none; transform: none;
  transition: width .9s linear;
}
.wsp-bar-pct {
  position: absolute; right: 0; top: -17px;
  font-size: .68rem; font-weight: 700; color: #5cc8ff; letter-spacing: .02em;
}
.wsp-gen-step {
  display: block; margin-top: 5px; font-size: .7rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wsp-bar.gen i {
  background: linear-gradient(90deg, transparent, #5cc8ff, transparent);
  animation: wspGen 1.5s linear infinite;
}
@keyframes wspGen { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
  .wsp-bar.gen i { animation: none; background: #5cc8ff; }
}
.wsp-targets { display: flex; align-items: center; gap: 6px; margin-top: auto;
  font-size: .74rem; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wsp-targets svg { width: 13px; height: 13px; flex: 0 0 auto; }
@media (max-width: 900px) {
  .ws-head-tools { flex-wrap: wrap; }
  .home-stats { grid-template-columns: repeat(2, 1fr); row-gap: 16px; }
}
@media (max-width: 520px) {
  /* Stays 2×2. One column turns four short facts into a screenful of scrolling, and they are
     read as a set — "16 workspaces, 1 generating" only means something side by side. */
  .home-stats { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .ws-search input { width: 100%; }
}

/* "＋ New workspace" card */
.wsp-avatar.has-shot { position: relative; overflow: hidden; width: 48px; height: 48px; }
.wsp-avatar .wsp-shot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.wsp-dormant { grid-column: 1 / -1; justify-self: center; margin-top: 4px; padding: 9px 16px;
  border: 1px dashed var(--border); border-radius: var(--r-pill); background: transparent;
  color: var(--text-muted); font: inherit; font-size: .84rem; cursor: pointer; }
.wsp-dormant:hover { color: var(--text); border-color: var(--border-hi); }
/* Phone, list cut to a screenful: "View all" is the one way on; this waits until it is used. */
.is-clamped .wsp-dormant { display: none; }
.wsp-card.new { align-items: center; justify-content: center; color: var(--cyan);
  border-style: dashed; background: transparent; gap: 8px; text-align: center; }
.wsp-card.new:hover { background: rgba(0,229,255,.05); }
.wsp-new-plus { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%;
  font-size: 1.5rem; line-height: 1; color: #fff;
  background: linear-gradient(135deg, #6d7cff, #4453e8); }
.wsp-new-lbl { font-size: .92rem; font-weight: 700; color: var(--text); }
.wsp-new-sub { font-size: .76rem; color: var(--faint); }
/* SETUP NO LONGER FITS ONE SCREEN, and pretending it does was what broke it. The page was
   `height: calc(100vh - 270px)` with each column scrolling inside itself — right when it held a
   model picker, a prompt box and an upload panel. It now holds the whole brief, twenty fields,
   and a fixed height meant the content overflowed a box that could not grow: the reference panel
   ended up painted on top of the product fields.
   The page scrolls. Nothing inside it scrolls separately, so there is one scrollbar and one
   reading order, which is also what makes a single column worth having. */
.view-ask .setup-card, .view-ask .ref-panel { min-height: 0; }
/* Each upload row is sized to what it holds — a drop target plus any thumbnails — and the strip
   of rows grows with the style's slots rather than scrolling inside a fixed box. */
.view-ask .ref-panel .anchor-drops { max-height: none; overflow: visible; justify-content: flex-start; }
.view-ask .ref-panel .anchor-drop { flex: 0 0 auto; min-height: 76px; }
.ask-glow {
  position: absolute; inset: -40% 10% auto 10%; height: 320px; z-index: 0;
  background: radial-gradient(closest-side, rgba(0,229,255,.18), transparent 70%),
              radial-gradient(closest-side, rgba(255,43,214,.16), transparent 70%);
  background-position: 30% 0, 70% 30%; background-repeat: no-repeat;
  filter: blur(20px); pointer-events: none;
}
/* header workspace switcher (top-left) */
.ws-switch { position: relative; }
.ws-btn { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: .9rem; font-weight: 600;
  background: var(--card); border: none; color: var(--text); padding: 6px 12px; border-radius: 10px; max-width: 320px; }
.ws-btn:hover { background: var(--card-2); }
.ws-glyph { color: var(--accent); }
.ws-glyph.running { color: var(--ok); }
.ws-glyph.off { color: var(--faint); filter: none; }
.ws-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; }
.ws-drop { position: absolute; top: 44px; left: 0; min-width: 260px; z-index: 60;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow); padding: 6px; max-height: 360px; overflow-y: auto; }
.ws-opt { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; background: transparent; border: none; color: var(--text); padding: 9px 10px; border-radius: 8px; cursor: pointer; font-size: .9rem; }
.ws-opt:hover { background: var(--card-2); }
.ws-opt-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* No selection marker. The row's own highlight says which one is picked, and the square was
   competing with the star for the right edge — two marks in the same place, meaning different
   things. Selected is made distinct from :hover so the highlight can carry it alone. */
.ws-opt.selected {
  background: var(--accent-weak); color: var(--text);
  font-weight: 600;
}
.ws-opt.new { color: var(--cyan); border-top: 1px solid var(--border); margin-top: 4px; }
/* Sits between the name and the selection marker, so it lines up down the list whatever the
   names are — and in the same gold as the star on the workspace cards, so it reads as the
   same mark rather than a second unrelated symbol. */
.ws-opt-star { flex: none; color: #f5c451; font-size: .82rem; line-height: 1; }

/* ---- Every step: controls left, context/preview right. One grid, all four pages. ---- */
.home-grid, .step-grid {
  position: relative; z-index: 1; display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 20px; align-items: stretch; text-align: left; margin: 0;
}
/* text-to-video: no reference panel → the card spans the FULL width (both columns), i.e. the
   same total width as the left+right panels combined for i2v/r2v. */
.home-grid.solo { grid-template-columns: minmax(0, 1fr); }

/* one card, three stacked fields (Model · Preset · Prompt) split by hairlines */
.setup-card {
  display: flex; flex-direction: column; min-width: 0;
  background: linear-gradient(180deg, rgba(22,25,39,.66), rgba(17,19,28,.5));
  border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow);
}
.setup-field { display: flex; flex-direction: column; gap: 8px; padding: 14px 16px; min-width: 0; }
.setup-field + .setup-field { border-top: 1px solid var(--border); }
.setup-label {
  display: inline-flex; align-items: center;
  font-size: .68rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); user-select: none;
}
/* "optional" next to a label. Lowercase and un-tracked against the uppercase label so it reads
   as an aside rather than as part of the field's name — the Prompt box being optional is the
   thing a returning user most needs told, and a second uppercase word just looks like a rename. */
.setup-opt {
  margin-left: 6px; font-size: .62rem; font-weight: 600; letter-spacing: .02em;
  text-transform: lowercase; color: var(--muted); opacity: .75;
}

/* The Preset editor's copy sits under the pane's subtitle, above the scrolling prompt rows. */
.pe-test-row { margin: 2px 0 12px; }

/* The result is a modal because both hosts are fixed-height columns and the answer is taller
   than either can give — an inline panel got clipped at exactly the spoken line, which is the
   part people most want to read. */
.tst-modal { padding: 22px; }
.tst-modal h3 { margin: 0 0 14px; font-size: 1.05rem; }
.tst-body { font-size: .88rem; }
/* Which input won — the panel's headline, because it is the fact the screen could not show. */
.tst-src { display: block; font-size: .72rem; font-weight: 700; letter-spacing: .02em; margin-bottom: 10px; }
.tst-src.ok  { color: var(--ok); }
.tst-src.own { color: var(--warn); }
.tst-rows { display: grid; gap: 12px; margin: 0; }
.tst-row { display: grid; grid-template-columns: 116px 1fr; gap: 12px; align-items: start; }
.tst-row dt {
  font-size: .68rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); padding-top: 2px;
}
.tst-row dd { margin: 0; color: var(--text); line-height: 1.5; overflow-wrap: anywhere; }
.tst-foot { margin: 10px 0 0; font-size: .72rem; color: var(--muted); opacity: .8; }
.tst-wait, .tst-err { font-size: .8rem; color: var(--muted); }
.tst-err { color: var(--err); }
@media (max-width: 560px) { .tst-row { grid-template-columns: 1fr; gap: 2px; } }

/* label with a value pinned to the right of the same row (e.g. "Clip length … 5s") */
.setup-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.setup-field .select { width: 100%; min-width: 0; padding: 10px 34px 10px 12px; }
.setup-card optgroup { font-style: normal; font-weight: 600; color: var(--muted); background: var(--card); }
.setup-card optgroup option { font-weight: 400; color: var(--text); }

.ref-panel {
  display: flex; flex-direction: column; gap: 10px; padding: 14px; min-width: 0;
  background: linear-gradient(180deg, rgba(22,25,39,.66), rgba(17,19,28,.5));
  border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow);
}
.ref-opt { font-size: .72rem; color: var(--faint); flex: none; }
.ref-count { margin-left: auto; font-size: .72rem; font-weight: 600; color: var(--cyan); white-space: nowrap; flex: none; }
.ref-count.full { color: var(--warn); }
.ref-none { font-size: .82rem; color: var(--muted); line-height: 1.5; padding: 18px 4px; text-align: center; }
.ref-hint { margin: 0; font-size: .7rem; color: var(--faint); text-align: center; }

/* ---- Step action bar: pinned to the bottom of the content area on all four steps ----
   Fixed (not sticky) so it never rides up when you scroll to the end of a page. Mirrors
   .topbar's geometry so it spans the content area but never sits under the sidebar. */
.setup-foot, .wizard-nav {
  position: fixed; left: var(--sidebar-w); right: 0; bottom: 0; z-index: 40;
  /* .main's side padding, not 26px of its own: the bar spans exactly the same box as .main, so
     sharing its gutter is what puts the bar's edges on the page's edges. It only showed up once
     a page was wider than the bar's old 1160 rail — below that the max-width hid the difference. */
  padding: 12px 2.5%; background: var(--header-bg); backdrop-filter: blur(10px);
  border-top: 1px solid var(--border); transition: left .2s ease;
}
.app.collapsed .setup-foot, .app.collapsed .wizard-nav { left: var(--sidebar-w-collapsed); }
/* The wizard's cards fill the content area rather than sitting on a centred rail, so its bar
   does too — Back and Next end up over the card's own right edge instead of short of it. */
.view-setup { --rail: none; }
/* THE BAR SITS ON THE CONTENT'S RAIL. One hard-coded 1160 was that rail when every step was
   1160 wide; the pages have since grown apart — Home is 1290 once the style panel is open, and
   the wizard cards run the full width of the content area. On a large screen the bar kept its
   old width and the pages did not, so Next floated ~65px inside the card it belongs to on Home,
   and further still on the wizard, with Estimated pulled the same distance off the left edge.
   Each view declares --rail once; the grid and the bar both read it, so they cannot drift. */
.bar-inner { display: flex; align-items: center; gap: 14px; width: 100%;
  max-width: var(--rail, 1160px); margin: 0 auto; }
/* A COUNT, AND THE CHECKLIST ON HOVER. It was one sentence, permanently in the bar, naming the
   FIRST thing missing — so a workspace missing two was told about one, fixed it, and met the
   same wall again. The count summarises; the hover lists every one; each line is a button that
   goes to the field it is about. Shown only once the action has been pressed. */
/* nowrap and flex:none — the estimate beside it already shrinks and truncates, and of the two
   "1 thing missi…" is the one that stops being an answer when it is cut. */
.bar-blocker { position: relative; flex: none; cursor: pointer; white-space: nowrap;
  font-family: "Space Mono", ui-monospace, monospace; font-size: .76rem; color: var(--danger); }
.bb-n { border-bottom: 1px dashed color-mix(in srgb, var(--danger) 55%, transparent);
  padding-bottom: 1px; }
.bb-pop { position: absolute; right: 0; bottom: calc(100% + 10px); z-index: 70;
  width: max-content; max-width: min(340px, 76vw); padding: 6px; text-align: left;
  /* A style with three questions of its own can put seven lines in here; past that the list
     scrolls rather than running off the top of the window. */
  max-height: min(58vh, 380px); overflow-y: auto;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface);
  box-shadow: 0 16px 40px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .14s, transform .14s, visibility .14s; }
.bar-blocker:hover .bb-pop, .bar-blocker:focus-visible .bb-pop,
.bb-pop:hover { opacity: 1; visibility: visible; transform: translateY(0); }
/* THE ROW IS THE LIST ITEM, not the button. The button rule used to carry the bullet, the
   padding and `display: block` — and once the link shrank to the one word "Posting", the
   sentence around it fell outside the styled box while the word itself became a full-width
   block with a bullet of its own. The <li> owns the layout; the link is a word inside it.

   The popup also resets the type: the bar's mono red is right for "2 things missing" and wrong
   for three sentences under it. */
.bb-pop ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 2px; }
.bb-pop li { position: relative; padding: 7px 10px 7px 22px; border-radius: 8px;
  font-family: var(--font-sans); font-size: 12.5px; line-height: 1.45; color: var(--text);
  white-space: normal; }
.bb-pop li::before { content: "•"; position: absolute; left: 9px; color: var(--danger); }
.bb-pop li:hover { background: var(--surface-2); }
.bb-pop .hint-go { display: inline; width: auto; padding: 0; font-size: inherit;
  font-family: inherit; line-height: inherit; }
.bar-blocker.shake { animation: barShake .38s cubic-bezier(.36,.07,.19,.97); }
@keyframes barShake {
  10%, 90% { transform: translateX(-1px); } 20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); } 40%, 60% { transform: translateX(4px); }
}
@media (prefers-reduced-motion: reduce) { .bar-blocker.shake { animation: none; } }
/* The four of them read as one group with one end to it, which is what "space between Back and
   the rest" is for. */
.wizard-nav .bar-inner > .btn-ghost + .btn-ghost,
.wizard-nav .bar-inner > .btn-ghost + .step-go { margin-left: 2px; }
/* estimate on the left, then the blocker hint, then Back, then Next — Next always last */
/* ONE line, always. This was a column, and every part of it was free to wrap: in a bar also
   holding a hint and three buttons, "ESTIMATED CREDITS" broke across two lines, "6 credits" broke
   between the number and the word, and the breakdown and the per-day total stacked underneath —
   a four-line estimate in a bar built for one, which pushed the row to twice its height.
   Now it is a single baseline row. The headline (label, number, unit, ⓘ) never shrinks and never
   wraps; the two detail strings are the only things allowed to give, and they ellipsize. */
.est-inline { display: flex; align-items: baseline; gap: 9px; min-width: 0; margin-right: auto;
  flex: 0 1 auto; overflow: hidden; }
.est-inline-top { display: flex; align-items: baseline; gap: 7px; flex: none; white-space: nowrap; }
.est-inline-lbl { font-size: .62rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.est-inline-val { font-size: 1.05rem; font-weight: 800; color: var(--cyan); }
.est-inline-val.short { color: var(--warn); }
.est-inline-val.idle { color: var(--faint); }        /* "—" before Format sets length + resolution */
.est-inline-unit { font-size: .66rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
/* The breakdown is the longest string and the least urgent, so it is the one that gives way:
   it shrinks and ellipsizes while the per-day total beside it keeps its full width. */
.est-inline-sub { flex: 0 1 auto; min-width: 0; font-size: .72rem; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A middot rather than a rule. A border-left here would be the height of the .72rem line box it
   sits on, not of the row, so beside the 1.05rem headline it reads as a tick mark that stopped
   short. The dot carries no height of its own and cannot mis-align. It leads the span so that
   the ellipsis eats the tail, never the separator — and it is drawn only when the span has
   something in it, since both are empty on most steps. */
.est-inline-sub:not(:empty)::before,
.est-inline-day:not(.hidden)::before { content: "·"; margin-right: 9px; color: var(--text-faint); opacity: .7; }
.est-inline-sub:empty { display: none; }
/* Narrow: the headline and the buttons are what the bar is FOR, and they are what has to fit.
   The breakdown is in the ⓘ's reach anyway, so it goes rather than squeezing everything else. */
@media (max-width: 720px) {
  .est-inline-sub, .est-inline-day { display: none; }
}
/* the fixed bar floats over the page — reserve space for it, and drop .main's own bottom padding
   on these steps so the two don't stack into an off-screen gap that makes the page scroll */
.view-ask, .view-setup { padding-bottom: 76px; }
.app:has(.view-ask.active) .main, .app:has(.view-setup.active) .main { padding-bottom: 0; }
.home-grid, .step-grid { margin-bottom: 16px; }
/* One line, always. At 12/28 with a .95rem label, "Start the schedule" wrapped to two lines and
   grew the whole bar — a button that changes height when its own text changes is a bar that
   moves under the cursor reaching for it. */
/* A PILL. A 10px radius on a 38px button is a rectangle with the corners taken off; fully
   rounded, the pair reads as one control with two ends — which is what Back and the action are. */
.step-go {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 22px; font-size: .88rem; font-weight: 700; border-radius: 999px;
  white-space: nowrap;
}
/* ---- the step header: where you are, and the way back ---------------------------------------
   Back names its destination, because a labelled exit reads as navigation and an unlabelled one
   reads as a fourth thing to press. */
/* Right-aligned, and clear of the ✕ that sits in the same corner. */
.step-head { display: flex; align-items: baseline; justify-content: flex-end; gap: 12px;
  margin: 0 0 10px; padding-right: 44px; }
.step-back { font-weight: 640; }
.step-where { font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint); }
.step-where i { font-style: normal; opacity: .8; }

/* ---- the finish button, and the two ways of not finishing ----------------------------------
   One filled button ends the flow. The caret opens what you might do INSTEAD of ending it —
   both of which leave the workspace off, which is what makes them one group. */
.split-go { position: relative; display: inline-flex; flex: none; }
.split-main { border-radius: 999px 0 0 999px; }
.split-caret { border-radius: 0 999px 999px 0; padding: 11px 13px 11px 11px;
  border-left: 1px solid rgba(255,255,255,.28); }
.split-caret svg { width: 15px; height: 15px; display: block; }
.split-menu { position: absolute; right: 0; bottom: calc(100% + 8px); z-index: 70;
  width: min(330px, 84vw); padding: 6px; display: grid; gap: 2px;
  border: 1px solid var(--border); border-radius: 14px; background: var(--surface);
  box-shadow: 0 18px 44px rgba(0,0,0,.5); }
.split-item { display: grid; gap: 2px; padding: 10px 12px; border: 0; border-radius: 10px;
  background: transparent; color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.split-item:hover:not(:disabled) { background: var(--surface-2); }
.split-item:disabled { opacity: .45; cursor: not-allowed; }
.si-top { display: flex; align-items: baseline; gap: 10px; }
.si-top b { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 650; }
.si-cost { margin-left: auto; font-family: "Space Mono", ui-monospace, monospace;
  font-size: 10.5px; color: var(--text-faint); }
.si-sub { font-size: 12px; line-height: 1.45; color: var(--text-muted); }

/* LEFT IS FACTS, RIGHT IS ACTIONS. Back was on the left on the reasoning that it points
   backwards — but it left the estimate's three phrases and one button interleaved, so the bar
   read as five fragments rather than two groups. The estimate's margin-right:auto owns the
   slack; everything that can be pressed sits after it, in order of commitment. */
.wizard-nav .btn-ghost, .setup-foot .btn-ghost { white-space: nowrap; }
.step-go-ico { width: 17px; height: 17px; flex: none; }


.ask-title { position: relative; z-index: 1; font-family: var(--font-display); font-size: 1.9rem;
  margin-bottom: 6px; font-weight: 800; letter-spacing: -0.025em; }
.ask-sub { position: relative; z-index: 1; margin: 0 0 20px; font-size: .88rem; color: var(--muted); }
.ask-sub:empty { margin: 0 0 6px; }   /* Format has no subtitle — don't leave its gap behind */
.ask-photo-preview {
  position: relative; z-index: 1; width: 72px; height: 72px; margin: 0 auto 12px;
}
.ask-photo-preview img {
  width: 100%; height: 100%; object-fit: cover; border-radius: 12px;
  border: 1px solid var(--border-hi);
}
.ask-thumb-clear {
  position: absolute; top: -7px; right: -7px; width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 0.7rem;
  background: var(--card-2); border: 1px solid var(--border-hi); color: var(--text);
}
.ask-thumb-clear:hover { background: rgba(255,93,108,.2); border-color: var(--err); color: var(--err); }

.ask-drop-hint { position: relative; z-index: 1; margin: 10px 0 4px; color: var(--cyan); display: none; }
.ask-drop-hint.show { display: block; }

/* ---- Home reference drop zones (character / wardrobe / environment) + AI toggle ----
   One compact ROW per category: icon + label · thumbnails · AI pill. Every tile is a fixed
   42px square (no aspect-ratio), so an EMPTY row is exactly as tall as a filled one. */
.anchor-bar { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.anchor-drops { display: flex; flex-direction: column; gap: 8px; width: 100%;
  max-height: 320px; overflow-y: auto; padding-right: 2px; }
/* flex-wrap, now that the row carries a sentence: the name and its explanation take the first
   line with the icon, the thumbnails and the buttons drop to the next. Without it the text
   squeezed the thumbnails to nothing on a narrow column. */
.anchor-drop { position: relative; display: flex; flex-direction: row; flex-wrap: wrap;
  align-items: center; gap: 10px; padding: 11px 12px;
  border: 1.5px dashed var(--border-hi); border-radius: 14px; background: var(--card);
  transition: border-color .15s, background .15s; }
.anchor-drop:hover { border-color: var(--muted); }
.anchor-drop.dragover { border-color: var(--cyan); background: rgba(0, 229, 255, .07); }
.anchor-drop.filled { border-style: solid; border-color: var(--cyan); }
/* Category identity is a tinted icon disc, not a word. The four categories are a fixed,
   never-growing set the user re-reads on every visit, so the label was pure repetition — and
   it cost 92px on every row, which is two thumbnails' worth of the space that actually
   matters. Colour does the telling-apart; the accessible name lives on title/aria-label. */
.anchor-cat-head { flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--cat-tint); border: 1px solid var(--cat-edge); color: var(--cat-ink);
  transition: transform .15s; }
.anchor-drop:hover .anchor-cat-head { transform: scale(1.06); }
.anchor-ico { width: 17px; height: 17px; flex: none; }
.anchor-drop[data-cat="character"]   { --cat-ink: #f2647a; --cat-tint: rgba(242,100,122,.13); --cat-edge: rgba(242,100,122,.34); }
.anchor-drop[data-cat="wardrobe"]    { --cat-ink: #5b9dff; --cat-tint: rgba(91,157,255,.13);  --cat-edge: rgba(91,157,255,.34); }
.anchor-drop[data-cat="environment"] { --cat-ink: #a97bff; --cat-tint: rgba(169,123,255,.13); --cat-edge: rgba(169,123,255,.34); }
.anchor-drop[data-cat="product"]     { --cat-ink: #57c98a; --cat-tint: rgba(87,201,138,.13);  --cat-edge: rgba(87,201,138,.34); }
/* ONE FAMILY, NOT SIX SIGNALS. Four categories in four colours was a legible set when the panel
   always showed the same four; a style now asks for two or three of eight, so the colour no
   longer encodes anything a creator could learn — it just makes the column look like a paint
   chart. The shapes tell them apart (see REF_ICONS); these two ride the same neutral as the rest
   of the panel, and the accent is kept for the row that is FILLED. */
.anchor-drop[data-cat="logo"],
.anchor-drop[data-cat="interior"]    { --cat-ink: var(--text-muted); --cat-tint: rgba(255,255,255,.05); --cat-edge: rgba(255,255,255,.14); }
/* Thumbnails wrap in a row; the add/AI tile is a compact pill at the end, not a full-width dropzone. */
/* One line, always. Wrapping put the "+" on a second row the moment four thumbnails filled
   the width, which made the row twice as tall and moved the button somewhere different for
   every category. The strip scrolls instead; the "+" sits outside it and never moves.
   The vertical padding is for the remove badges, which hang past the tile's top edge — an
   overflow-x container clips the other axis too, and without it they'd be sliced off. */
.anchor-thumbs { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: nowrap;
  align-items: center; gap: 6px; overflow-x: auto; overflow-y: hidden;
  padding: 8px 8px 8px 2px; margin: -8px -8px -8px 0; scrollbar-width: none; }
.anchor-thumbs::-webkit-scrollbar { display: none; }
.anchor-thumb-item, .anchor-ai-tile { flex: none; }
.anchor-addslot { flex: none; display: flex; align-items: center; }
/* No overflow:hidden — the remove badge hangs off the corner, and clipping it would put a
   half-circle on every thumbnail. The image is clipped by its own radius instead. */
.anchor-thumb-item { position: relative; width: 42px; height: 42px; border-radius: 9px;
  border: 1px solid var(--border-hi); }
.anchor-thumb-item img { width: 100%; height: 100%; object-fit: cover; display: block;
  border-radius: 8px; }
/* Perched on the corner, not sitting on the image. At 20px inside a 42px tile the badge read
   as the tile's content rather than as an affordance attached to it — on a thumbnail that
   small there is no "corner" left to place anything in. Hidden until the row is hovered so
   four rows of references aren't studded with delete buttons. */
.anchor-thumb-x { position: absolute; top: -6px; right: -6px; width: 17px; height: 17px;
  border-radius: 50%; display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: 0.58rem; padding: 0; line-height: 1; z-index: 2;
  background: rgba(8, 9, 14, .92); border: 1px solid var(--border-hi); color: #fff;
  opacity: 0; transition: opacity .12s, background .12s, border-color .12s; }
.anchor-drop:hover .anchor-thumb-x, .anchor-thumb-x:focus-visible { opacity: 1; }
.anchor-thumb-x:hover { background: var(--err); border-color: var(--err); color: #fff; }
.anchor-add { width: 42px; height: 42px; border-radius: 9px; cursor: pointer; background: transparent;
  border: 1.5px dashed var(--border-hi); color: var(--muted); display: flex; flex-direction: row;
  align-items: center; justify-content: center; gap: 2px; transition: border-color .15s, color .15s; }
.anchor-add:hover { border-color: var(--cyan); color: var(--cyan); }
.anchor-add-plus { font-size: 1.3rem; line-height: 1; }
/* i2v takes a single image — give its lone tile a bit more presence */
.anchor-bar.single-ref .anchor-add { width: 56px; height: 56px; }
/* per-category AI auto-fill toggle — sits at the end of the row */
.anchor-ai { flex: none;
  display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--border-hi); background: rgba(8,9,14,.72); color: var(--muted);
  font: inherit; font-size: 0.64rem; font-weight: 700; letter-spacing: .04em; cursor: pointer;
  transition: all .15s; backdrop-filter: blur(2px); }
.anchor-ai:hover:not(:disabled) { color: var(--text); border-color: var(--cyan-dim); }
.anchor-ai.on { color: #05222a; background: var(--cyan); border-color: var(--cyan); box-shadow: var(--glow-cyan); }
.anchor-ai:disabled { opacity: .3; cursor: not-allowed; }
/* The AI control: toggle + a −/+ stepper for how many images to generate. */
/* Sits where the lone AI button used to: the last flex child of the row. */
/* A fixed three-column grid, not a flex row: the AI stepper appears only where AI is on, and
   under flex its absence pulled that row's other controls sideways — so the same control sat
   at a different x on every row and nothing could be compared down the column. Explicit
   grid-column keeps each control in its own track whether or not its neighbours are there. */
.anchor-ai-wrap { flex: none; margin-left: auto; display: grid; align-items: center;
  grid-template-columns: 30px 92px 62px; gap: 8px; justify-items: end; }
.anchor-mode      { grid-column: 1; }
.anchor-send-step { grid-column: 2; }
.anchor-ai         { grid-column: 3; }
/* One count control on the row: how many of the pool go to the model each run. (AI's count is
   the number of placeholder tiles — each has its own ✕, so it needs no stepper here.) */
.step-box { display: inline-flex; align-items: center; justify-content: space-between; padding: 3px 5px;
  border-radius: var(--r-pill); background: rgba(8,9,14,.72); border: 1px solid var(--border-hi); }
.step-box.hidden { display: none; }
.step-box > b { display: inline-flex; align-items: baseline; gap: 1px;
  font-size: .74rem; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.step-box button {
  width: 18px; height: 18px; cursor: pointer; padding: 0; line-height: 1;
  border: 0; border-radius: 50%; background: none;
  color: var(--muted); font: inherit; font-size: .8rem;
  display: flex; align-items: center; justify-content: center;
}
.step-box button:hover:not(:disabled) { color: var(--text); background: var(--card-2); }
.step-box button:disabled { opacity: .28; cursor: not-allowed; }
/* Fixed width so the −, the number and the + hold their x across rows — a pool of 3 and a
   pool of 12 are different string lengths, and centring them would jitter the column. */
.anchor-send-step { border-color: var(--cat-edge); width: 92px; }
.anchor-send-step > b { color: var(--cat-ink); }
.send-pool { font-style: normal; font-size: .64rem; font-weight: 600; color: var(--faint);
  margin-left: -1px; letter-spacing: -.02em; }
.anchor-ai-ico { font-size: 0.72rem; line-height: 1; }
.anchor-ai-ico svg { width: 13px; height: 13px; display: block; }
.anchor-ai-spark svg { width: 16px; height: 16px; }
.btn-ico { width: 15px; height: 15px; vertical-align: -2px; margin-right: 5px; }
/* the "AI will generate" tile shown in place of the add button when AI is on for this category */
/* A placeholder for an image the AI will draw — not clickable, so no pointer or hover state
   (the "+" beside it is the upload affordance). */
/* A square, the same 42px as a thumbnail and as the ＋ beside it. It was content-width, which
   only looked deliberate while it had a label in it. */
.anchor-ai-tile { position: relative;   /* anchors its own ✕ */
  height: 42px; width: 42px; padding: 0; border-radius: 9px; font: inherit;
  border: 1.5px dashed var(--cyan-dim); background: rgba(0,229,255,.06);
  display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 7px; color: var(--cyan); }
.anchor-ai-spark { font-size: 1.5rem; line-height: 1; }
.anchor-drop.ai-on { border-style: solid; border-color: var(--cyan-dim); }
.anchor-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; }
.anchor-head-label { color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anchor-x { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 0.85rem;
  padding: 2px 7px; border-radius: 6px; line-height: 1; }
.anchor-x:hover { color: var(--err); background: rgba(255,93,108,.12); }
.anchor-reopen { position: relative; z-index: 1; background: none; border: 1px dashed var(--border-hi);
  color: var(--muted); cursor: pointer; border-radius: 10px; padding: 9px 16px; font: inherit; font-size: 0.85rem;
  margin: 0 auto 14px; display: block; }
.anchor-reopen:hover { color: var(--text); border-color: var(--muted); }

/* Autopilot "what's it doing" dropdown */
.ap-details { margin: 6px 0 18px; border: 1px solid var(--border); border-radius: 12px; background: var(--card); }
.ap-details summary { cursor: pointer; padding: 12px 16px; color: var(--text); font-size: 0.9rem; user-select: none; }
.ap-details summary::marker { color: var(--cyan); }
.ap-config { padding: 4px 16px 14px; }
.cfg-row { display: flex; gap: 14px; padding: 7px 0; border-top: 1px solid var(--border); font-size: 0.86rem; }
.cfg-row:first-child { border-top: none; }
.cfg-k { flex: 0 0 180px; color: var(--muted); }
.cfg-v { flex: 1; color: var(--text); word-break: break-word; }

/* Studio */
.dropzone {
  border: 2px dashed var(--border-hi); border-radius: 14px; min-height: 180px;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: border-color .15s, background .15s; text-align: center; padding: 18px;
}
.dropzone.dragover { border-color: var(--cyan); background: rgba(0,229,255,.05); box-shadow: var(--glow-cyan); }
.drop-ico { font-size: 2.2rem; margin-bottom: 8px; }
/* (the ask view's upload preview and #refPreview were removed with that screen; their rules
   lived on here and, being later in the file, quietly overrode the references page's own
   .ref-preview — display:flex became block and max-width:360px became 100%.) */
.view-ask .link-ghost { position: relative; z-index: 1; margin-top: 18px; }

/* ============================== WIZARD ============================== */
/* Same top-anchored layout as Setup (fixed bar → no viewport-tall min-height needed) */
.view-setup.active { display: flex; }
.view-setup { align-items: flex-start; justify-content: center; }
.wizard { width: 100%; margin: 0; display: flex; flex-direction: column; }
/* Center the step nav (matches the Setup/Home step nav); float the ✕ close top-right */
/* The wizard's own step strip, pinned the same way as Setup's — they are two steps of one flow
   and had two different navs. Its ✕ goes where Setup's goes, for the same reason. */
.wizard-top { position: fixed; top: 52px; left: var(--sidebar-w); right: 0; height: 2px;
  z-index: 55; display: block; margin: 0; transition: left .2s ease; }
.app.collapsed .wizard-top { left: var(--sidebar-w-collapsed); }
.wizard-top::before { content: ""; position: absolute; inset: 0; background: var(--border); opacity: .6; }
.wizard-top .dots { max-width: none; }
.wizard-top-right { position: fixed; right: 26px; top: 66px; z-index: 56;
  display: flex; align-items: center; gap: 14px; }
.wiz-close {
  width: 30px; height: 30px; flex-shrink: 0; border-radius: 8px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 0.95rem;
  background: var(--card); border: 1px solid var(--border-hi); color: var(--muted);
  transition: color .15s, border-color .15s, box-shadow .15s;
}
.wiz-close:hover { color: var(--text); border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }
/* STEP NAV — two pixels on the top bar's own border, and nothing else.

   It has been, in order: a row of interlocking chevrons; then a 3px rail with the step's name
   and "1 / 3" above it. Both were a navigation control for a flow of three screens that already
   has Back and Next on every one of them, and the second still spent 60px — a heading's worth
   of height — saying where you are, on a page whose heading says where you are.

   What is lost is the step's NAME. The page titles carry it now ("Let's create your video",
   "Let's configure your output", "Where it goes, and when"), which is where a reader looks
   first anyway. What is kept is how far along you are, which a line can say without a word. */
.dots { position: absolute; left: 0; right: 0; top: 0; height: 2px; max-width: none;
  background: transparent; pointer-events: none; }
/* 2px of accent over the whole width would be a bar, not a border. The unfilled remainder stays
   the border it is replacing. */
.home-steps-row::before { content: ""; position: absolute; inset: 0;
  background: var(--border); opacity: .6; }
.pstep-line { display: block; height: 2px; background: var(--accent); border-radius: 0 2px 2px 0;
  transition: width .42s cubic-bezier(.22,.61,.36,1); }
@media (prefers-reduced-motion: reduce) { .pstep-line { transition: none; } }
/* The nav stays optically centred on the page; the ✕ sits at the right without shifting it,
   which a plain flex row would do. */
/* The row is a 2px strip pinned to the bottom edge of the fixed top bar — 52px tall, 1px
   border — which is exactly where the line it replaces already runs. It follows the sidebar's
   left edge so it starts where the content does, not under the sidebar. */
.home-steps-row { position: fixed; top: 52px; left: var(--sidebar-w); right: 0; height: 2px;
  z-index: 55; display: block; padding: 0; margin: 0; transition: left .2s ease; }
.app.collapsed .home-steps-row { left: var(--sidebar-w-collapsed); }
.home-steps { margin: 0; position: absolute; inset: 0; z-index: 1; }
/* The ✕ cannot ride a 2px strip. It sits just under the top bar at the right of the content,
   which is where the wizard's own ✕ already is — the two are the same control on two steps of
   one flow, so they belong in the same place. */
.home-steps-row > .wiz-close { position: fixed; right: 26px; top: 66px; z-index: 56;
  pointer-events: auto; }
.note-hint { display: block; margin-top: 6px; line-height: 1.4; }
.prompt-advanced { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 6px; }
.prompt-advanced > summary { cursor: pointer; color: var(--muted); font-size: .85rem; font-weight: 600; padding: 6px 0; user-select: none; list-style: none; }
.prompt-advanced > summary::-webkit-details-marker { display: none; }
.prompt-advanced > summary::before { content: "▸ "; color: var(--muted); }
.prompt-advanced[open] > summary::before { content: "▾ "; }
.prompt-advanced > summary:hover { color: var(--text); }

.wizard-stage { position: relative; margin-bottom: 16px; }
.wcard { display: none; }
.wcard.show { display: block; animation: cardIn .28s ease; }
@keyframes cardIn { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* Step 0's Back returns to Setup, so "go back one page" works the whole way through. */
.bar-inner #wizBack, .bar-inner .btn-neon { flex: none; }
/* NO `overflow: hidden` HERE ANY MORE. It belonged to the version that was a long sentence
   needing an ellipsis; the hover checklist is a child of this element and sits ABOVE it, so
   clipping to the element's own 112x18 box removed the popup entirely — it was in the DOM, at
   the right place, invisible. The count is short and nowrap, so nothing needs clipping. */
.bar-inner #wizLaunchHint { flex: none; text-align: right; }
/* The page that fixes the blocker, named in the sentence and clickable there. A button, not an
   <a>: it moves the view, it does not navigate to a URL — and inside a nowrap/ellipsis line it
   has to stay part of the text run, so it inherits the font and carries no box of its own. */
/* THE FIELD THAT WAS MISSING, found for you. Landing on the right page is half an answer when
   the page has eight controls on it — this is the other half, and it fades out on its own
   because a highlight that stays becomes part of the furniture. */
/* INSET, NOT A RING AROUND IT. An outer ring is drawn outside the element's box, so it took the
   element's radius from a rule of its own (a pill around a square select), and any ancestor with
   `overflow: hidden` cut it off part-way — which is what "half highlighted" was. Drawn inside,
   it cannot be clipped, it cannot mismatch the corners, and it fills the thing it is pointing
   at rather than outlining the space around it. */
@keyframes blkFlash {
  0%   { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--danger) 0%, transparent);
         background-color: transparent; }
  15%  { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--danger) 75%, transparent);
         background-color: color-mix(in srgb, var(--danger) 14%, transparent); }
  100% { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--danger) 0%, transparent);
         background-color: transparent; }
}
/* Rounded, because the block it lights sits inside a rounded card — a square ring in the first
   or last field of one crosses the card's own corner. */
.blk-flash { animation: blkFlash 2.2s ease-out; border-radius: 10px; }
/* An upload slot already has corners; the flash must not square them off for 2.2 seconds. */
.anchor-drop.blk-flash { border-radius: 14px; }
@media (prefers-reduced-motion: reduce) {
  .blk-flash { animation: none; box-shadow: inset 0 0 0 2px var(--danger); }
}

.hint-go { border: 0; background: none; padding: 0; font: inherit; color: var(--accent);
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.hint-go:hover { filter: brightness(1.2); }

/* provider list */
.provider-list { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.provider-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; border-radius: 12px; cursor: pointer;
  border: 1px solid var(--border); background: var(--card-2);
  transition: all .15s;
}
.provider-row:hover { border-color: var(--border-hi); }
.provider-row.on { border-color: var(--cyan); box-shadow: var(--glow-cyan); background: rgba(0,229,255,.05); }
.provider-logo { font-size: 1.3rem; width: 28px; text-align: center; }
.engine-ico { width: 18px; height: 18px; vertical-align: -4px; display: inline-block; flex: none; }
.provider-logo .engine-ico { width: 22px; height: 22px; vertical-align: middle; }
.provider-name { font-weight: 600; flex: 1; }
.model-check { color: var(--cyan); font-weight: 700; font-size: 1.05rem; width: 18px; text-align: center; }
.model-id { background: var(--bg); padding: 2px 7px; border-radius: 6px; font-size: 0.78rem; color: var(--cyan); font-family: ui-monospace, monospace; }
.provider-avail {
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; border: 1px solid var(--border-hi);
}
.provider-avail .d { width: 9px; height: 9px; border-radius: 50%; background: var(--faint); }
.provider-avail.ready .d { background: var(--ok); box-shadow: 0 0 8px var(--ok); }

/* duration slider */
.slider { -webkit-appearance: none; appearance: none; width: 100%; height: 5px; border-radius: 5px;
  background: var(--border-hi); outline: none; margin-top: 8px; padding: 0; border: none; }
.slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%;
  background: var(--cyan); cursor: pointer; box-shadow: 0 0 10px rgba(0,229,255,.7);
  border: 2px solid #07080d;
}
.slider::-moz-range-thumb { width: 20px; height: 20px; border-radius: 50%; background: var(--cyan); cursor: pointer; border: 2px solid #07080d; box-shadow: 0 0 10px rgba(0,229,255,.7); }
.neon-val { color: var(--accent); font-family: var(--font-display); font-weight: 800; font-size: 1.1rem; }

/* aspect tiles */
.aspect-tiles { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.aspect-tile {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-radius: 10px; cursor: pointer; font-size: 0.9rem;
  border: 1px solid var(--border-hi); background: var(--card-2); color: var(--muted);
  transition: all .15s;
}
.aspect-tile:hover { color: var(--text); }
.aspect-tile.on { color: #07080d; background: var(--grad); border-color: transparent; box-shadow: var(--glow-cyan); font-weight: 600; }
.aspect-tile .icn { display: inline-block; border: 2px solid currentColor; border-radius: 3px; flex-shrink: 0; }

/* post targets */
.post-targets { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.target-pill {
  padding: 10px 18px; border-radius: 12px; cursor: pointer; font-size: 0.9rem; font-weight: 600;
  border: 1px solid var(--border-hi); background: var(--card-2); color: var(--muted);
  transition: all .15s;
}
.target-pill:hover { color: var(--text); }
.target-pill.on { color: #07080d; background: var(--grad); border-color: transparent; box-shadow: var(--glow-cyan); }
.target-pill.dev.on { background: linear-gradient(135deg, var(--warn), #ff8a3d); box-shadow: 0 0 16px rgba(255,181,71,.4); }
/* admin add/edit-model modal: duration range row + enabled toggle */
.am-dur { display: flex; gap: 10px; }
.am-dur label { flex: 1; }
.am-enabled { flex-direction: row !important; align-items: center; gap: 8px; cursor: pointer; }
.am-enabled input { width: auto; }
.imgm-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.imgm-model { max-width: 230px; }
.imgm-custom { max-width: 200px; }
/* The number keeps a name of its own. A placeholder is not a label — it disappears the moment
   the field has a value, which for this one is always. */
.imgm-field { display: flex; flex-direction: column; gap: 4px; max-width: 150px;
  font-size: .72rem; font-weight: 600; color: var(--muted); }
.imgm-field .select { width: 100%; }
.conn-state { margin-top: 10px; }

/* review */
.review-summary { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.rev-row { display: flex; justify-content: space-between; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.rev-row:last-child { border-bottom: none; }
.rev-row .k { color: var(--muted); }
.rev-row .v { text-align: right; font-weight: 600; }
.rev-row .edit { color: var(--cyan); cursor: pointer; font-size: 0.8rem; margin-left: 10px; }

/* ============================ AUTOPILOT ============================ */
.ap-head { display: flex; align-items: center; justify-content: space-between; }
.hero { display: flex; align-items: center; gap: 22px; }
/* Padding matches the ring's 14px overhang on each side, so the orbit sits inside this box
   and .hero's gap still measures 22px of real space to the text. */
.hero-left { flex-shrink: 0; padding: 14px; }
.hero-mid { flex: 1; }
.hero-state { font-size: 1.4rem; font-weight: 700; }
.hero-sub { font-size: 0.9rem; margin-top: 2px; }
.hero-right { display: flex; flex-direction: column; gap: 8px; }
/* 2×2 icon-only action grid (Stop/Start · Run · Edit · Delete) — hover shows the label */
.hero-actions { display: grid; grid-template-columns: repeat(2, 46px); grid-auto-rows: 46px; gap: 8px; }
.ico-btn { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px;
  border-radius: 10px; border: 1px solid var(--border); background: var(--card-2); color: var(--text);
  font-size: 1.1rem; cursor: pointer; transition: border-color .15s, background .15s, color .15s; }
.ico-btn svg { width: 20px; height: 20px; }
.ico-btn:hover { border-color: var(--border-hi); background: var(--card); }
.ico-btn:disabled { opacity: .4; cursor: not-allowed; }
.ico-btn.start { color: #22c55e; }
.ico-btn.start:hover { border-color: #22c55e; }
.ico-btn.stop:hover, .ico-btn.danger:hover { border-color: #ff6b6b; color: #ff6b6b; }
/* ---- Status bead: a living indicator for each Autopilot state ---- */
.orb {
  width: 58px; height: 58px; border-radius: 50%; flex-shrink: 0;
  background: var(--faint); position: relative;
}
/* two concentric layers: a ring track and a rotating arc (or a spinner) per state */
.orb::before, .orb::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
}

/* RUNNING — glowing bead with a ring orbiting it. (Was expanding sonar rings; a steady
   orbit reads as "working" rather than "pinging", and doesn't flash the layout.) */
.orb.running {
  background: radial-gradient(circle at 34% 30%, #9bf9ff, var(--cyan) 72%);
  box-shadow: 0 0 22px color-mix(in srgb, var(--accent) 55%, transparent),
              inset 0 -6px 10px rgba(20,30,90,.55), inset 0 5px 9px rgba(255,255,255,.4);
  animation: breathe 2.6s ease-in-out infinite;
}
/* the faint full circle the bright arc travels along */
.orb.running::before {
  inset: -14px; border: 2px solid var(--accent-border);
}
/* the arc itself: a conic gradient masked down to a 2px ring, rotating */
.orb.running::after {
  inset: -14px;
  background: conic-gradient(from 0deg, transparent 0 62%, var(--cyan));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 0);
          mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 0);
  animation: spin 2.4s linear infinite;
}

/* GENERATING — energetic magenta bead with a spinning ring */
.orb.generating {
  background: radial-gradient(circle at 34% 30%, #ff9bef, var(--magenta) 72%);
  box-shadow: 0 0 22px rgba(255,43,214,.6),
              inset 0 -6px 10px rgba(110,0,80,.55), inset 0 5px 9px rgba(255,255,255,.4);
  animation: breathe 1.1s ease-in-out infinite;
}
.orb.generating::before {
  inset: -5px; background: conic-gradient(from 0deg, transparent 30%, var(--magenta));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 0);
          mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 0);
  animation: spin .9s linear infinite;
}

/* CAPPED — warm bead resting until tomorrow, gentle slow glow */
.orb.capped {
  background: radial-gradient(circle at 34% 30%, #ffe0a8, var(--warn) 72%);
  animation: glowWarm 3s ease-in-out infinite;
}

/* STOPPED — dim, asleep bead */
.orb.stopped {
  background: radial-gradient(circle at 34% 30%, #3c4250, #1c1f27 72%);
  box-shadow: inset 0 0 10px rgba(0,0,0,.7);
}

/* One card, one row: five equal columns split by hairlines. minmax(0,…) is what keeps it on
   a single line — with the default `auto` minimum a long value would widen its own column
   and push the last stat onto a second row. */
.stats-row {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0;
  margin-bottom: 8px; overflow: hidden;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
}
.stat {
  min-width: 0; padding: 14px 16px;
  background: none; border: 0; border-left: 1px solid var(--border); border-radius: 0;
}
.stat:first-child { border-left: 0; }
.stat .label {
  display: flex; align-items: center; gap: 7px;
  font-size: 0.72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.stat .label svg { width: 15px; height: 15px; flex: none; color: var(--accent); }
.stat .label span { overflow: hidden; text-overflow: ellipsis; }
/* Values and sub-lines clip rather than wrap, so the row height stays uniform. */
.stat .value { font-size: 1.45rem; font-weight: 700; margin-top: 6px; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat .sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat .value.cyan { color: var(--cyan); }
.stat .value.warn { color: #ff9f43; }

.credits-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 14px; }
.credit-box { background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 16px; text-align: center; }
.credit-num { font-size: 1.8rem; font-weight: 800; color: var(--cyan); }
.credit-num.low { color: #ff9f43; }
/* low-balance highlight on the CARD (border colour only → same box size, stays aligned) */
.credit-box.low { border-color: rgba(255,159,67,.5); background: rgba(255,159,67,.06); }
.credit-lbl { font-size: 0.8rem; color: var(--muted); margin-top: 4px; }

/* credits history ledger */
.cred-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 4px; border-bottom: 1px solid var(--border); }
.cred-row:last-child { border-bottom: none; }
.cred-row-name { font-weight: 600; }
.cred-amt { font-weight: 700; font-size: 1rem; white-space: nowrap; margin-left: 16px; }
.cred-amt.neg { color: var(--err); }
.cred-amt.pos { color: var(--ok); }

/* ---- multi-account accounts page ---- */
.acct-platform { margin-bottom: 26px; }
.acct-platform-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.acct-platform-head h2 { margin: 0; }
.account-card .acct-title { cursor: pointer; }
.account-card .acct-title:hover { color: var(--cyan); }

/* ---- autopilots dashboard ---- */
/* Workspaces: left = card list, right = selected workspace detail (blank until picked) */
.ws-split { display: grid; grid-template-columns: 360px minmax(0, 1fr); gap: 28px; align-items: start; margin-top: 10px; }
/* Each side scrolls on its own — the page itself doesn't scroll on this view, so a long
   activity feed can't push the workspace list out of reach (and vice versa). */
.ws-left { display: flex; flex-direction: column; gap: 12px; min-width: 0; max-height: calc(100vh - 190px); }
.ws-new { width: 100%; flex: none; }   /* same width as the cards below it */
.ws-list { min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-right: 6px; margin-right: -6px; }
/* Detail-only view now: let the PAGE scroll (one scrollbar) instead of a nested container. */
.ws-detail-wrap { min-width: 0; }
.ws-list::-webkit-scrollbar, .ws-detail-wrap::-webkit-scrollbar { width: 8px; }
.ws-list::-webkit-scrollbar-thumb, .ws-detail-wrap::-webkit-scrollbar-thumb {
  background: var(--border-hi); border-radius: 999px; }
.ws-list::-webkit-scrollbar-track, .ws-detail-wrap::-webkit-scrollbar-track { background: transparent; }
.ws-empty { color: var(--muted); text-align: center; padding: 60px 16px; border: 1px dashed var(--border); border-radius: 14px; }
@media (max-width: 920px) {
  .ws-split { grid-template-columns: 1fr; }
  /* Phones/narrow: stacked, so let the page scroll normally instead of two nested scrollers. */
  .ws-left, .ws-detail-wrap { max-height: none; }
  .ws-list, .ws-detail-wrap { overflow-y: visible; }
}
.ap-grid { display: flex; flex-direction: column; gap: 12px; }
.ap-card { display: flex; align-items: center; gap: 14px; padding: 16px 18px; }
.ap-card.clickable { cursor: pointer; transition: border-color .15s, background .15s; }
.ap-card.clickable:hover { border-color: var(--border-hi); background: var(--card-2); }
.ap-card.selected { outline: 1px solid var(--cyan-dim); }
.stat .value span[title] { border-bottom: 1px dotted var(--border-hi); cursor: help; }
.ap-card .ap-main { flex: 1; min-width: 0; }
.ap-card .ap-name { font-weight: 700; font-size: 1.05rem; }
.ap-name-row { display: flex; align-items: center; gap: 8px; }
.ap-rename-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border-radius: 7px;
  background: transparent; border: 1px solid transparent; color: var(--faint);
  cursor: pointer; opacity: 0; transition: opacity .12s, color .12s, border-color .12s;
}
.ap-rename-btn svg { width: 14px; height: 14px; }
.ap-card:hover .ap-rename-btn { opacity: 1; }
.ap-rename-btn:hover { color: var(--cyan); border-color: var(--border-hi); background: var(--card-2); }
.ap-name-input {
  background: var(--card-2); border: 1px solid var(--cyan); border-radius: 8px;
  color: var(--text); font-size: 1.02rem; font-weight: 600; padding: 6px 10px; min-width: 200px;
  outline: none; box-shadow: 0 0 0 3px rgba(0,229,255,.12);
}
.ap-card .ap-sub { color: var(--muted); font-size: 0.82rem; margin-top: 3px; }
.ap-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.ap-chip { font-size: 0.74rem; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); color: var(--muted); }
.ap-actions { display: flex; gap: 8px; flex-shrink: 0; }
.ap-status { display: inline-flex; align-items: center; gap: 6px; font-size: 0.8rem; }
.ap-status .orb-dot { width: 8px; height: 8px; }
.ap-status.running .orb-dot { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.ap-status.paused .orb-dot { background: var(--faint); }

/* ---- target picker + presets ---- */
.targets-box { margin-top: 6px; }
.target-acct { display: inline-flex; align-items: center; gap: 9px; font-size: 0.9rem; color: var(--text);
  padding: 9px 14px; margin: 0 8px 8px 0; cursor: pointer; border: 1px solid var(--border);
  border-radius: 12px; background: var(--card); user-select: none;
  transition: border-color .15s, background .15s, box-shadow .15s; }
.target-acct:hover { border-color: var(--muted); }
.target-acct:has(input:checked) { border-color: var(--cyan); background: rgba(0, 229, 255, .07);
  box-shadow: 0 0 0 1px var(--cyan) inset; }
.target-acct input { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; margin: 0;
  border: 1.6px solid var(--muted); border-radius: 6px; cursor: pointer; position: relative; flex: none;
  transition: background .15s, border-color .15s; }
.target-acct input:checked { background: var(--grad); border-color: transparent; }
.target-acct input:checked::after { content: ""; position: absolute; left: 5px; top: 1.5px;
  width: 5px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.ta-plat { display: inline-flex; align-items: center; color: var(--muted); margin-left: 1px; }
.plat-ico { width: 17px; height: 17px; }
/* multi-select account dropdown (Posting → Post to) */
.acct-multi { position: relative; margin-top: 6px; max-width: 460px; }
.acct-multi-trigger { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  padding: 11px 14px; border: 1px solid var(--border-hi); border-radius: 12px; background: var(--card);
  color: var(--text); font: inherit; cursor: pointer; text-align: left; transition: border-color .15s; }
.acct-multi-trigger:hover { border-color: var(--muted); }
.acct-multi-label { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.ta-chip { display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; border-radius: 999px;
  background: rgba(0,229,255,.09); border: 1px solid var(--cyan-dim); color: var(--text); font-size: .82rem; white-space: nowrap; }
.acct-multi-caret { color: var(--muted); flex: none; }
.acct-multi-menu { position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 40;
  background: var(--card); border: 1px solid var(--border-hi); border-radius: 12px; box-shadow: var(--shadow);
  padding: 6px; max-height: 280px; overflow-y: auto; }
.acct-multi-opt { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px;
  cursor: pointer; color: var(--text); user-select: none; }
.acct-multi-opt:hover { background: var(--card-2); }
.acct-multi-opt input { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; margin: 0; flex: none;
  border: 1.6px solid var(--muted); border-radius: 6px; cursor: pointer; position: relative; transition: background .15s, border-color .15s; }
.acct-multi-opt input:checked { background: var(--grad); border-color: transparent; }
.acct-multi-opt input:checked::after { content: ""; position: absolute; left: 5px; top: 1.5px;
  width: 5px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.acct-multi-opt .ta-name { flex: 1; }
/* Email is not one more account — it is what happens instead of them — so a line separates it
   from the list rather than letting it read as a fourth handle. */
.acct-multi-sep { height: 1px; margin: 6px 4px; background: var(--border); }
.acct-multi-opt .ta-sub { display: block; font-size: .74rem; color: var(--text-faint); }
.preset-bar { display: flex; gap: 8px; align-items: center; margin: 10px 0 16px; flex-wrap: wrap; }

.feed { display: flex; flex-direction: column; gap: 8px; }
.feed-item {
  display: flex; gap: 12px; align-items: flex-start; position: relative;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px;
  font-size: 0.88rem;
}
.feed-item .when { color: var(--faint); font-size: 0.78rem; white-space: nowrap; }
.feed-del {
  background: transparent; border: none; color: var(--faint); cursor: pointer;
  font-size: 0.85rem; padding: 2px 6px; border-radius: 6px; opacity: 0; transition: opacity .15s, color .15s;
  align-self: center; flex-shrink: 0;
}
.feed-item:hover .feed-del { opacity: 1; }
.feed-del:hover { color: var(--err); background: rgba(255,93,108,.12); }
.feed-more {
  width: 100%; padding: 10px; margin-top: 4px; cursor: pointer;
  background: var(--card); border: 1px dashed var(--border-hi); border-radius: 12px;
  color: var(--cyan); font-size: 0.85rem;
}
.feed-more:hover { box-shadow: var(--glow-cyan); }
.feed-item .body { flex: 1; min-width: 0; }
.feed-item .prov { color: var(--cyan); font-size: 0.76rem; }
.feed-item .res-ok { color: var(--ok); }
.feed-item .res-bad { color: var(--err); }
/* Portrait, because every clip is 9:16 — a square thumb cropped away most of the frame. */
.feed-thumb { width: 84px; height: 112px; border-radius: 8px; object-fit: cover; background: #000; cursor: pointer; flex-shrink: 0; transition: box-shadow .15s, transform .1s; }
.feed-thumb:hover { box-shadow: var(--glow-cyan); transform: scale(1.04); }
/* held-for-approval clips in the Activity feed */
.feed-item.pending { border-color: rgba(224,169,58,.45); }
/* right column: timestamp on top, Pending tag under it, hover-only action icons below */
.feed-side { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; flex-shrink: 0; }
.feed-tag { color: var(--warn); font-size: .72rem; font-weight: 600; white-space: nowrap; }
.feed-actions { display: flex; gap: 5px; opacity: 0; transition: opacity .15s; }
.feed-item:hover .feed-actions { opacity: 1; }   /* icons appear only on hover */
.feed-act { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px;
  border-radius: 8px; border: 1px solid var(--border); background: var(--card-2); color: var(--muted); cursor: pointer;
  transition: color .15s, border-color .15s; }
.feed-act svg { width: 15px; height: 15px; }
.feed-act.approve:hover { color: var(--ok); border-color: var(--ok); }
.feed-act.reject:hover { color: var(--err); border-color: var(--err); }
.feed-act:disabled { opacity: .5; cursor: default; }
/* date line above each day's runs — click to collapse the day, the line stays put */
.feed-day { display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;
  padding: 6px 2px; margin-top: 6px; color: var(--muted); font-size: 0.78rem;
  font-weight: 600; letter-spacing: .04em; text-transform: uppercase; transition: color .15s; }
.feed-day:first-child { margin-top: 0; }
.feed-day:hover { color: var(--text); }
.feed-day-caret { font-size: .7rem; color: var(--faint); transition: transform .18s, color .15s; }
.feed-day:hover .feed-day-caret { color: var(--cyan); }
.feed-day.closed .feed-day-caret { transform: rotate(-90deg); }
.feed-day-line { flex: 1; height: 1px; background: var(--border); }
.feed-day-items { display: flex; flex-direction: column; gap: 8px; }
.feed-day-items.closed { display: none; }
.feed-prompt {
  cursor: pointer; border-radius: 6px; transition: color .15s;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden; line-height: 1.45;
}
.feed-prompt:hover { color: var(--text); text-decoration: underline dotted var(--cyan-dim); text-underline-offset: 3px; }

/* ============================= LIBRARY ============================= */
.lib-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }
.lib-loading {
  grid-column: 1 / -1; display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 60px 0; color: var(--muted); font-size: 0.92rem;
}
.spinner {
  width: 18px; height: 18px; border-radius: 50%; display: inline-block;
  border: 2px solid var(--border-hi); border-top-color: var(--cyan);
  animation: spin .7s linear infinite;
}
/* per-card thumbnail loading overlay (covers the black frame until it decodes) */
.lib-thumb-wrap { position: relative; }
.thumb-spinner {
  position: absolute; inset: 0; z-index: 1; display: flex; align-items: center; justify-content: center;
  background: #000; transition: opacity .25s;
}
.lib-thumb-wrap.ready .thumb-spinner { opacity: 0; pointer-events: none; }
/* generic "button is working" state (Run once now, Start, Reset, Launch, …) */
.btn-neon.is-busy, .btn-ghost.is-busy {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  opacity: .85; cursor: default;
}
.btn-neon.is-busy .spinner { border-color: rgba(255,255,255,.45); border-top-color: #fff; }
.lib-card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; position: relative; }
/* One stack in the card's top-left corner: the workspace name always, the actions under it on
   hover. The name sits outside the hover rule on purpose — "which workspace made this" is what
   you scan the grid for, and a label you have to hover each card to read is no label at all. */
.lib-overlay {
  position: absolute; top: 8px; left: 8px; right: 8px; z-index: 2;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  pointer-events: none;                      /* the thumbnail underneath stays clickable */
}
.lib-overlay > * { pointer-events: auto; }
/* pointer-events, not just opacity. Invisible buttons that still take clicks were tolerable in
   the corner; over the thumbnail's left edge they would swallow clicks meant for the preview,
   and Delete would be one of them. */
/* THE ACTIONS STAND IN THE TOP-RIGHT CORNER, one above another (owner, 2026-10-10): share,
   download, delete — away from the workspace chip and the "Playing" badge on the left. Anchored
   to the card, not the left-hand stack. */
.lib-actions { position: absolute; top: 0; right: 0; z-index: 3;
  display: flex; flex-direction: column; gap: 6px; opacity: 0; pointer-events: none; transition: opacity .15s; }
.lib-card:hover .lib-actions { opacity: 1; pointer-events: auto; }
.lib-act {
  width: 30px; height: 30px; padding: 0; border-radius: 8px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; text-decoration: none;
  background: rgba(7,8,13,.75); border: 1px solid var(--border-hi); color: var(--text);
}
.lib-act svg { width: 16px; height: 16px; display: block; }
.lib-act:hover { border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }
.lib-act.is-busy { opacity: .5; pointer-events: none; }
.lib-act.is-busy svg { animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.lib-act.lib-del { color: var(--err); }
.lib-act.lib-share:hover { color: var(--accent); border-color: var(--accent); }
.lib-act.lib-del:hover { background: rgba(255,93,108,.2); box-shadow: 0 0 12px rgba(255,93,108,.3); border-color: var(--err); }
.lib-card video, .lib-card img.lib-thumb { width: 100%; display: block; background: #000; aspect-ratio: 9/16; object-fit: cover; }
.lib-thumb { cursor: pointer; transition: filter .15s; }
.lib-thumb:hover { filter: brightness(1.12); }
.lib-meta { padding: 10px 12px; }
.lib-meta .cap { font-size: 0.82rem; color: var(--muted); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lib-badges { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }

/* -- library header: status tabs, search -- */
.lib-title { margin-bottom: 14px; }
.lib-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 18px;
}
.lib-tabs {
  display: flex; align-items: stretch; gap: 4px; flex-wrap: wrap; padding: 4px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--card);
}
.lib-tab {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  padding: 7px 13px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--muted); font: inherit; font-size: .84rem; font-weight: 600;
  line-height: 1.4;                        /* fixed: the mono count set its own line box */
  transition: background .16s ease, color .16s ease;
}
.lib-tab:hover { color: var(--text); }
.lib-tab.on { background: var(--surface-2); color: var(--text); }
.lib-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.lib-tab.warn .lib-tab-dot { color: var(--warn); }
.lib-tab.ok   .lib-tab-dot { color: var(--ok); }
.lib-tab.err  .lib-tab-dot { color: var(--danger); }
.lib-tab.neutral .lib-tab-dot { color: var(--faint); }
/* All three children share one line box, so nothing rides higher or lower than its siblings. */
.lib-tab-l, .lib-tab-n { display: block; line-height: 18px; }
.lib-tab-n { font-family: var(--font-mono); font-size: .72rem; color: var(--faint); }
.lib-tab.on .lib-tab-n { color: var(--muted); }
.lib-search-wrap { position: relative; flex: 0 1 320px; min-width: 240px; }
.lib-search-ico {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--faint); pointer-events: none;
}
.lib-search { width: 100%; padding-left: 36px; font-size: .84rem; }
.lib-search-wrap:focus-within .lib-search-ico { color: var(--muted); }

/* -- card meta lines + state footer -- */
.lib-lines { display: grid; gap: 5px; margin-top: 9px; }
.lib-line { display: flex; align-items: center; gap: 7px; font-size: .74rem; color: var(--muted); }
.lib-line-ico { width: 13px; height: 13px; flex: none; color: var(--accent); }
/* Cards stretch to the tallest in the row; the meta takes the slack so every footer sits on
   the same line. Without this a two-line caption pushed one card's "Posted" below its
   neighbours'. */
.lib-card { display: flex; flex-direction: column; }
.lib-meta { flex: 1 1 auto; }
.lib-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: auto; padding: 10px 12px; border-top: 1px solid var(--border);
}
.lib-st { display: inline-flex; align-items: center; gap: 6px; font-size: .78rem; font-weight: 600; color: var(--muted); }
.lib-st-ico { width: 14px; height: 14px; flex: none; }
.lib-st.ok { color: var(--ok); }
.lib-st.warn { color: var(--warn); }
.lib-st.err { color: var(--danger); }
.lib-restore {
  width: 100%; margin-top: 10px; cursor: pointer; padding: 8px 10px;
  border: 1px solid var(--border-hi); border-radius: var(--r-sm);
  background: none; color: var(--text); font: inherit; font-size: .82rem; font-weight: 600;
}
.lib-restore:hover { border-color: var(--accent); color: var(--accent); }
/* POST, ON THE CARD AND NOT UNDER A HOVER. It was a round icon in the overlay, invisible until
   the pointer happened to cross the thumbnail and gone entirely on a phone — the one action the
   Library exists for, and people asked where it was. */
.lib-post {
  width: 100%; margin-top: 10px; cursor: pointer; padding: 8px 10px;
  border: 1px solid var(--accent-border); border-radius: var(--r-sm);
  background: var(--accent-weak); color: var(--accent); font: inherit; font-size: .82rem; font-weight: 650;
}
.lib-post:hover { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.lib-foot .lib-post { width: auto; margin: 0; padding: 6px 16px; }
.lib-more { display: none; font-size: 1rem; line-height: 1; position: absolute; top: 0; right: 0; z-index: 3; }
@media (hover: none) {
  .lib-more { display: flex; }
  .lib-card .lib-actions { opacity: 0; pointer-events: none; }
  .lib-card.acts-open .lib-actions { opacity: 1; pointer-events: auto; }
  .lib-card .lib-actions { top: 36px; }        /* under the ⋯ that opens them */
}

/* The Post dialog: the accounts it can go to, ticked, and the caption as it will go out. */
.modal-card:has(.post-dlg) { max-width: 440px; }
.post-dlg-label { display: block; margin: 0 0 8px; font-size: .68rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); }
.post-dlg-accts { display: grid; grid-auto-rows: max-content; gap: 6px; margin-bottom: 16px; max-height: 240px; overflow-y: auto; }
.post-acct { display: flex; align-items: center; gap: 10px; padding: 9px 11px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px; background: var(--card); }
.post-acct:has(input:checked) { border-color: var(--accent-border); background: var(--accent-weak); }
.post-acct input { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; flex: none; }
.post-acct-ico { display: grid; place-items: center; color: var(--text); flex: none; }
.post-acct-txt { display: grid; gap: 1px; min-width: 0; }
.post-acct-txt b { font-size: .88rem; font-weight: 620; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.post-acct-txt span { font-size: .74rem; color: var(--text-muted); }
.post-dlg-cap { width: 100%; resize: vertical; min-height: 84px; margin-bottom: 14px; font: inherit; font-size: .88rem; }
.post-dlg-err { margin: -4px 0 14px; font-size: .84rem; color: var(--err); }
.lib-badge { font-size: 0.68rem; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border-hi); color: var(--muted); }
.lib-badge.ok { color: var(--ok); border-color: var(--ok); }
.lib-badge.bad { color: var(--err); border-color: var(--err); }
.lib-badge.pending { color: var(--warn); border-color: var(--warn); }
.lib-card.pending { border-color: rgba(255,181,71,.45); }
/* The clip the preview drawer is currently playing. */
.lib-card.playing {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 22px color-mix(in srgb, var(--accent) 28%, transparent);
}
.lib-card.playing .lib-thumb-wrap::after {
  content: "▶ Playing"; position: absolute; top: 8px; left: 8px; z-index: 2;
  padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--accent); color: var(--on-accent);
  font-size: .64rem; font-weight: 700; letter-spacing: .04em;
}
.lib-approve { margin-top: 9px; width: 100%; padding: 9px 12px; border-radius: 9px; cursor: pointer;
  font: inherit; font-size: 0.82rem; font-weight: 600; color: #0a0c12; border: none; white-space: nowrap;
  background: linear-gradient(135deg, var(--warn), #ffd089); }
.lib-approve:hover { filter: brightness(1.06); }
.lib-approve:disabled { opacity: .6; cursor: default; }
/* when the button is in "save caption" mode, use the neutral accent instead of the post-orange */
.lib-approve.saving { background: var(--card-2); color: var(--text); border: 1px solid var(--cyan); }
.lib-reject { display: block; width: 100%; margin-top: 7px; padding: 2px; background: none; border: none;
  color: var(--err); font: inherit; font-size: 0.78rem; text-decoration: underline; cursor: pointer; text-align: center; }
.lib-reject:hover { filter: brightness(1.15); }
.empty { text-align: center; color: var(--muted); padding: 60px 20px; }

/* ============================ ACCOUNTS ============================ */
.account-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.account-head h2 { margin: 0; }
.conn-badge { font-size: 0.78rem; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border-hi); color: var(--muted); }
.conn-badge.ok { color: var(--ok); border-color: var(--ok); background: rgba(46,230,166,.08); }
.conn-badge.bad { color: var(--err); border-color: rgba(255,93,108,.4); }
.btn-icon { display: inline-flex; align-items: center; gap: 7px; }
.btn-icon .ico { width: 16px; height: 16px; flex: none; }
.acct-rename-wrap { display: inline-flex; align-items: center; gap: 8px; }
.acct-rename-input {
  background: var(--card-2); border: 1px solid var(--cyan); border-radius: 8px;
  color: var(--text); font-size: 0.95rem; padding: 6px 10px; min-width: 180px; outline: none;
  box-shadow: 0 0 0 3px rgba(0,229,255,.12);
}
.acct-rename-input::placeholder { color: var(--faint); }
.row-wrap { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }

.link-inline { color: var(--cyan); text-decoration: underline; cursor: pointer; }
.link-inline:hover { color: #6ff6ff; }

/* ---- onboarding tour (driver.js) — dark neon skin ---- */
.driver-popover.ap-tour {
  background: var(--card-2); color: var(--text);
  border: 1px solid var(--border-hi); border-radius: 14px;
  box-shadow: 0 16px 50px rgba(0,0,0,.6), 0 0 0 1px rgba(0,229,255,.18), 0 0 24px rgba(0,229,255,.12);
  max-width: 330px; padding: 20px 20px 16px;
}
.driver-popover.ap-tour .driver-popover-title { color: var(--text); font-size: 1.08rem; font-weight: 700; margin-bottom: 6px; }
.driver-popover.ap-tour .driver-popover-description { color: var(--muted); font-size: 0.9rem; line-height: 1.55; }
.driver-popover.ap-tour .driver-popover-progress-text { color: var(--faint); font-size: 0.76rem; letter-spacing: .03em; }
.driver-popover.ap-tour .driver-popover-close-btn { color: var(--faint); font-size: 1.4rem; transition: color .15s; }
.driver-popover.ap-tour .driver-popover-close-btn:hover { color: var(--text); }
.driver-popover.ap-tour .driver-popover-footer { margin-top: 14px; gap: 10px; }
.driver-popover.ap-tour .driver-popover-navigation-buttons { gap: 8px; }
.driver-popover.ap-tour .driver-popover-prev-btn,
.driver-popover.ap-tour .driver-popover-next-btn {
  text-shadow: none; border-radius: 10px; padding: 8px 16px; font-weight: 600; font-size: 0.85rem; cursor: pointer;
  transition: box-shadow .15s, color .15s, border-color .15s;
}
.driver-popover.ap-tour .driver-popover-prev-btn { background: transparent; color: var(--muted); border: 1px solid var(--border-hi); }
.driver-popover.ap-tour .driver-popover-prev-btn:hover { color: var(--text); border-color: var(--cyan-dim); }
.driver-popover.ap-tour .driver-popover-next-btn { background: var(--grad); color: #07080d; border: none; }
.driver-popover.ap-tour .driver-popover-next-btn:hover { box-shadow: 0 0 18px rgba(0,229,255,.45); }
/* arrow matches the card colour */
.driver-popover.ap-tour .driver-popover-arrow-side-left.driver-popover-arrow { border-left-color: var(--card-2); }
.driver-popover.ap-tour .driver-popover-arrow-side-right.driver-popover-arrow { border-right-color: var(--card-2); }
.driver-popover.ap-tour .driver-popover-arrow-side-top.driver-popover-arrow { border-top-color: var(--card-2); }
.driver-popover.ap-tour .driver-popover-arrow-side-bottom.driver-popover-arrow { border-bottom-color: var(--card-2); }

/* ---- per-user account onboarding ---- */
.uri-row { display: flex; align-items: stretch; gap: 8px; margin: 6px 0 2px; }
.redirect-uri {
  flex: 1; padding: 9px 12px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--border-hi); color: var(--cyan);
  font-family: ui-monospace, monospace; font-size: 0.8rem; word-break: break-all; user-select: all;
  display: flex; align-items: center;
}
.copy-uri { flex-shrink: 0; align-self: center; }
.acc-msg { margin-top: 10px; }

/* ---- auth gate (login / signup) ---- */
.auth-gate {
  position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center;
  background:
    linear-gradient(rgba(7,8,13,.86), rgba(7,8,13,.96)),
    url("/assets/background.jpg") center / cover no-repeat fixed, var(--bg);
  transition: opacity .3s ease;
}
.auth-gate:not(.hidden) { animation: fadeIn .35s ease both; }
.auth-card {
  width: 360px; max-width: 92vw; padding: 32px 28px; border-radius: 18px;
  background: var(--card); border: 1px solid var(--border-hi); box-shadow: var(--shadow); text-align: center;
  animation: pageIn .5s cubic-bezier(.22,.61,.36,1) both;
}
.auth-brand { display: flex; align-items: center; gap: 10px; font-size: 1.1rem; font-weight: 700; margin-bottom: 18px; }
.auth-brand .brand-glyph { width: 34px; }
.auth-card h1 { font-size: 1.5rem; margin: 0 0 4px; }
.auth-card form { display: flex; flex-direction: column; gap: 10px; margin: 18px 0 8px; }
.auth-card input {
  padding: 12px 14px; border-radius: 10px; border: 1px solid var(--border-hi);
  background: var(--bg); color: var(--text); font-size: 0.95rem;
}
.auth-card input:focus { outline: none; border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }
.auth-card .btn-neon { margin-top: 4px; }
.auth-msg { min-height: 18px; font-size: 0.85rem; margin: 6px 0; color: var(--muted); }
.auth-msg.err { color: var(--err); }
.auth-links { display: flex; flex-direction: column; gap: 8px; align-items: center; margin-top: 6px; }
.small.err, .muted.err { color: var(--err); }

/* create-user modal */
.cu-modal { width: 420px; max-width: 92vw; text-align: left; padding: 26px 26px 22px; }
.cu-modal h2 { margin: 0 0 4px; }
.cu-form { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }
.cu-form label { display: flex; flex-direction: column; gap: 5px; font-size: 0.85rem; color: var(--muted); }
.cu-modal .btn-neon { width: 100%; }
.role-select, .status-select, .plan-select { width: auto; padding: 5px 26px 5px 9px; font-size: 0.82rem; }

/* admin tabs */
.admin-tabs { display: flex; gap: 6px; margin: 4px 0 22px; border-bottom: 1px solid var(--border); }
.admin-tab {
  background: none; border: none; color: var(--muted); cursor: pointer;
  padding: 10px 16px; font-size: 0.92rem; font-weight: 600; position: relative; bottom: -1px;
  border-bottom: 2px solid transparent;
}
.admin-tab:hover { color: var(--text); }
.admin-tab.on { color: var(--text); border-bottom-color: var(--cyan); }

/* admin status badges */
.status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px; font-size: 0.8rem; font-weight: 600; }
.status-badge.active { color: var(--ok); background: rgba(46,230,166,.1); border: 1px solid rgba(46,230,166,.35); }
.status-badge.disabled { color: var(--err); background: rgba(255,93,108,.1); border: 1px solid rgba(255,93,108,.35); }
.status-badge.off { color: var(--muted); background: rgba(140,150,170,.08); border: 1px solid rgba(140,150,170,.25); }
.status-text { font-weight: 600; font-size: 0.85rem; }
.status-text.active { color: var(--ok); }
.status-text.disabled { color: var(--err); }

/* admin action icon buttons */
.icon-btn {
  width: 30px; height: 30px; padding: 0; border-radius: 8px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--card); border: 1px solid var(--border-hi); color: var(--muted);
  transition: color .15s, border-color .15s, box-shadow .15s;
}
.icon-btn svg { width: 16px; height: 16px; }
.icon-btn:hover { color: var(--text); border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }
.icon-btn.saving { color: var(--ok); border-color: var(--ok); }
.icon-btn.danger:hover { color: var(--err); border-color: var(--err); box-shadow: 0 0 12px rgba(255,93,108,.3); }
.icon-btn:disabled { opacity: .5; pointer-events: none; }
.icon-btn.spinning svg { animation: spin .7s linear infinite; }
/* keep the cell as a real table-cell (don't use flex on a <td> — it breaks the row border) */
.admin-actions { white-space: nowrap; }
.admin-actions .icon-btn + .icon-btn { margin-left: 8px; }

/* ---- sidebar user chip ---- */
.user-chip { display: flex; align-items: center; gap: 8px; font-size: 0.78rem; color: var(--muted); }
.user-email { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.logout-btn {
  flex-shrink: 0; background: var(--card); border: 1px solid var(--border-hi); color: var(--muted);
  border-radius: 8px; padding: 5px 9px; cursor: pointer;
}
.logout-btn:hover { color: var(--err); border-color: var(--err); }
.app.collapsed .user-email { display: none; }

/* ---- admin table ---- */
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; table-layout: auto; }
.admin-table th { text-align: left; color: var(--muted); font-weight: 600; padding: 10px; }
.admin-table td { padding: 11px 10px; vertical-align: middle; height: 48px; }
/* one full-width divider per row (on the row, not per-cell, so it always lines up) */
.admin-table thead tr, .admin-table tbody tr { border-bottom: 1px solid var(--border); }
.admin-table tbody tr:last-child { border-bottom: none; }
.admin-table td.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.admin-table tr.is-disabled { opacity: .5; }
.admin-actions { display: flex; gap: 6px; flex-wrap: nowrap; align-items: center; }
.admin-table td .model-id { white-space: nowrap; }
.btn-ghost.mini { padding: 5px 10px; font-size: 0.78rem; }
/* .mini existed only for the ghost button, so a `btn-neon mini` rendered at full size beside
   the small ghosts it was meant to sit with — which is how the angle editor's Done ended up
   twice the height of the Cancel next to it. */
.btn-neon.mini { padding: 5px 12px; font-size: 0.78rem; }
.btn-ghost.mini.danger { color: var(--err); border-color: rgba(255,93,108,.4); }

/* ============================== SETUP GUIDE DOCK ============================== */
.guide-dock {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 150;
  width: min(46vw, 560px); display: flex; flex-direction: column;
  background: var(--card); border-left: 1px solid var(--border-hi);
  box-shadow: -12px 0 40px rgba(0,0,0,.5);
  transform: translateX(100%); transition: transform .28s ease; will-change: transform;
}
.guide-dock.open { transform: translateX(0); }
.guide-dock-head {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
}
.guide-dock-title { font-size: 0.9rem; font-weight: 600; color: var(--text); }
.guide-dock-actions { display: flex; gap: 8px; }
.guide-frame { flex: 1 1 auto; width: 100%; border: 0; background: #f7f8fb; }
/* nudge the main content left while the guide is docked, so nothing hides under it */
.app.guide-open .main { margin-right: min(46vw, 560px); transition: margin-right .28s ease; }
@media (max-width: 900px) {
  .guide-dock { width: 100vw; }
  .app.guide-open .main { margin-right: 0; }
  /* too narrow for pickers | references side by side → stack them */
  .home-grid { grid-template-columns: 1fr; }
  .ref-panel .anchor-drops { max-height: none; }
}

/* ============================== TOAST ============================== */
.toast {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(20px);
  background: var(--card-2); border: 1px solid var(--border-hi); color: var(--text);
  padding: 12px 20px; border-radius: 12px; box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; transition: all .25s; z-index: 100; max-width: 90vw;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.ok { border-color: var(--ok); }
.toast.err { border-color: var(--err); }

/* ============================== MODAL ============================== */
.modal-overlay {
  position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center;
  background: rgba(3,4,8,.72); backdrop-filter: blur(6px); padding: 24px; animation: fadeIn .2s ease;
}
.modal-card {
  position: relative; background: var(--card); border: 1px solid var(--border-hi);
  border-radius: var(--radius); box-shadow: var(--shadow); max-width: 560px; width: 100%;
  max-height: 88vh; overflow: auto; animation: cardIn .25s ease;
}
.modal-close {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
  background: rgba(0,0,0,.5); border: 1px solid var(--border-hi); color: var(--text); font-size: 0.9rem;
}
.modal-close:hover { border-color: var(--cyan-dim); box-shadow: var(--glow-cyan); }
.modal-body { padding: 0; }

/* ---- Edit references (modal) ----------------------------------------------------------------
   The panel inside is the REAL #refPanel, on loan from Setup — so it keeps its own chrome and
   this only supplies the frame around it. .in-modal drops the card look it needs on Setup, where
   it sits beside a second column; here it IS the card. */
.modal-card:has(.refm) { max-width: 620px; }
.refm { display: flex; flex-direction: column; gap: 14px; padding: 22px; }
.refm h3 { margin: 0; padding-right: 34px; font-size: 1.05rem; }
.refm .ref-panel.in-modal { background: none; border: 0; border-radius: 0; box-shadow: none; padding: 0; }
.refm .in-modal .anchor-head-label, .refm .in-modal .ref-opt { display: none; }
.refm .in-modal .ref-count { margin-left: 0; }
.refm-wait, .refm-none, .refm-err { display: block; padding: 26px 4px; text-align: center; font-size: .86rem; color: var(--muted); line-height: 1.6; }
.refm-err { color: var(--err); }
.refm-foot { display: flex; align-items: center; gap: 10px; padding-top: 4px; border-top: 1px solid var(--border); }
.refm-note { flex: 1; min-width: 0; font-size: .76rem; color: var(--faint); }


/* media preview */
.modal-media video, .modal-media img {
  width: 100%; display: block; background: #000; max-height: 70vh; object-fit: contain;
  border-radius: var(--radius) var(--radius) 0 0;
}
.modal-media .modal-caption { padding: 14px 18px; color: var(--muted); font-size: 0.86rem; }

/* ---- clip preview drawer: right-hand panel, Video feed + Settings tabs ---- */
.clip-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 150;
  width: min(96vw, 440px); display: flex; flex-direction: column;
  background: var(--card); border-left: 1px solid var(--border-hi);
  box-shadow: -12px 0 40px rgba(0,0,0,.5);
  transform: translateX(100%); transition: transform .28s ease; will-change: transform;
}
.clip-drawer.open { transform: translateX(0); }
/* Reserve the drawer's width (same trick as .app.guide-open) so the grid REFLOWS into what's
   left. Collapsing the sidebar alone made it worse: the extra width let auto-fill add a fifth
   column, which then sat underneath the drawer. */
.app.clip-open .main { margin-right: min(96vw, 440px); transition: margin-right .28s ease; }
@media (max-width: 820px) {
  .app.clip-open .main { margin-right: 0; }   /* drawer is near-full-width here */
}
/* Head is title + up to three buttons. NOT space-between: with four children that spreads the
   free space across all three gaps, so approve/reject/close drift apart into the middle of the
   header instead of reading as one action cluster — and the spacing shifts again whenever
   approve/reject are hidden. The title takes the slack instead, so the buttons stay grouped
   hard right whichever of them is showing. */
.clip-drawer-head {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: flex-start; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.clip-drawer-head h2 {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 1rem;
}
.clip-drawer-head h2 svg { width: 17px; height: 17px; color: var(--muted); flex: none; }
.clip-count-pill {
  font-family: var(--font-mono); font-size: .66rem; padding: 3px 7px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--muted);
}
.clip-tabs {
  flex: 0 0 auto; display: flex; gap: 4px; margin: 12px 16px;
  padding: 4px; border-radius: var(--r-md); background: var(--surface-2);
}
.clip-tab {
  flex: 1; cursor: pointer; padding: 7px 12px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--muted); font: inherit; font-size: .85rem; font-weight: 600;
  transition: background .16s ease, color .16s ease;
}
.clip-tab:hover { color: var(--text); }
.clip-tab.on { background: var(--card); color: var(--text); box-shadow: var(--shadow-card); }

/* The feed itself: one clip per "page", snapping like a reels scroller. */
.clip-feed {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  scroll-snap-type: y mandatory; background: #000;
}
.clip-feed::-webkit-scrollbar { width: 0; }        /* the snap points are the affordance */
.clip-slide {
  height: 100%; scroll-snap-align: start; scroll-snap-stop: always;
  display: flex; align-items: center; justify-content: center; background: #000;
}
.clip-slide video { width: 100%; max-height: 100%; display: block; object-fit: contain; background: #000; }

.clip-settings { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 4px 16px 20px; }
.clip-rows { margin: 0; display: grid; gap: 2px; }
.clip-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 10px 0; border-bottom: 1px solid var(--border);
}
.clip-row:last-child { border-bottom: 0; }
.clip-row dt { font-size: .84rem; color: var(--muted); }
.clip-row dd { margin: 0; font-size: .84rem; color: var(--text); text-align: right; word-break: break-word; }
.clip-block { margin-top: 18px; }
.lib-tab-skel { display: inline-block; width: 18px; height: 10px; border-radius: 4px; vertical-align: -1px; }
.clip-chip { display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  font-size: .72rem; font-weight: 600; vertical-align: 1px;
  background: var(--sidebar-raised); color: var(--text-muted); }
.clip-chip.auto { background: var(--accent-weak); color: var(--accent); }
.clip-block h4 {
  margin: 0 0 6px; font-size: .66rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint);
}
.clip-block p { margin: 0; font-size: .84rem; line-height: 1.6; color: var(--text); }
.clip-prompt { color: var(--muted); font-size: .8rem; }

/* run summary */
.modal-summary { padding: 22px; }
.modal-summary h3 { margin: 0 0 14px; font-size: 1.05rem; }
.sum-row { display: flex; gap: 14px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.sum-row:last-child { border-bottom: none; }
.sum-row .k { color: var(--muted); flex-shrink: 0; width: 110px; font-size: 0.82rem; }
.sum-row .v { color: var(--text); flex: 1; font-size: 0.88rem; word-break: break-word; }
.sum-row .v.mono { white-space: pre-wrap; line-height: 1.5; }
/* runDetailRows() emits these, and it now feeds the clip drawer as well as this modal. */
.sum-row .v .ok, .clip-row dd .ok { color: var(--ok); }
.sum-row .v .bad, .clip-row dd .bad { color: var(--err); }
.clip-row dd .muted { color: var(--muted); }

/* ============================ RESPONSIVE ============================ */
@media (max-width: 760px) {
  /* Never let a stray-wide element scroll the whole page sideways (was clipping page titles on the left) */
  html, body { overflow-x: hidden; max-width: 100%; }
  /* Page titles that carry an inline workspace dropdown shrink + wrap on phones */
  .lib-title { font-size: 1.7rem; }
  /* Notifications take the page, like the nav drawer — the list is the whole reason the screen
     was opened, and a 74vh card floating over a dimmed page was showing eight rows in the space
     that fits fourteen. Starts below the header so the bell that opened it stays reachable. */
  .notif-drop { position: fixed; top: 52px; left: 0; right: 0; bottom: 0; width: auto;
    max-height: none; border-radius: 0; border-left: 0; border-right: 0; border-bottom: 0;
    display: flex; flex-direction: column; z-index: 75; }
  .notif-list { flex: 1 1 auto; min-height: 0; max-height: none; }
  .notif-head { flex: none; padding: 14px 16px; }
  .notif-x { display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; margin-left: 2px; margin-right: -6px; padding: 0; border: 0; border-radius: 9px;
    background: none; color: var(--muted); cursor: pointer; flex: none; }
  .notif-x svg { width: 18px; height: 18px; }
  .notif-x:active { background: var(--accent-weak); color: var(--accent); }
  /* ---- nav: an off-canvas DRAWER, not a bottom icon strip ----
     Seven destinations plus Manage plus the credits button shared one row with every label
     hidden, so the bar was eight unlabelled glyphs and the word "MANAGE" wedged between them.
     A drawer gives each one its name back and costs one tap. The sidebar keeps its desktop
     column layout inside it — nothing about the items changes, only where the column lives. */
  /* Full width, starting BELOW the 52px header — so the ✕ that closes it and the brand stay on
     screen while it is open, which is where the eye already is. A drawer that covers its own
     close button has to grow a second one. */
  .sidebar { position: fixed; top: 52px; bottom: 0; left: 0; right: 0; width: 100%;
    height: auto; flex-direction: column; align-items: stretch; z-index: 70;
    border-right: 0; border-top: 1px solid var(--border);
    /* Credits sits at the very bottom of this panel, which on a phone is the very bottom of the
       screen — where the home indicator lives. */
    padding-bottom: calc(18px + env(safe-area-inset-bottom));
    transform: translateX(-100%); transition: transform .26s cubic-bezier(.22,.61,.36,1); }
  .app.nav-open .sidebar { transform: translateX(0); }
  .app.collapsed .sidebar { width: 100%; }   /* desktop collapse has no meaning here */
  /* No scrim: at full width there is nothing behind it to dim, and a scrim under an opaque
     panel is a layer that can only ever be wrong about pointer events. */
  .nav-scrim { display: none; }
  /* The brand moves into the header beside the hamburger (see relocateBrand) — inside the
     drawer it would only be visible once the drawer is already open. */
  .topbar .brand { display: flex; padding: 0; margin: 0 auto 0 2px; width: auto; gap: 8px; }
  .topbar .brand-name { font-size: 1rem; }
  /* relocateBrand() moves the node into the header; this only covers the frame before that
     runs, so the brand never flashes at the top of the drawer on the way. */
  .sidebar > .brand { display: none; }
  .nav { padding-top: 8px; }
  .nav-item { padding: 13px 16px; }          /* a phone target, not a 28px desktop row */
  .nav-item .lbl { display: inline; }
  /* The brand beside it now carries the `margin-right: auto` that pushes the right-hand cluster
     over; leaving it on both would put a gap between the button and the name it labels. */
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; flex: none; padding: 0; border: 0; border-radius: 10px;
    background: none; color: var(--text-muted); cursor: pointer; }
  .nav-toggle svg { width: 21px; height: 21px; }
  .nav-toggle:active { background: var(--accent-weak); color: var(--accent); }
  /* The topbar spans the full width — the drawer is over the page, not beside it. */
  .topbar, .app.collapsed .topbar { left: 0; padding: 0 10px; }
  /* Clears the 52px fixed header, and the tab bar at the other end — plus the home indicator
     under it, which is not part of the bar's own height. */
  .main { padding: 66px 16px calc(84px + env(safe-area-inset-bottom)); }
  /* Same gutter as .main above — 2.5% of a phone is 9px, which reads as no margin at all. */
  .setup-foot, .wizard-nav { padding-left: 16px; padding-right: 16px; }
  /* FROM THE LEFT EDGE on a phone. The bar kept the desktop's sidebar offset (220px) and slid
     half off the screen: "Next" cut to "Ne", the estimate to "ESTIMAT" (launch audit,
     2026-10-12). The drawer is over the page here, not beside it — the same as the topbar. */
  .setup-foot, .wizard-nav, .app.collapsed .setup-foot, .app.collapsed .wizard-nav {
    left: 0; padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
  /* The step title runs under the ✕ in the corner: leave it its room. */
  .ask-title { padding-right: 44px; }
  /* The estimate gets its own line above the buttons: with Back, Start and its menu beside it
     there was no width left, and it read "EST". */
  .setup-foot .bar-inner, .wizard-nav .bar-inner { flex-wrap: wrap; row-gap: 8px; }
  .setup-foot .est-inline, .wizard-nav .est-inline { flex: 1 1 100%; min-width: 0; }
  /* Seven days on one line on a phone: at full size Sunday wrapped to a row of its own. */
  #wDayCircles { gap: 6px; flex-wrap: nowrap; }
  #wDayCircles > .day-circle { width: 38px; height: 38px; min-width: 0; flex: 0 0 38px; font-size: 13px; }
  /* …so the page scrolls its last field clear of that taller bar. */
  .app:has(.view-setup.active) .main,
  .app:has(.view-ask.active:not(.picking)) .main { padding-bottom: calc(150px + env(safe-area-inset-bottom)); }

  /* The chevrons had to scroll sideways on a phone — five of them could not share the width and
     the middle three vanished. A rail of five 3px segments fits any width there is. */
  .wiz-steps, .home-steps { max-width: none; width: 100%; }

  /* ---- home: stat CARDS, workspace ROWS ---------------------------------------------------
     The stats were one strip divided by hairlines, which reads as a table on a wide screen and
     as four stacked fragments on a narrow one. Four cards say "four separate facts" at any
     width. */
  .home-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
    background: none; border: 0; padding: 0; }

  /* A phone shows one card per row anyway, so a 150px-tall box with its content in a column is
     mostly empty space — and four of them is one workspace per screen. As a row, the same
     facts fit on two lines and eight fit on a screen. */
  .ws-picker-grid { grid-template-columns: 1fr; gap: 0; }
  .wsp-card { flex-direction: row; align-items: center; gap: 12px; min-height: 0;
    padding: 14px 4px; border: 0; border-radius: 0; background: none; box-shadow: none;
    border-bottom: 1px solid var(--border); overflow: visible; }
  .wsp-card:hover { transform: none; box-shadow: none; border-color: var(--border); }
  .wsp-id { flex: 1 1 auto; min-width: 0; }
  .wsp-avatar { width: 44px; height: 44px; border-radius: 12px; font-size: 1rem; }
  .wsp-name { font-size: .98rem; }
  /* Status, count and age become one line under the name — the mock's second row. */
  .wsp-status { position: static; order: 2; padding: 0; background: none; border: 0; }
  .wsp-bar, .wsp-gen-step, .wsp-targets { display: none; }

  /* the ⋯ menu rules live at the END of this file — see there for why */
  /* The close ✕ overlays the row; on a scrolling bar it would sit on top of the last step. */
  .home-steps-row { padding-right: 34px; }

  /* The update banner is centred at top:14px, which on a phone is exactly where the header's
     account menu and the new hamburger are — it covered both, and its own text wrapped to four
     lines inside a pill sized for one. Below the header, and wide enough to read. */
  .update-bar { top: 60px; left: 10px; right: 10px; transform: none;
    border-radius: 12px; justify-content: space-between; }
  .hero { flex-direction: column; text-align: center; gap: 14px; }
  .hero-right { flex-direction: row; }
  /* Wide admin tables scroll horizontally (with a min-width) instead of squishing columns off-screen */
  #adminUsers, #adminModels, #adminPricing, .log-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .admin-table { min-width: 560px; }
  /* Tabs stay on one row and swipe instead of wrapping awkwardly */
  .admin-tabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .admin-tabs::-webkit-scrollbar { display: none; }
  /* Workspace stat tiles: on a phone the single row is unreadable — go back to separate
     tiles, 2 per row, and swap the column dividers for per-tile borders. */
  .stats-row { grid-template-columns: repeat(2, 1fr) !important;
    gap: 12px; background: none; border: 0; border-radius: 0; overflow: visible; }
  .stat { border: 1px solid var(--border); border-radius: 12px; }
  /* Big Home title is too large on phones */
  .ask-title { font-size: 1.7rem; margin-bottom: 16px; }
  /* Reference rows: drop the fixed label column so the category name gets the width it needs */
  .anchor-cat-head { flex: 0 0 auto; }
  /* Config/summary rows: label above a full-width value (side-by-side crams long text into a narrow column) */
  .cfg-row, .sum-row { flex-direction: column; gap: 3px; }
  .cfg-k, .sum-row .k { flex: none; width: auto; }
  /* Activity items: thumbnail + time/tag on top, full-width text below (side-by-side crams the text) */
  .feed-item { flex-wrap: wrap; align-items: center; row-gap: 8px; }
  .feed-thumb { width: 60px; height: 80px; }
  .feed-side { margin-left: auto; }
  .feed-item .body { flex: 1 1 100%; order: 5; }
  .feed-actions, .feed-del { opacity: .6; }   /* no hover on touch — keep actions visible */
  /* Section headers (accounts / workspaces): title above the action button, not a cramped/​wrapping row */
  .ap-head { flex-direction: column; align-items: stretch; gap: 12px; }
  .ap-head .btn-neon { white-space: nowrap; }
  /* Settings rows: label + description above the control (side-by-side squeezes the description word-per-line) */
  /* Keep info on the left (description stays in its column, not full-width) and the control on the
     right. Only the username row stacks, since its input wants the full width. */
  .set-row { gap: 14px; padding: 14px 16px; }
  .set-row:has(.set-profile) { flex-direction: column; align-items: stretch; }
  .set-profile { display: flex; gap: 10px; }
  .set-profile .select { flex: 1; min-width: 0; }
  /* Accounts + credits-pricing tables scroll inside their box instead of overflowing the whole page */
  #accountsWrap, #credPricing { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* Very narrow: stack the admin tables into cards (cleaner than side-scrolling).
   Users, Models and Pricing all qualify — an eight-column table on a 390px screen is a table
   nobody reads, they scroll it sideways until they give up. The log tables deliberately do NOT:
   they are read by scanning a column down (times, statuses, errors), which is the one thing
   cards destroy, and a run history of 50 rows would become 50 cards. Those keep their scroll. */
@media (max-width: 560px) {
  #adminUsers, #adminModels, #adminPricing { overflow-x: visible; }
  #adminUsers .admin-table, #adminModels .admin-table, #adminPricing .admin-table { min-width: 0; }
  #adminUsers .admin-table thead, #adminModels .admin-table thead, #adminPricing .admin-table thead { display: none; }
  #adminUsers .admin-table, #adminModels .admin-table, #adminPricing .admin-table,
  #adminUsers .admin-table tbody, #adminModels .admin-table tbody, #adminPricing .admin-table tbody,
  #adminUsers .admin-table td, #adminModels .admin-table td, #adminPricing .admin-table td { display: block; width: 100%; }
  /* flex column rather than block, so `order` can lift the row's name to the top of its own card
     — the identity is the last thing that should be buried mid-list. */
  #adminUsers .admin-table tr, #adminModels .admin-table tr, #adminPricing .admin-table tr {
    display: flex; flex-direction: column; width: 100%;
    border: 1px solid var(--border); border-radius: 12px;
    padding: 4px 12px; margin-bottom: 12px; background: var(--card); }
  #adminUsers .admin-table td, #adminModels .admin-table td, #adminPricing .admin-table td {
    border: none; height: auto; padding: 8px 0;
    display: flex; justify-content: space-between; align-items: center; gap: 12px; text-align: right; }
  #adminUsers .admin-table td::before, #adminModels .admin-table td::before, #adminPricing .admin-table td::before {
    content: attr(data-label); color: var(--muted);
    font-size: .78rem; font-weight: 600; flex: none; text-align: left; }
  #adminUsers .admin-table td.admin-actions, #adminModels .admin-table td.admin-actions {
    justify-content: flex-start; flex-wrap: wrap; gap: 6px; }
  #adminUsers .admin-table td.admin-actions::before,
  #adminModels .admin-table td.admin-actions::before { margin-right: auto; }   /* label left, buttons right */

  /* ---- Users: identity in the list, the rest on tap ---- */
  #adminUsers .admin-table tr { cursor: pointer; }
  #adminUsers .admin-table tr:not(.is-open) > td[data-label="Role"],
  #adminUsers .admin-table tr:not(.is-open) > td[data-label="Plan"],
  #adminUsers .admin-table tr:not(.is-open) > td[data-label="Workspace"],
  #adminUsers .admin-table tr:not(.is-open) > td[data-label="Status"],
  #adminUsers .admin-table tr:not(.is-open) > td.admin-actions { display: none; }
  /* Name over email, as a heading — not two labelled fields called "User" and "Email", which is
     the table's phrasing and says nothing a person reading a list of people needs told. */
  #adminUsers .admin-table td[data-label="User"] {
    order: -2; justify-content: flex-start; text-align: left; gap: 8px;
    padding: 12px 0 2px; font-size: .95rem; font-weight: 700; }
  #adminUsers .admin-table td[data-label="Email"] {
    order: -1; justify-content: flex-start; text-align: left;
    padding: 0 0 12px; color: var(--muted); font-size: .8rem; }
  #adminUsers .admin-table td[data-label="User"]::before,
  #adminUsers .admin-table td[data-label="Email"]::before { content: none; }
  /* The identity block keeps its own line once the rest is showing, so the fields below read as
     belonging to it rather than continuing it. */
  #adminUsers .admin-table tr.is-open td[data-label="Email"] {
    border-bottom: 1px solid var(--border); }
  #adminUsers .admin-table td[data-label="User"]::after {
    content: "\203A"; margin-left: auto; flex: none; color: var(--faint);
    font-size: 1.15rem; line-height: 1; transform: rotate(90deg);
    transition: transform .18s ease; }
  #adminUsers .admin-table tr.is-open td[data-label="User"]::after { transform: rotate(-90deg); }

  /* The card's heading: the name, first and without a label repeating what it obviously is. */
  #adminModels .admin-table td.cell-title, #adminPricing .admin-table td.cell-title {
    order: -1; justify-content: flex-start; text-align: left;
    padding: 10px 0 8px; font-size: .95rem; font-weight: 700; flex-wrap: wrap; }
  #adminModels .admin-table td.cell-title::before,
  #adminPricing .admin-table td.cell-title::before { content: none; }
  #adminPricing .admin-table td.cell-title { border-bottom: 1px solid var(--border); }

  /* ---- Models: the same bargain as Users ---- */
  /* Eight fields per model, and seven of them are things you look up when you are already
     interested in that model. The name is what you scan the list for. */
  #adminModels .admin-table tr { cursor: pointer; }
  #adminModels .admin-table tr:not(.is-open) > td:not(.cell-title) { display: none; }
  #adminModels .admin-table tr.is-open > td.cell-title { border-bottom: 1px solid var(--border); }
  #adminModels .admin-table td.cell-title::after {
    content: "\203A"; margin-left: auto; flex: none; color: var(--faint);
    font-size: 1.15rem; line-height: 1; transform: rotate(90deg);
    transition: transform .18s ease; }
  #adminModels .admin-table tr.is-open td.cell-title::after { transform: rotate(-90deg); }
  /* A disabled model still has to be findable while the row is shut, and its own row styling
     (opacity) is the only thing left saying so. */
  #adminModels .admin-table tr.is-disabled { opacity: .55; }
  /* A number box that fills the row is easier to hit than a 78px one floating at its end. */
  #adminPricing .admin-table .price-in { width: 110px !important; text-align: right; }

  /* The log tables stay tabular, so say so: an edge-to-edge scroller with no visible cut looks
     like a table that is simply missing columns. */
  .log-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .log-scroll .admin-table { min-width: 560px; }
}

/* respect the user's OS-level "Reduce Motion" accessibility setting */
@media (prefers-reduced-motion: reduce) {
  *, *::after, *::before { animation: none !important; transition: none !important; }
}


/* ============ Step 2-4 shell: same language as Setup ============ */
/* .wcard is just a step container now — the panels inside carry the card styling
   (the .card visual was dropped from the markup; .wcard.show keeps the cardIn animation) */
.side-panel {
  display: flex; flex-direction: column; gap: 12px; padding: 14px; min-width: 0;
  background: linear-gradient(180deg, rgba(22,25,39,.66), rgba(17,19,28,.5));
  border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow);
}
.preview-badge { margin-left: auto; font-size: .72rem; font-weight: 700; color: var(--cyan); white-space: nowrap; }

/* the frame itself takes the chosen aspect ratio and animates between them */
.preview-stage { display: flex; align-items: center; justify-content: center; height: 202px; padding: 6px 0; }
/* fixed height + aspect-ratio drives the width, so switching ratios animates without
   the panel jumping (height:100% here would be circular inside a content-sized flex box) */
.preview-frame {
  height: 190px; width: auto; max-width: 100%; border-radius: 10px;
  background: repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 10px, rgba(255,255,255,.02) 10px 20px);
  border: 1px solid var(--border-hi);
  transition: aspect-ratio .28s cubic-bezier(.22,.61,.36,1), max-width .28s cubic-bezier(.22,.61,.36,1);
}
.preview-specs { display: grid; grid-template-columns: auto 1fr; gap: 7px 14px; margin: 0; font-size: .8rem; }
.preview-specs dt { color: var(--muted); }
.preview-specs dd { margin: 0; color: var(--text); text-align: right; font-weight: 600; }
.preview-specs dd.accent { color: var(--cyan); }

/* upcoming post times on the Posting step */
.sched-times { display: flex; flex-wrap: wrap; gap: 6px; }
.sched-time { font-size: .74rem; padding: 4px 9px; border-radius: 999px;
  background: var(--card-2); border: 1px solid var(--border); color: var(--muted); }
.sched-time.first { color: var(--cyan); border-color: var(--cyan-dim); }

/* radio cards — a labelled choice reads faster than a bare dropdown */
.opt-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; }
.opt-card {
  display: flex; flex-direction: column; gap: 2px; padding: 9px 11px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px; background: var(--card);
  color: var(--text); font: inherit; text-align: left; transition: border-color .15s, background .15s;
}
.opt-card:hover { border-color: var(--border-hi); }
/* Blue, not cyan: the accent is what "chosen" looks like everywhere else on this page — the
   Next button, the picked style card, the progress bar — and a second highlight colour on one
   screen reads as a second kind of selection. */
.opt-card.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); }
/* Two markups for the same two things: the wizard writes the -t/-d spans, the brief writes
   plain <b> and <span>. Both are styled rather than one being rewritten to match the other. */
.opt-card-t, .opt-card > b { font-size: .88rem; font-weight: 700; line-height: 1.3; }
.opt-card.on .opt-card-t, .opt-card.on > b { color: var(--accent); }
.opt-card-d, .opt-card > span { font-size: .68rem; color: var(--faint); line-height: 1.35; }

/* The asks' choices are bare labels with no explanatory half, so they pack tighter. */
.ask-cards { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 6px; }
.ask-cards .opt-card { padding: 7px 10px; }
/* THE OTHER CELL IS A CARD THAT HAPPENS TO TAKE TYPING. Same box, same track, same height as
   the two it sits beside — the point of the pattern is that a typed answer is not somewhere
   else from a picked one. */
/* Dashed, not solid: the empty slot is not one of the answers, it is the offer to write one —
   a solid card the colour of the others would read as a third choice called "Something else",
   which is not a thing anyone's product is. It stays in the page's quiet ink until the pointer
   is on it: accent is what CHOSEN looks like here, and an untouched slot has chosen nothing. */
.ask-cards .ask-other-card { border-style: dashed; border-color: var(--border); }
.ask-cards .ask-other-card > b { color: var(--muted); font-weight: 700; }
.ask-cards .ask-other-card:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, transparent); }
.ask-cards .ask-other-card:hover > b { color: var(--accent); }
/* SAME BOX METRICS AS THE CARD BESIDE IT. The cell is a grid item in the same row, so anything
   that makes it a pixel taller makes every card in that row taller — the row visibly grew the
   moment you clicked it. The input therefore carries the card's own type (.88rem/1.3) and no
   padding of its own, and the cell carries the card's padding. */
.ask-cards .ask-other-cell {
  flex-direction: row; align-items: center; gap: 4px; padding: 7px 6px 7px 10px; cursor: text;
}
/* An empty box is not an answer: it lights up like a picked card only once something is in it
   (or while it is being typed into), so a row with nothing typed still reads as unanswered —
   which it is, and its MISSING tag says so two lines above. */
.ask-cards .ask-other-cell:focus-within,
.ask-cards .ask-other-cell:has(input:not(:placeholder-shown)) {
  border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent);
}
/* The typed answer is set like the label on the card next to it — same size, same weight, same
   accent — because it IS the same answer, only arrived at by typing. */
/* The typed answer is text someone wrote, not a label we printed: plain weight and the page's
   normal ink, so it reads as their words sitting in the slot. */
.ask-other-cell input {
  flex: 1; min-width: 0; border: 0; background: transparent; color: var(--text);
  font: inherit; font-size: .88rem; font-weight: 500; line-height: 1.3; padding: 0;
  height: auto;
}
/* The global `input:focus` rule paints a border colour AND a cyan glow that follows the input's
   own border-radius — inside a cell that already IS the box, that drew a second rounded ring
   inside the first. The cell carries the focus state (see :focus-within above); the input
   carries none of its own. */
.ask-other-cell input, .ask-other-cell input:focus {
  outline: none; box-shadow: none; border: 0; border-radius: 0;
}
.ask-other-cell input::placeholder { color: var(--faint); font-weight: 400; }
/* Kept inside the line box it sits in, for the same reason: a 20px button in an 18px row is
   two pixels of extra height on every card beside it. */
.ask-other-x {
  flex: none; width: 18px; height: 18px; padding: 0; border: 0; border-radius: 5px;
  background: transparent; color: var(--faint); font-size: 14px; line-height: 1; cursor: pointer;
}
.ask-other-x:hover { color: var(--text); background: var(--card-2); }

/* The brief's two rows carry a title AND a line of explanation, so they need a wider track than
   the wizard's bare tiles: at 96px "However many the story needs" became four lines and dragged
   all six of its siblings to that height. Four across, two rows for the seven cast options. */
#pfObjectiveCards, #pfCastCards { grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); }

@media (max-width: 900px) { .step-grid { grid-template-columns: 1fr; } }

/* ===== Plan gating: destination list + lock panel + plan badge ===== */
.dest-list { display: flex; flex-direction: column; gap: 8px; }
.dest-opt {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--border);
  border-radius: 12px; background: var(--card);
}
.dest-opt .dest-ico {
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  font-weight: 800; color: var(--muted);
}
.dest-opt .dest-ico svg { width: 20px; height: 20px; }
.dest-opt .dest-name { flex: 1; font-weight: 600; }
.dest-opt.active {
  border-color: var(--cyan);
  box-shadow: var(--glow-cyan, 0 0 0 1px rgba(0,229,255,.5), 0 0 18px rgba(0,229,255,.28));
}
.dest-opt.active .dest-name, .dest-opt.active .dest-ico { color: var(--cyan); }
.dest-opt .dest-tag {
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--cyan); border: 1px solid var(--cyan); border-radius: 999px; padding: 2px 8px;
}
/* A row that is an invitation, not a state. The locked variant below says "you cannot have
   this"; this one says "one click and it is yours", so it has to look pressable — and its tag
   stays quiet until then, because nothing here is selected yet. */
.dest-opt.goto-accounts { cursor: pointer; }
.dest-opt.goto-accounts .dest-tag { color: var(--text-faint); border-color: var(--border-strong); }
.dest-opt.goto-accounts:hover, .dest-opt.goto-accounts:focus-visible {
  border-color: var(--border-strong); background: var(--surface-2); outline: none; }
.dest-opt.goto-accounts:hover .dest-tag, .dest-opt.goto-accounts:focus-visible .dest-tag {
  color: var(--cyan); border-color: var(--cyan); }

.dest-opt.locked { opacity: .5; color: var(--muted); cursor: not-allowed; }
.dest-opt.locked .dest-name { color: var(--muted); font-weight: 500; }
.dest-opt .dest-lock { margin-left: auto; font-size: .95rem; }

.lock-panel {
  text-align: center; max-width: 520px; margin: 8px auto; padding: 28px 22px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--card);
}
.lock-panel-ico { font-size: 2rem; margin-bottom: 6px; }
.lock-panel h3 { margin: 6px 0 10px; }

/* Plan cell (admin table) — understated text to match the Role (plain) and Status (.status-text) cells */
.plan-text { font-weight: 600; font-size: 0.85rem; text-transform: capitalize; }
.plan-text.paid { color: var(--ok); }
.plan-text.free { color: var(--muted); }

/* Plan pill — used in the Accounts-page callout banner (a badge suits that context) */
.plan-badge {
  display: inline-block; font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; padding: 2px 9px; border-radius: 999px; border: 1px solid var(--border-hi);
  color: var(--muted);
}
.plan-badge.paid { color: var(--ok); border-color: var(--ok); }
.plan-badge.free { color: var(--muted); }

/* ===== Accounts page =========================================================
   Two faces of one page: a FREE plan sells the upgrade (hero → current plan →
   locked destinations), a PAID plan manages connections (one group per
   platform, each a list of account rows). Shared atoms first. */

/* -- shared atoms -- */
.acct-tile {                                   /* rounded icon plate */
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-muted);
}
.acct-tile .plat-ico { width: 22px; height: 22px; }
.acct-tile.accent { background: var(--accent-weak); border-color: var(--accent-border); color: var(--accent); }

.acct-row-main { flex: 1; min-width: 0; }
.acct-row-top { display: flex; align-items: center; gap: 8px; }
.acct-row-top b { font-size: .94rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-row-sub { font-size: .8rem; color: var(--text-muted); margin-top: 2px; }
.acct-row-meta { font-family: var(--font-mono); font-size: .76rem; color: var(--text-faint); margin-top: 3px; }

.acct-pill {                                   /* "Default" / "Connected" tag */
  flex: none; font-size: .68rem; font-weight: 700; letter-spacing: .02em;
  padding: 2px 8px; border-radius: var(--r-pill);
  background: var(--accent-weak); border: 1px solid var(--accent-border); color: var(--accent);
}
.acct-pill.ok { background: var(--ok-weak); border-color: var(--ok); color: var(--ok); }

.acct-feats { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.acct-feats li { display: flex; align-items: center; gap: 9px; font-size: .86rem; color: var(--text-muted); }
.acct-feats .ico-check { flex: none; width: 14px; height: 14px; color: var(--ok); }
.acct-feats.hero li { color: var(--text); }

.ico-check { width: 1em; height: 1em; display: inline-block; vertical-align: -0.12em; }
.ico-chev { width: 15px; height: 15px; display: inline-block; vertical-align: -0.18em; margin-left: 2px; }

/* -- free plan: upgrade hero -- */
.acct-hero {
  position: relative; overflow: hidden;
  display: flex; align-items: flex-start; gap: 18px;
  padding: 24px 26px; margin-bottom: 26px;
  border: 1px solid var(--accent-border); border-radius: var(--r-lg);
  background: linear-gradient(135deg, var(--accent-weak) 0%, var(--surface) 62%);
  box-shadow: var(--shadow-card);
}
.acct-hero-ico {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: var(--r-md);
  background: var(--accent); color: var(--on-accent); box-shadow: var(--shadow-accent);
}
.acct-hero-ico svg { width: 24px; height: 24px; }
.acct-hero-body { flex: 1; min-width: 0; }
.acct-hero-title {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -.02em;
  font-size: 1.42rem; line-height: 1.22; margin: 0 0 16px;
}
.acct-hero-cta { margin-top: 20px; }
.acct-hero-art {                               /* faint platform glyphs, decorative */
  position: absolute; right: 26px; bottom: -14px;
  display: flex; gap: 14px; color: var(--accent); opacity: .13; pointer-events: none;
}
.acct-hero-art .plat-ico { width: 92px; height: 92px; }
.acct-hero-art .plat-ico:first-child { transform: rotate(-12deg); }
.acct-hero-art .plat-ico:last-child { transform: rotate(9deg); }

/* -- section heading -- */
.acct-sec {
  font-family: var(--font-mono); font-size: .72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em; color: var(--text-faint);
  margin: 0 0 10px;
}
.acct-sec + * { margin-bottom: 26px; }

/* -- free plan: the Email row you already have -- */
.acct-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface);
}
.acct-row.current { border-color: var(--accent-border); }
.acct-check {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--ok); color: #04120c;
}
.acct-check .ico-check { width: 12px; height: 12px; }

/* -- free plan: locked destination cards -- */
.acct-lock-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
.acct-lock-card {
  display: flex; flex-direction: column; gap: 14px;
  padding: 18px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface);
}
.acct-lock-head { display: flex; align-items: flex-start; gap: 12px; }
.acct-lock-head > div:nth-child(2) { flex: 1; min-width: 0; }
.acct-lock-name { font-weight: 700; font-size: 1rem; }
.acct-lock-desc { font-size: .8rem; color: var(--text-muted); margin-top: 2px; }
.acct-lock-mark { flex: none; color: var(--text-faint); font-size: 1rem; }
.acct-lock-btn { margin-top: auto; width: 100%; justify-content: center; color: var(--accent); }
.acct-lock-btn .ico-lock { margin-right: 6px; }

/* -- free plan: closing call to action -- */
.acct-cta {
  display: flex; align-items: center; gap: 14px;
  padding: 16px; margin-top: 26px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface-2);
}

/* -- paid plan: grouped account lists -- */
/* The intro paragraph used to be the gap between the header and the first platform. With it
   hidden once accounts exist, "Add account" — and its glow — sat straight on top of the
   TikTok heading. The spacing belongs to the header, not to a paragraph that comes and goes. */
.view-accounts .ap-head { margin-bottom: 20px; }
.acct-group { margin-bottom: 26px; }
.acct-group-head { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.acct-group-head h3 { margin: 0; font-size: 1.02rem; }
.acct-group-ico { display: flex; color: var(--text-muted); }
.acct-group-ico .plat-ico { width: 19px; height: 19px; }
.acct-count { font-size: .82rem; color: var(--text-faint); }
.acct-list { display: grid; gap: 8px; }

.acct-av {                                     /* initial avatar */
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--accent-weak); border: 1px solid var(--accent-border);
  color: var(--accent); font-weight: 700; font-size: .9rem;
}
.acct-state {
  flex: none; display: flex; align-items: center; gap: 7px;
  font-size: .82rem; color: var(--ok);
}
.acct-state.off { color: var(--text-faint); }
.acct-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

.acct-kebab {
  flex: none; width: 28px; height: 28px; border-radius: var(--r-sm);
  background: none; border: none; cursor: pointer;
  color: var(--text-faint); font-size: 1.05rem; line-height: 1;
}
.acct-kebab:hover, .acct-kebab.open { background: var(--surface-2); color: var(--text); }

.acct-add {                                    /* dashed "connect another" row */
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; padding: 12px; cursor: pointer;
  border: 1px dashed var(--border-strong); border-radius: var(--r-md);
  background: none; color: var(--accent); font: inherit; font-size: .88rem;
  transition: border-color .18s ease, background .18s ease;
}
.acct-add:hover { border-color: var(--accent); background: var(--accent-weak); }
.acct-add .ico { width: 16px; height: 16px; }

/* -- paid plan: footer status bar -- */
.acct-status {
  display: flex; align-items: center; gap: 14px;
  padding: 16px; margin-top: 4px;
  border: 1px solid var(--ok); border-radius: var(--r-md); background: var(--ok-weak);
}
.acct-status.warn { border-color: var(--warn); background: var(--warn-weak); }
.acct-status-ico {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%;
  border: 1.5px solid var(--ok); color: var(--ok);
}
.acct-status.warn .acct-status-ico { border-color: var(--warn); color: var(--warn); }
.acct-status-ico .ico-check { width: 15px; height: 15px; }

/* -- row overflow menu (NB: not .acct-menu — that's the header user dropdown) -- */
.acct-rowmenu {
  position: fixed; z-index: 90; min-width: 168px; padding: 5px;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-pop);
}
.acct-rowmenu-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 8px 10px; border: none; border-radius: var(--r-sm);
  background: none; color: var(--text); font: inherit; font-size: .86rem;
}
.acct-rowmenu-item:hover { background: var(--surface-2); }
.acct-rowmenu-item.danger { color: var(--danger); }
.acct-rowmenu-item.danger:hover { background: var(--danger-weak); }

/* -- "add account" platform picker (modal) -- */
.acct-pick { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.acct-pick-btn {
  display: flex; flex-direction: column; align-items: center; gap: 10px; cursor: pointer;
  padding: 18px 12px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text); font: inherit; font-size: .9rem;
  transition: border-color .18s ease;
}
.acct-pick-btn:hover { border-color: var(--accent); }

@media (max-width: 640px) {
  .acct-hero { flex-direction: column; padding: 20px; }
  .acct-hero-art { display: none; }
  .acct-lock-grid { grid-template-columns: 1fr; }
  .acct-status, .acct-cta { flex-wrap: wrap; }
}

/* Stroke lock icon — sizes to its container's font-size, inherits text colour */
.ico-lock { width: 1em; height: 1em; display: inline-block; vertical-align: -0.15em; }

/* ===== Schedule: day-of-week + time-of-day pickers ===== */
.day-presets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.day-preset {
  padding: 8px 16px; border-radius: 10px; cursor: pointer; font-weight: 600; font-size: .85rem;
  background: var(--card-2); border: 1px solid var(--border); color: var(--muted);
  transition: all .15s ease;
}
.day-preset:hover { color: var(--text); border-color: var(--border-hi); }
.day-preset.on {
  background: var(--grad, linear-gradient(135deg, var(--cyan), var(--magenta)));
  color: #fff; border-color: transparent;
}

.day-circles { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 8px; }
.day-circle {
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer;
  font-weight: 700; font-size: .9rem;
  background: var(--card-2); border: 1px solid var(--border); color: var(--muted);
  display: flex; align-items: center; justify-content: center; transition: all .15s ease;
}
.day-circle:hover { color: var(--text); border-color: var(--border-hi); }
.day-circle.on {
  background: var(--grad, linear-gradient(135deg, var(--cyan), var(--magenta)));
  color: #fff; border-color: transparent;
  box-shadow: var(--glow-cyan, 0 0 0 1px rgba(0,229,255,.4), 0 0 14px rgba(0,229,255,.28));
}

/* ---- posting schedule: a day you click on --------------------------------------------------
   Four controls edited one array from four directions — a count row, a hidden hour/minute pair,
   a row per time with a pencil and a bin, and four tiles that toggled — and not one of them drew
   the DAY. Two posts forty minutes apart and two twelve hours apart looked identical. Here the
   gap is the information, and each gesture acts on the thing itself: click the day to add, drag
   a marker to move, double-click to remove. */
.sched-day { display: flex; flex-direction: column; gap: 14px; }
.sday-head { display: flex; align-items: baseline; gap: 10px; }
.sday-head .sched-sub { margin: 0; font-size: .68rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-muted); }
.sday-cap { margin-left: auto; font-family: var(--font-mono), "Space Mono", ui-monospace, monospace;
  font-size: 11px; color: var(--text-faint); }
.sday-cap.at-cap { color: var(--warn); }

/* The top padding is the room the markers stand in — they hang above the track, not on it. */
.sday-wrap { padding: calc(22px + (var(--lanes, 1) - 1) * var(--lane-h, 22px)) 4px 6px; transition: padding .15s; }
.sday-track { position: relative; height: 34px; border-radius: 10px;
  border: 1px solid var(--border); cursor: copy;
  /* Midday reads lighter than midnight, so the shape of a schedule is legible before any
     label is read. */
  background: linear-gradient(90deg, #141319 0%, #1C1B22 25%, #232128 50%, #1C1B22 75%, #141319 100%); }
.sday-tick { position: absolute; top: 0; bottom: 0; width: 1px; background: #2A2833; }

/* The hover preview: where a click would land, and what time that is. Dimmer and thinner than
   a real marker, so a time you are only pointing at never reads as a time you have set. */
.sday-ghost { position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: rgba(123,150,255,.45); pointer-events: none;
  opacity: 0; transition: opacity .12s ease; }
.sday-ghost.on { opacity: 1; }
.sday-ghost b { position: absolute; bottom: calc(100% + 5px); left: 50%; transform: translateX(-50%);
  padding: 2px 7px; border-radius: 999px; background: var(--surface);
  border: 1px solid var(--border-strong); color: var(--text-muted);
  font-family: var(--font-mono), "Space Mono", ui-monospace, monospace;
  font-size: 10.5px; font-weight: 700; white-space: nowrap; }

.sday-mark { position: absolute; top: calc(-19px - var(--lane, 0) * var(--lane-h, 22px)); transform: translateX(-50%);
  display: grid; justify-items: center; gap: 3px; }
.sday-pill { padding: 2px 8px; border: 0; border-radius: 999px; background: var(--accent);
  color: var(--on-accent); font-family: var(--font-mono), "Space Mono", ui-monospace, monospace;
  font-size: 10.5px; font-weight: 700; white-space: nowrap; cursor: ew-resize;
  touch-action: none; }
.sday-mark.on .sday-pill { background: #7B96FF; box-shadow: 0 0 0 2px rgba(123,150,255,.35); }
/* Exactly the track's height: a taller stem strikes through the axis labels under it. */
.sday-stem { width: 2px; height: calc(34px + var(--lane, 0) * var(--lane-h, 22px)); border-radius: 2px; background: var(--accent); }
.sday-mark.on .sday-stem { background: #7B96FF; }

.sday-axis { margin-top: 7px; display: flex; justify-content: space-between;
  font-family: var(--font-mono), "Space Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .06em; color: var(--text-faint); }

/* The nudge popover, above the marker it belongs to. */
.sday-pop { position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 4px; padding: 4px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--border-strong);
  box-shadow: 0 12px 30px rgba(0,0,0,.6); }
.sdp-b { width: 24px; height: 24px; border: 0; border-radius: 50%; background: transparent;
  color: var(--text-muted); font: inherit; font-size: 14px; line-height: 1; cursor: pointer; }
.sdp-b:hover { background: #232128; color: var(--text); }
.sdp-x:hover { color: var(--danger); }
.sdp-l { font-family: var(--font-mono), "Space Mono", ui-monospace, monospace; font-size: 10px;
  color: var(--text-faint); white-space: nowrap; }
.sdp-div { width: 1px; height: 16px; background: var(--border-strong); }

.sday-jump { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sday-jump-lbl { font-family: var(--font-mono), "Space Mono", ui-monospace, monospace;
  font-size: 10px; letter-spacing: .09em; text-transform: uppercase; color: var(--text-faint); }
.sday-chips { display: flex; gap: 8px; flex-wrap: wrap; }
.sday-chip, .sday-clear { height: 28px; padding: 0 13px; border-radius: 999px;
  border: 1px solid #2E2C38; background: transparent; color: var(--text-muted);
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  transition: background .14s, border-color .14s, color .14s; }
.sday-chip:hover, .sday-clear:hover { background: var(--surface-2); border-color: #3A3745;
  color: var(--text); }
.sday-chip.on { background: var(--accent-weak); border-color: var(--accent-border); color: #CBD6FF; }
.sday-clear { margin-left: auto; }

.sday-sum { display: flex; align-items: center; gap: 9px; padding: 11px 13px; border-radius: 12px;
  background: #141319; border: 1px solid var(--border); }
.sday-sum-t { flex: 1; min-width: 0; font-size: 13px; color: #C6C1CE; }
.sday-sum-dim { color: var(--text-faint); }
.sday-sum-tz { flex: none; font-family: var(--font-mono), "Space Mono", ui-monospace, monospace;
  font-size: 10.5px; color: var(--text-faint); }

/* Schedule panel header + section labels */
/* .setup-card carries no padding of its own — it lives on .setup-field — so a direct child of
   the card sits flush against its border. These two are direct children, which is why the
   heading was clipped at the left edge and the timezone touched the right one. */
.sched-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; padding: 14px 16px 0;
}
.sched-tz {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .78rem; color: var(--text-muted);
}
.sched-tz .select { max-width: 170px; }
.sched-sub {
  display: block; margin-bottom: 10px;
  font-size: .82rem; font-weight: 600; color: var(--text-muted);
}

/* ===== Workspace-card hover actions (run / view / edit / delete) ===== */
/* A hover action bar pinned to the bottom of the card — separated from the status badge,
   over a subtle scrim so it reads as one intentional control. */
.wsp-card { position: relative; overflow: hidden; padding-bottom: 16px; }
.wsp-actions {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; justify-content: flex-end; gap: 8px;
  /* The buttons sit ON TOP of the card's last line, so the gradient has to do the separating.
     At 60% it stopped just under the progress bar and the icons read as attached to it; the
     extra top padding drops them clear of it and the longer fade gives the bar a dark run-out
     instead of a hard edge. */
  padding: 30px 14px 13px; border-radius: 0 0 14px 14px;
  background: linear-gradient(to top, var(--card) 46%, rgba(17,19,28,.92) 74%, transparent);
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity .15s ease, transform .15s ease;
}
.wsp-card:hover .wsp-actions, .wsp-card:focus-within .wsp-actions {
  opacity: 1; transform: none; pointer-events: auto;
}
.wsp-act {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border-radius: 8px; cursor: pointer;
  background: var(--card-2); border: 1px solid var(--border-hi); color: var(--muted);
  transition: color .12s, border-color .12s, background .12s;
}
.wsp-act:hover:not(:disabled) { color: var(--text); border-color: var(--cyan-dim, var(--cyan)); background: var(--card); }
.wsp-act.danger:hover:not(:disabled) { color: var(--err, #ff5d6c); border-color: var(--err, #ff5d6c); }
/* Locked while a clip is generating — :hover is excluded above so it doesn't still look live. */
.wsp-act:disabled { opacity: .35; cursor: not-allowed; }
.wsp-act svg { width: 16px; height: 16px; }

/* ===== Setup layout guarantee: a single centered column whenever the reference panel is
   hidden (text-to-video) — even if the .solo class didn't apply — so the card never collapses
   to its content width or drifts to one side. ===== */
/* Setup keeps a fixed 2-column grid regardless of model kind: the card is always the left
   column's width; text-to-video just leaves the right (reference) column empty. */
.view-ask .home-grid > .setup-card { min-width: 0; }

/* ===== Workspace dashboard: two columns — status/config (left) · activity (right) ===== */
.ap-split {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 24px; align-items: start;
}
.ap-left { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.ap-right { min-width: 0; display: flex; flex-direction: column; }
.ap-right .section-h { margin-top: 0; }
@media (max-width: 1000px) { .ap-split { grid-template-columns: 1fr; } }

/* (the workspace view's :has() width override is gone — .main is 95% everywhere now) */

/* Back link: a plain text link, not a bordered pill competing with the title beneath it. */

/* -- title bar: name + live state, actions right -- */
/* One row now that the subtitle is gone: name on the left, actions on the right. */
.ws-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.ws-top-id { min-width: 0; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.ws-back {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; padding: 0; border-radius: 11px;
  border: 1px solid var(--border); background: var(--card-2); color: var(--muted);
  cursor: pointer; transition: border-color .15s, background .15s, color .15s;
}
.ws-back svg { width: 20px; height: 20px; }

/* Back-to-somewhere controls that have to name where. Same family as .ws-back, wider. */
.btn-back {
  display: inline-flex; align-items: center; gap: 7px; margin-left: -2px;
  padding: 6px 14px 6px 11px; border-radius: var(--r-pill);
  border: 1px solid var(--border); background: var(--card-2); color: var(--muted);
  font: inherit; font-size: .82rem; font-weight: 600; cursor: pointer;
  transition: border-color .15s, background .15s, color .15s;
}
.btn-back svg { width: 15px; height: 15px; flex: none; }
.btn-back { width: fit-content; align-self: flex-start; }
.btn-back:hover { border-color: var(--border-hi); background: var(--card); color: var(--text); }
.ws-back:hover { border-color: var(--accent-border); background: var(--accent-weak); color: var(--accent); }
.ws-top-id h1 { margin: 0; font-size: 1.7rem; line-height: 1.2; }
/* The title is the rename field: it reads as a heading until you hover it. */
.ws-top-id h1.ws-name { cursor: text; border-radius: 6px; padding: 2px 6px; margin: 0 -6px; transition: background .12s; }
.ws-top-id h1.ws-name:hover { background: var(--surface-2); }
.ws-rename {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: 0; border-radius: 6px;
  background: none; color: var(--text-faint); cursor: pointer; opacity: 0;
  transition: opacity .12s, color .12s, background .12s;
}
.ws-rename svg { width: 15px; height: 15px; }
.ws-top-id:hover .ws-rename, .ws-rename:focus-visible { opacity: 1; }
.ws-rename:hover { color: var(--text); background: var(--surface-2); }
.ws-name-input {
  font-family: var(--font-display); font-size: 1.7rem; font-weight: 800;
  letter-spacing: -0.022em; line-height: 1.2; color: var(--text);
  min-width: 0; width: min(30ch, 60vw); padding: 2px 6px; margin: 0 -6px;
  background: var(--surface-2); border: 1px solid var(--accent-border); border-radius: 6px;
}
.ws-name-input:focus { outline: none; border-color: var(--accent); }
.ws-top-state { display: inline-flex; align-items: center; gap: 6px; font-size: .84rem; font-weight: 600; color: var(--muted); }
.ws-top-state .ws-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.ws-top-state.on { color: var(--ok); }
.ws-top-state.warn { color: var(--warn); }
/* The original .ico-btn action set, moved up here from the hero. */
.ws-top-actions { flex: 0 1 auto; min-width: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.hero-left:has(> .orb.hidden) { display: none; }
@media (max-width: 560px) {
  /* Phone: Start takes the row; the rest share the next one. */
  .ws-top-actions { width: 100%; }
  .ws-top-actions .lbl-btn.primary, .ws-top-actions .lbl-btn.stop { flex: 1 1 100%; justify-content: center; }
  .ws-top-actions #apRunNow { flex: 1 1 auto; justify-content: center; }
}
/* Labelled actions. Same height as the icon buttons they replaced, so the bar keeps its line. */
.lbl-btn { display: inline-flex; align-items: center; gap: 8px; height: 42px; padding: 0 16px;
  border-radius: 10px; border: 1px solid var(--border); background: var(--card-2); color: var(--text);
  font: inherit; font-size: .88rem; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: border-color .15s, background .15s, color .15s, transform .08s; }
.lbl-btn svg { width: 17px; height: 17px; flex: none; }
.lbl-btn:hover { border-color: var(--border-hi); background: var(--card); }
.lbl-btn:active:not(:disabled) { transform: translateY(1px); }
.lbl-btn:disabled { opacity: .45; cursor: not-allowed; }
.lbl-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.lbl-btn.primary:hover { filter: brightness(1.08); background: var(--accent); }
.lbl-btn.stop:hover { border-color: #ff6b6b; color: #ff6b6b; }
/* "Generate one now" lights up on hover the way Stop does, in the accent (owner, 2026-10-10). */
#apRunNow:hover:not(:disabled) { border-color: var(--accent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--card)); }
.lbl-btn.ghost { background: transparent; }
.ap-more { position: relative; display: inline-flex; }
.ap-more-btn { width: 42px; height: 42px; }
.ap-more-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; min-width: 200px; padding: 6px;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow); }
.ap-more-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 10px; border: 0;
  border-radius: 8px; background: none; color: var(--text); font: inherit; font-size: .88rem; cursor: pointer; text-align: left; }
.ap-more-item svg { width: 16px; height: 16px; }
.ap-more-item:hover { background: var(--card-2); }
.ap-more-item.danger { color: #ff6b6b; }
/* The workspace name is the page title: shown whole, not cut at 220px beside empty space. */
.ws-top-id h1.ws-name { max-width: min(62vw, 760px); white-space: normal; overflow-wrap: anywhere; }
.ws-style-tag { display: inline-flex; align-items: center; height: 26px; padding: 0 10px; border-radius: var(--r-pill);
  background: var(--accent-weak); border: 1px solid var(--accent-border); color: var(--accent);
  font-size: .78rem; font-weight: 600; white-space: nowrap; }
.cfg-how { margin-left: 6px; font-size: .78rem; font-weight: 500; color: var(--text-faint); }
.ws-pane-wide { grid-column: 1 / -1; }
.ap-details-h { margin: 16px 0 6px; font-size: .78rem; font-weight: 600; color: var(--text-faint); }
.feed-pill { display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--text-muted); font-size: .74rem; font-weight: 600; }
.feed-meta { margin-left: 8px; font-size: .76rem; color: var(--text-faint); }

/* -- hero: state, model, progress -- */
.hero-chip {
  display: inline-block; margin-bottom: 8px; padding: 4px 10px; border-radius: var(--r-pill);
  background: var(--accent-weak); border: 1px solid var(--accent-border); color: var(--accent);
  font-family: var(--font-mono); font-size: .64rem; font-weight: 700; letter-spacing: .09em;
}
.hero-chip.idle { background: var(--surface-2); border-color: var(--border); color: var(--text-faint); }
.hero-chip.warn { background: var(--warn-weak); border-color: var(--warn); color: var(--warn); }
.hero-model { font-size: .88rem; color: var(--text-muted); margin-top: 4px; }
.hero-prog { display: flex; align-items: center; gap: 12px; margin: 14px 0 4px; }
.hero-prog-track {
  flex: 1 1 auto; height: 8px; border-radius: var(--r-pill);
  background: var(--surface-2); overflow: hidden;
}
.hero-prog-bar {
  position: relative; overflow: hidden;      /* clips the shimmer to the filled part */
  display: block; height: 100%; width: 0;
  border-radius: var(--r-pill); background: var(--accent);
  transition: width .6s ease;
}
/* A highlight that sweeps across the FILLED portion, forever, while the width advances on
   its own every poll. The two are independent on purpose: the shimmer says "still working",
   the width says "how far" — a bar that only moves once every 10s reads as frozen. */
.hero-prog-bar::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 50%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  animation: progShimmer 1.5s linear infinite;
}
@keyframes progShimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(200%); }
}
@media (prefers-reduced-motion: reduce) { .hero-prog-bar::after { animation: none; opacity: 0; } }
.hero-prog-pct { flex: none; font-size: .92rem; font-weight: 700; font-variant-numeric: tabular-nums; }
/* Past the estimate: the number becomes elapsed time, and the bar stops claiming a share.
   Deeper blue rather than amber — a run that is taking a while is not a warning, and painting
   it in the warning colour made every long render look like something had gone wrong. The
   number stays at the normal accent so it is still legible against the dark surface; only the
   bar darkens, which is enough to read as "no longer counting toward a target". */
.hero-prog.over .hero-prog-pct { color: var(--accent); }
.hero-prog.over .hero-prog-bar { background: var(--accent-deep); }

/* Waiting for the worker to pick the run up. There is no elapsed time yet, so there is no
   honest percentage — a bar frozen at 0% for ten seconds reads as hung, and inventing a
   number would be a lie the next poll contradicts. An indeterminate sweep says "working,
   position unknown", which is exactly true. */
.hero-prog.is-starting .hero-prog-bar {
  width: 32% !important;
  animation: prog-sweep 1.4s ease-in-out infinite;
}
.hero-prog.is-starting .hero-prog-pct { color: var(--text-faint); }
@keyframes prog-sweep {
  0%   { transform: translateX(-105%); }
  100% { transform: translateX(320%); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-prog.is-starting .hero-prog-bar { animation: none; width: 8% !important; }
}

/* -- stat tiles: value + sub-label -- */
.stat .sub { font-size: .72rem; color: var(--muted); margin-top: 3px; }

/* -- config / last-prompt panes: .card + .section-h + .cfg-row do the styling -- */
.ws-panes { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 14px; }
@media (max-width: 760px) { .ws-panes { grid-template-columns: 1fr; } }
.ws-pane { display: flex; flex-direction: column; }
.ws-pane .section-h { margin: 0 0 10px; }
.ws-pane .cfg-row:first-child { border-top: none; }
/* .cfg-k's fixed 180px basis is sized for the full-width list below. In this ~330px pane it
   left the value ~130px, which broke words mid-character ("Referen / ce → video"). Here the
   label takes only what it needs and the value takes the rest, right-aligned. */
.ws-pane .cfg-row { align-items: baseline; gap: 16px; padding: 9px 0; }
.ws-pane .cfg-k { flex: 0 1 auto; white-space: nowrap; }
.ws-pane .cfg-v { flex: 1 1 auto; text-align: right; overflow-wrap: anywhere; word-break: normal; }
/* Long free text (the seed theme) gets two lines, then ellipsis — the full text is a click
   away under "View full configuration". */
.ws-pane .cfg-row:last-child .cfg-v {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Clamped because it's a summary — the untruncated prompt is the "Last prompt sent to AI"
   row inside the Full configuration block directly below. */
.ws-lastprompt {
  margin: 0; font-size: .86rem; line-height: 1.65; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 8; -webkit-box-orient: vertical; overflow: hidden;
}

/* -- activity filter row (.select supplies the styling) -- */
.ws-act-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.ws-act-filters { display: flex; gap: 8px; }
.ws-act-filters .select { width: auto; font-size: .8rem; padding: 6px 26px 6px 10px; }

/* ===== Themed scrollbars (replace the chunky default OS scrollbar) ===== */
/* Firefox */
* { scrollbar-width: thin; scrollbar-color: var(--border-hi) transparent; }
/* WebKit / Chromium / Edge */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border-hi); border-radius: 8px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }
::-webkit-scrollbar-button { display: none; height: 0; width: 0; }
::-webkit-scrollbar-corner { background: transparent; }

/* ---- per-category reference mode + AI refresh policy (icon toggles) ---- */
/* Two-state icon buttons. Off = the cheap/default state, on = the deliberate one, so the
   highlight always marks the choice that costs something (combining, or redrawing). */
.anchor-mode, .ref-refresh {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  padding: 3px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text-muted);
  font: inherit; font-size: .68rem; font-weight: 600; line-height: 1;
}
.anchor-mode svg, .ref-refresh svg { width: 13px; height: 13px; }
.anchor-mode:hover, .ref-refresh:hover { color: var(--text); border-color: var(--border-hi); }
.anchor-mode.on, .ref-refresh.on {
  color: var(--warn); background: var(--warn-weak); border-color: var(--warn);
}
.anchor-mode { padding: 3px 6px; }          /* icon only — no label */
.ref-refresh { margin-left: 6px; }

/* The per-day roll-up beside the credit estimate. Lower contrast than the headline: it's the
   consequence of that number, not a second number competing with it. */
.est-inline-day { flex: none; white-space: nowrap; font-size: .72rem; color: var(--text-faint); }
.est-inline-day.hidden { display: none; }

/* Review actions in the clip-preview head, beside ✕ — approve/reject what you just watched. */
.clip-act {
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  width: 32px; height: 32px; border-radius: var(--r-sm); flex: none;
  background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text-muted);
}
.clip-act svg { width: 17px; height: 17px; }
.clip-act.hidden { display: none; }
.clip-act.ok:hover    { color: var(--ok);     border-color: var(--ok);     background: var(--ok-weak); }
.clip-act.bad:hover   { color: var(--danger); border-color: var(--danger); background: var(--danger-weak); }
.clip-act.share:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-weak); }
/* Tight 6px between the three buttons so they read as one group — then a wider gap before ✕.
   Reject is destructive and sat immediately beside Close, which is the one button a user reaches
   for without looking; the extra space separates "act on this clip" from "put the panel away". */
.clip-drawer-head { gap: 6px; }
.clip-drawer-head #clipClose { margin-left: 10px; }

/* ---- run incidents: what a run absorbed and carried on through ---- */
.admin-table tr.log-warn td { background: rgba(224, 169, 58, .06); }
.log-badge.warn { background: var(--warn-weak); border: 1px solid var(--warn); color: var(--warn); }
.log-inc { color: var(--warn); margin-top: 3px; }
.log-inc-list { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
.log-inc-row {
  display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: start;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--warn-weak); border: 1px solid var(--warn);
}
.log-inc-kind {
  padding: 2px 8px; border-radius: var(--r-pill); white-space: nowrap;
  background: var(--warn); color: #0a0c12; font-size: .66rem; font-weight: 800;
}
.log-inc-step { font-size: .78rem; font-weight: 700; color: var(--text); }
.log-inc-detail { font-size: .78rem; color: var(--text-muted); line-height: 1.45; margin-top: 2px; }
.log-inc-row .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ---- hero countdown: the one number people actually watch ---- */
/* Tabular figures and a fixed-width unit: without them every tick nudges the digits sideways
   as glyph widths change, which is the whole reason a live clock feels cheap. */
.hero-count {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 14px;
  font-variant-numeric: tabular-nums;
}
.hero-count.hidden { display: none; }
.hero-count-unit { display: flex; flex-direction: column; align-items: center; min-width: 62px; }
.hero-count-unit b {
  font-family: var(--font-display, inherit);
  font-size: 2.6rem; font-weight: 800; line-height: 1; letter-spacing: -.02em;
  color: var(--text);
}
.hero-count-unit i {
  font-style: normal; margin-top: 4px;
  font-size: .7rem; font-weight: 600; letter-spacing: .06em;
  color: var(--text-faint);
}
/* The separator sits on the digits' baseline, not the column's — centring it against a block
   that also contains a label would float it below the numbers it separates. */
.hero-count-sep {
  font-size: 2.1rem; font-weight: 700; line-height: 1.15; color: var(--text-faint);
}
.hero-count-when {
  margin-top: 8px; font-size: .8rem; color: var(--text-muted);
}
.hero-count-when.hidden { display: none; }

@media (max-width: 720px) {
  .hero-count-unit { min-width: 52px; }
  .hero-count-unit b { font-size: 2.1rem; }
  .hero-count-sep { font-size: 1.7rem; }
}

/* An AI image that's been drawn and kept ("draw once"). It's a real reference — the next run
   reuses it — so it looks like one, with a small mark saying where it came from. Deleting it
   is how you ask for a redraw, hence the same ✕ as an upload. */
.anchor-thumb-item.is-ai { outline: 1px solid var(--warn); outline-offset: -1px; }
.anchor-thumb-ai {
  position: absolute; left: 3px; bottom: 3px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%;
  background: linear-gradient(135deg, var(--warn), #ffd089); color: #0a0c12;
}
.anchor-thumb-ai svg { width: 10px; height: 10px; }

/* Why a post failed, in the activity feed. Same weight as a generation error — both are
   things the run couldn't do, and both need reading. */
.res-why { margin-top: 4px; font-size: .78rem; line-height: 1.45; color: var(--danger); }

/* The activity row whose clip is playing in the drawer — same signal as .lib-card.playing,
   so the two lists mean the same thing by the same outline. */
.feed-item.playing {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 22px color-mix(in srgb, var(--accent) 28%, transparent);
}

/* ---- the stats strip flips between three faces ---- */
/* Absolute faces need a reserved height or the block collapses mid-flip and the page jumps.
   Fixed rather than measured: all three faces are one row of the same shape. */
/* min-height carries the tallest face (refs: 14+14 padding + label + gap + 70px thumb ≈ 128),
   and the bottom margin is the dots' room — they sit outside the card, so without it they
   collide with whatever follows. Absolute faces get clipped, not scrolled, if this is short. */
/* The faces share ONE grid cell rather than being absolutely positioned over a fixed 128px box:
   on a phone a face wraps to two rows and is taller than that, and the overflow sat on top of
   the panel below. Stacked in a cell, the strip is as tall as its tallest face. */
.stat-flip { position: relative; display: grid; min-height: 128px; margin-bottom: 28px; perspective: 1200px; }
.flip-face {
  grid-area: 1 / 1; position: relative;
  transform-origin: top center; backface-visibility: hidden;
  transition: transform .5s cubic-bezier(.22,.61,.36,1), opacity .35s ease;
  transform: rotateX(90deg); opacity: 0; pointer-events: none;   /* waiting below */
}
.flip-face.prev { transform: rotateX(-90deg); }                   /* already gone, upward */
.flip-face.on   { transform: rotateX(0); opacity: 1; pointer-events: auto; }
.flip-face > .stats-row { margin-bottom: 0; height: 100%; }
.stats-row.alt { grid-template-columns: 1fr; }
.stat.wide { padding: 14px 16px; }        /* match .stat — a face shouldn't feel tighter */
.stat-note { margin-left: auto; font-size: .68rem; color: var(--text-faint); font-weight: 600; }
.stat .label { display: flex; align-items: center; gap: 6px; }

/* the clock times behind the countdown */
/* Two rows, filling top-to-bottom then scrolling sideways. A single row of 14 slots ran off
   the panel; wrapping into unbounded rows would instead push the block taller every time a
   slot is added. Two is the compromise the layout can afford. */
.slot-row { overflow-x: auto; padding: 10px 0 4px; }
.slot-track {
  display: grid; grid-auto-flow: column; grid-template-rows: repeat(2, auto);
  grid-auto-columns: max-content; gap: 6px; width: max-content;
}

/* Drifts left, then back, only when the slots overrun the panel. Hidden overflow while it
   runs so the native scrollbar isn't fighting the transform; hover parks it so you can read
   a time without chasing it. */
.slot-row.drift { overflow: hidden; }
.slot-row.drift .slot-track {
  animation-name: slot-drift;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
.slot-row.drift:hover .slot-track { animation-play-state: paused; }
@keyframes slot-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(var(--drift-x, 0)); }
}
@media (prefers-reduced-motion: reduce) {
  .slot-row.drift { overflow-x: auto; }
  .slot-row.drift .slot-track { animation: none; }
}
.slot-row::-webkit-scrollbar { height: 4px; }
.slot-row::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
.slot-chip {
  flex: none; padding: 6px 12px; border-radius: var(--r-pill); white-space: nowrap;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
  font-size: .86rem; font-weight: 600; font-variant-numeric: tabular-nums;
}
.slot-chip.next { background: var(--accent-weak); border-color: var(--accent); color: var(--accent); }
.slot-chip.past { opacity: .45; }                                 /* already spent today */

/* the references in play — scrolls sideways when there are more than fit */
.ref-strip { overflow-x: auto; padding: 10px 0 4px; }
.ref-strip-track { display: flex; gap: 7px; width: max-content; }
.ref-strip::-webkit-scrollbar { height: 4px; }
.ref-strip::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }

/* Auto-scroll only when they don't fit — a marquee on content that already fits is motion
   for its own sake, and the duplicated track would show a gap. Hidden overflow while it runs
   so the browser's own scrollbar doesn't fight the animation. */
.ref-strip.marquee { overflow: hidden; }
.ref-strip.marquee .ref-strip-track {
  animation-name: ref-marquee;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.ref-strip.marquee:hover .ref-strip-track { animation-play-state: paused; }
@keyframes ref-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(var(--marquee-x, -50%)); }
}
@media (prefers-reduced-motion: reduce) {
  .ref-strip.marquee { overflow-x: auto; }
  .ref-strip.marquee .ref-strip-track { animation: none; }
}
.ref-strip-i {
  flex: none; position: relative; width: 70px; height: 70px; border-radius: 9px;
  overflow: hidden; border: 1px solid var(--border-strong);
}
.ref-strip-i img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ref-strip-i.ai { border-color: var(--warn); }

.flip-dots { position: absolute; right: 4px; bottom: -17px; display: flex; gap: 5px; align-items: center; }
.flip-dots button {
  width: 6px; height: 6px; padding: 0; border-radius: 50%; cursor: pointer;
  background: var(--border-strong); border: 0; transition: background .2s ease, width .2s ease;
}
.flip-dots button.on { background: var(--accent); width: 14px; border-radius: 3px; }

@media (prefers-reduced-motion: reduce) {
  .flip-face { transition: opacity .2s ease; transform: none !important; }
}

/* Developer-only inspection control (References → originals vs what the model got).
   Hidden entirely unless the server reports dev_mode, so production never sees it. */
.dev-only.on {
  color: var(--warn); border-color: var(--warn); background: var(--warn-weak);
}

/* The CHARACTER placeholder doubles as the sex control. Frame and figures are one SVG (see
   sexSvg): the "either" state needs a dashed outline that is pink on one side and blue on the
   other, and a CSS dashed border cannot carry a gradient — the fill shows through the gaps. */
.anchor-ai-tile.is-sex {
  /* Square, matching the thumbnails beside it — the base tile is a wide pill sized for its
     "AI will generate" label, which this state replaces with an icon. */
  width: 42px; height: 42px; flex: none;
  border: 0; background: none; padding: 0; cursor: pointer;
  display: block; line-height: 0;
  transition: transform .15s ease, filter .15s ease;
}
.anchor-ai-tile.is-sex:hover { transform: translateY(-1px); filter: brightness(1.12); }
.anchor-ai-tile.is-sex svg { display: block; width: 100%; height: 100%; }

/* References page actions. One segmented group rather than two loose ghost buttons: they act on
   the same thing (this page's clip list) and sat at different weights before — a 5px-padded
   pill next to an 11px one, only one of them carrying an icon. */
.ref-actions { display: inline-flex; align-items: stretch; flex: none;
  border: 1px solid var(--border-hi); border-radius: var(--r-pill);
  background: var(--surface-2); overflow: hidden; }
.ref-act { display: inline-flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px;
  border: 0; background: none; color: var(--muted); cursor: pointer;
  font: inherit; font-size: .8rem; font-weight: 600; white-space: nowrap;
  transition: background .15s, color .15s; }
.ref-act svg { width: 15px; height: 15px; flex: none; }
.ref-act:hover:not(:disabled):not(.is-off) { color: var(--text); background: var(--sidebar-raised); }
/* Switched off for this clip — see syncRefEditBtn. Kept focusable and hoverable so the title
   can say why; the click handler is what refuses. */
.ref-act.is-off { color: var(--faint); opacity: .55; cursor: not-allowed; }
/* Why the button is off, said where the reader is already looking. */
.ref-frozen {
  margin-bottom: 12px; padding: 9px 12px; border-radius: 10px;
  border: 1px solid var(--border); border-left: 3px solid var(--warn);
  background: var(--surface-2); color: var(--muted); font-size: .78rem; line-height: 1.55;
}
.ref-frozen.gone { border-left-color: var(--faint); }
.ref-act:focus-visible { outline: 2px solid var(--cyan-dim); outline-offset: -2px; }
/* The icon-only half is square and divided from its neighbour — without the rule the two read
   as one wide button and the refresh looks like decoration on "Edit references". */
.ref-act-ico { width: 38px; padding: 0; justify-content: center;
  border-right: 1px solid var(--border-hi); }
.ref-act-ico:disabled { color: var(--faint); cursor: default; }
.ref-act-ico.spin svg { animation: ref-spin .9s linear infinite; }
@keyframes ref-spin { to { transform: rotate(360deg); } }

/* ---- Presets index: one card per preset ---- */
.preset-card { min-height: 132px; }
.preset-card-name { font-family: var(--font-display); font-size: 1.1rem; font-weight: 700; color: var(--text); }
.preset-card-gist { flex: 1 1 auto; font-size: .82rem; line-height: 1.5; color: var(--text-muted); }
.preset-card-foot { display: flex; align-items: center; gap: 8px; }
.preset-used { font-size: .68rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  padding: 3px 9px; border-radius: var(--r-pill); color: var(--cyan); background: rgba(0,229,255,.1); }
/* A lone action beside a title, not half of a segmented pair. */
.ref-act-solo { border: 1px solid var(--border-hi); border-radius: var(--r-pill); background: var(--surface-2); }
.ref-act-danger { color: var(--err); border-left: 1px solid var(--border-hi); }
.ref-act-danger:hover:not(:disabled) { color: #fff; background: var(--err); }

/* ---- "New preset" beside the Setup dropdown ---- */
.preset-pick { display: flex; align-items: stretch; gap: 8px; }
.preset-pick .select { flex: 1 1 auto; min-width: 0; }
.preset-pick-new { flex: none; display: inline-flex; align-items: center; gap: 6px; padding: 0 13px;
  border: 1px dashed var(--border-hi); border-radius: var(--r-md); background: transparent;
  color: var(--text-muted); font: inherit; font-size: .82rem; font-weight: 600; cursor: pointer;
  transition: color .15s, border-color .15s; }
.preset-pick-new svg { width: 14px; height: 14px; }
.preset-pick-new:hover { color: var(--cyan); border-color: var(--cyan-dim); }

.pe-relink {
  margin-left: auto; padding: 3px 10px; cursor: pointer;
  border: 1px solid var(--warn); border-radius: var(--r-pill);
  background: none; color: var(--warn); font: inherit; font-size: .72rem; font-weight: 600;
}
.pe-relink:hover { background: var(--warn-weak); }
.pe-relink.hidden { display: none; }

/* The strip already pauses on hover (see .ref-strip.marquee:hover) — this just says the click
   does something. */
.ref-strip-i img { cursor: zoom-in; }

/* The tick that appeared on its own says so, in the accent — a change nobody made needs to be
   visibly ours before the creator can decide to disagree with it. */
.int-auto { color: var(--accent); font-weight: 700; margin-right: 4px; }
.note-hint i { color: var(--faint); font-style: normal; }

/* Folded away: the panel's first job is "what is this clip", and these answer the second one. */
.clip-preset > summary { cursor: pointer; list-style: none; font-size: .82rem; font-weight: 700;
  color: var(--muted); padding: 2px 0; }
.clip-preset > summary::-webkit-details-marker { display: none; }
.clip-preset > summary::before { content: "\25B8"; display: inline-block; margin-right: 6px;
  transition: transform .16s ease; }
.clip-preset[open] > summary::before { transform: rotate(90deg); }
.clip-preset > summary:hover { color: var(--text); }

/* ===================== Credits — overview ===================== */
.cr-hero { display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 22px 24px; margin-bottom: 16px; border: 1px solid var(--border); border-radius: 16px;
  background: linear-gradient(135deg, rgba(56,62,120,.30), rgba(22,25,39,.55) 55%); }
.cr-kicker { font-size: .68rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--faint); }
.cr-bal { display: flex; align-items: baseline; gap: 8px; margin: 6px 0 8px;
  font-family: var(--font-display); font-size: 2.6rem; font-weight: 800; line-height: 1; }
.cr-bal small { font-size: .9rem; font-weight: 600; color: var(--muted); }
.cr-bal .low { color: var(--err, #ff5d6c); }
.cr-note { margin: 6px 0 0; font-size: .85rem; }
.cr-note.bad { color: var(--err, #ff5d6c); }
.cr-topup { flex: 0 0 auto; height: 40px; padding: 0 18px; border: 0; border-radius: 10px;
  cursor: pointer; font: inherit; font-size: .88rem; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, #6d7cff, #4453e8);
  box-shadow: 0 2px 10px rgba(77,90,232,.22); transition: filter .12s, transform .12s; }
.cr-topup:hover { filter: brightness(1.08); transform: translateY(-1px); }

.cr-grid { display: grid; grid-template-columns: 1.35fr 1fr; gap: 16px; align-items: start; }
.cr-card { padding: 18px 20px; border: 1px solid var(--border); border-radius: 16px;
  background: linear-gradient(180deg, rgba(22,25,39,.6), rgba(17,19,28,.45)); }
.cr-card-head { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 12px; }
.cr-card-head h3 { margin: 0; font-family: var(--font-display); font-size: 1rem; font-weight: 700; }
.cr-range { height: 32px; padding: 0 30px 0 10px; font-size: .8rem; width: auto; }

.cr-chart { position: relative; width: 100%; }
.cr-chart svg { width: 100%; height: 170px; display: block; overflow: visible; }

/* Hover readout. Hidden until the pointer is over the chart, and pointer-events: none on the
   tooltip so it can never sit between the cursor and the plot it is describing. */
.cr-hl { stroke: rgba(255,255,255,.22); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0; }
.cr-hd { fill: #fff; stroke: #7c8cff; stroke-width: 2; opacity: 0;
  vector-effect: non-scaling-stroke; }
.cr-chart.on .cr-hl, .cr-chart.on .cr-hd { opacity: 1; }
.cr-tip { position: absolute; top: -2px; z-index: 2; display: none; flex-direction: column;
  gap: 1px; padding: 7px 10px; border-radius: 9px; pointer-events: none; white-space: nowrap;
  background: var(--card-2, #1a1d2b); border: 1px solid var(--border-hi, var(--border));
  box-shadow: 0 8px 22px rgba(0,0,0,.45); }
.cr-chart.on .cr-tip { display: flex; }
.cr-tip-d { font-size: .7rem; color: var(--muted); }
.cr-tip-v { font-family: var(--font-display); font-size: .95rem; font-weight: 800; }
.cr-tip-v small { font-size: .7rem; font-weight: 600; color: var(--muted); }
.cr-ax { fill: var(--faint); font-size: 11px; }
.cr-trend { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.cr-trend-n { font-family: var(--font-display); font-size: 1.3rem; font-weight: 800; }
.cr-trend-n small { font-size: .78rem; font-weight: 600; color: var(--muted); }
.cr-trend-d { font-size: .84rem; font-weight: 700; }
.cr-trend-d small { font-weight: 500; color: var(--muted); }
.cr-trend-d.up { color: #f0a83c; }        /* spending MORE is not a win — amber, not green */
.cr-trend-d.down { color: #34d399; }
.cr-trend-d.none { color: var(--faint); font-weight: 500; }

.cr-wsrow { display: grid; grid-template-columns: 10px 1fr 84px 54px 38px; align-items: center;
  gap: 10px; padding: 7px 0; }
.cr-wsdot { width: 10px; height: 10px; border-radius: 3px;
  background: hsl(var(--h, 258) 70% 62%); }
.cr-wsname { font-size: .86rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-wsbar { height: 5px; border-radius: 3px; background: rgba(255,255,255,.07); overflow: hidden; }
.cr-wsbar i { display: block; height: 100%; border-radius: 3px;
  background: hsl(var(--h, 258) 70% 62%); }
.cr-wsn { text-align: right; font-size: .86rem; font-weight: 700; }
.cr-wspct { text-align: right; font-size: .8rem; color: var(--muted); }
.cr-wstotal { display: grid; grid-template-columns: 1fr 54px 38px; gap: 10px; margin-top: 8px;
  padding-top: 10px; border-top: 1px solid var(--border); font-size: .86rem; font-weight: 700; }
.cr-wstotal span:nth-child(2), .cr-wstotal span:nth-child(3) { text-align: right; }
.cr-wstotal span:nth-child(3) { color: var(--muted); font-weight: 500; }

@media (max-width: 900px) {
  .cr-grid { grid-template-columns: 1fr; }
  .cr-hero { flex-direction: column; align-items: stretch; }
  .cr-topup { width: 100%; }
}

/* The collapsed tail of the per-workspace list. A button, not a div, so it is reachable by
   keyboard and announces its own state. */
.cr-wsmore { width: 100%; border: 0; background: transparent; color: inherit; font: inherit;
  cursor: pointer; text-align: left; padding: 7px 0; }
.cr-wsmore:hover .cr-wsname { color: var(--text); }
.cr-wsmore .cr-wsname { display: inline-flex; align-items: center; gap: 5px; color: var(--muted); }
.cr-chev { width: 13px; height: 13px; transition: transform .15s ease; }
.cr-wsmore[aria-expanded="true"] .cr-chev { transform: rotate(180deg); }
.cr-wsrest { padding-left: 18px; border-left: 1px solid var(--border); margin: 2px 0 2px 4px; }
.cr-wsrest .cr-wsname { font-size: .82rem; color: var(--muted); }

/* Read-only value on a Settings row — right-aligned like the controls it sits among, so the
   column of values still lines up when some rows are inputs and others are facts. */
.set-ro { flex: 0 0 auto; font-size: .92rem; font-weight: 600; color: var(--text); }

/* Username: a fact with an edit affordance, not a form that is always open. */
.set-profile { display: flex; align-items: center; gap: 8px; }
.set-ro.unset { color: var(--muted); font-weight: 500; font-style: italic; }
.set-iconbtn { display: grid; place-items: center; width: 30px; height: 30px; padding: 0;
  border: 1px solid transparent; border-radius: 8px; cursor: pointer;
  background: transparent; color: var(--muted); transition: color .12s, background .12s, border-color .12s; }
.set-iconbtn:hover { color: var(--text); background: var(--card-2, rgba(255,255,255,.05));
  border-color: var(--border-hi, var(--border)); }
.set-iconbtn svg { width: 15px; height: 15px; }
.set-profile input.select { width: 200px; }

/* ---------- Admin: the two halves ---------- */
.admin-sections { display: inline-flex; gap: 4px; padding: 4px; margin-bottom: 16px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; }
.admin-section { padding: 7px 18px; border-radius: 999px; border: 0; cursor: pointer;
  background: transparent; color: var(--muted); font: inherit; font-weight: 600; font-size: .85rem; }
.admin-section.on { background: var(--accent); color: var(--on-accent); }

/* ---------- Admin > Analytics ---------- */
.schart-legend { display: flex; align-items: center; gap: 16px; margin-bottom: 12px;
  font-size: .76rem; color: var(--muted); flex-wrap: wrap; }
.schart-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  margin-right: 5px; vertical-align: -1px; }
.dot-clips { background: #5cc8ff; } .dot-users { background: #a78bfa; }
/* Two series, one column per day. The clip bar sits in front at partial opacity so the user
   bar behind it stays readable — stacking them would add two numbers that share no unit. */
.schart-wrap { position: relative; }
/* Columns are capped and centred. Left to fill the width, seven days became seven slabs the
   size of playing cards — the same data as thirty days, rendered as something that no longer
   looks like a chart. */
.schart { display: flex; align-items: flex-end; justify-content: center;
  gap: 3px; height: 130px; }

.schart-tip {
  position: absolute; bottom: calc(100% + 10px); z-index: 5; min-width: 176px;
  padding: 9px 11px; border-radius: 10px; pointer-events: none;
  background: var(--surface-2); border: 1px solid var(--border-hi);
  box-shadow: 0 10px 26px rgba(0,0,0,.5);
  opacity: 0; transition: opacity .12s;
}
.schart-wrap.on .schart-tip { opacity: 1; }
.stip-d { font-size: .74rem; font-weight: 700; margin-bottom: 6px; color: var(--text); }
/* A label column and a number column, right-aligned: four figures on one wrapped line is the
   slowest way to read four figures, which is what the native title attribute gave. */
.stip-row { display: flex; justify-content: space-between; gap: 18px;
  font-size: .74rem; color: var(--muted); line-height: 1.7; white-space: nowrap; }
.stip-row b { color: var(--text); font-variant-numeric: tabular-nums; }
.sbar {
  flex: 1 1 0; height: 100%; max-width: 44px; min-width: 3px; padding: 0 2px;
  display: flex; align-items: flex-end; justify-content: center; gap: 2px;
  border-radius: 3px; background: rgba(255,255,255,.03);
}
.sbar:hover, .sbar.on { background: rgba(255,255,255,.09); }
/* The two series share the column and split its width; the cap stops a 7-day range turning
   each one into a slab. min-height 0 so a zero day is genuinely nothing, not a stub. */
.sbar > span { flex: 1 1 0; max-width: 14px; min-height: 0; }
.sbar-users { background: #a78bfa; border-radius: 3px 3px 0 0; }
.sbar-clips { background: #5cc8ff; border-radius: 3px 3px 0 0; }
.schart-axis { display: flex; justify-content: space-between; margin-top: 6px; }

/* Nine columns of numbers. Tabular figures so the digits line up down the column, and the
   counts right-aligned so magnitudes are comparable at a glance rather than by reading. */
#adminStatsPane .admin-table td, #adminStatsPane .admin-table th { white-space: nowrap; }
#adminStatsPane .admin-table td:not(:first-child):not(:nth-child(2)),
#adminStatsPane .admin-table th:not(:first-child):not(:nth-child(2)) {
  text-align: right; font-variant-numeric: tabular-nums;
}
#adminStatsPane .admin-table td:last-child, #adminStatsPane .admin-table th:last-child { text-align: left; }
#adminStatsPane .ao-pb.flush { overflow-x: auto; }
.sfunnel-row { display: grid; grid-template-columns: 1fr 2fr auto; align-items: center;
  gap: 10px; padding: 6px 0; }
.sfunnel-lbl { font-size: .82rem; }
.sfunnel-track { height: 8px; border-radius: 4px; background: rgba(255,255,255,.06); overflow: hidden; }
.sfunnel-track i { display: block; height: 100%; border-radius: 4px;
  background: linear-gradient(90deg, #5cc8ff, #a78bfa); }
.sfunnel-n { font-size: .82rem; font-weight: 700; white-space: nowrap; }


/* ---------- the bell, when something is unread ----------
   Every 6 seconds, not continuously: a permanently shaking icon becomes wallpaper within a
   minute and is then ignored precisely when it matters. The pause is what keeps it a signal. */
@keyframes bellShake {
  0%, 82%, 100% { transform: rotate(0); }
  84% { transform: rotate(-13deg); } 86% { transform: rotate(11deg); }
  88% { transform: rotate(-9deg); }  90% { transform: rotate(7deg); }
  92% { transform: rotate(-4deg); }  94% { transform: rotate(2deg); }
}
.notif-btn.has-unread svg { animation: bellShake 6s ease-in-out infinite; transform-origin: 50% 15%; }
@media (prefers-reduced-motion: reduce) { .notif-btn.has-unread svg { animation: none; } }


/* ---------- Interaction: pick one, or several to roll between ---------- */
.inter-picker { display: grid; gap: 4px; padding: 6px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--border); }
.inter-opt { display: grid; grid-template-columns: auto auto 1fr; align-items: center;
  gap: 9px; padding: 7px 9px; border-radius: 8px; cursor: pointer; }
.inter-opt:hover { background: var(--card-2); }
.inter-opt input { accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; }
.inter-opt:has(input:checked) { background: var(--accent-weak); }
.inter-name { font-size: .85rem; font-weight: 600; white-space: nowrap; }
.inter-note { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- story angle: a line on the page, a drawer beside it ---------------------------
   Seven written pitches carry about twenty lines of prose between them, and they were the
   tallest thing in the column — the questions that still needed answering sat above a wall of
   text about films nobody had chosen. So the page keeps one line naming what is in force, and
   the comparison happens in a drawer that owes the layout nothing. */
/* The card's own 14/16 padding is switched off: this one is a single row, and the row brings
   its own. Without it the bar was 81px tall for one line of text. */
#angleCard.angle-bar { padding: 0; }
.angle-bar > div { display: flex; align-items: center; gap: 12px; padding: 12px 16px; }
.angle-bar-lbl { flex: none; font-family: "Space Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint); }
.angle-bar-txt { flex: 1; min-width: 0; font-size: 13.5px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.angle-bar .btn-ghost { flex: none; }

/* SHUT, IT IS A TAB ON THE EDGE with the number in play on it — the one fact the page still has
   to carry when the drawer is closed. */
.angle-tab { position: fixed; right: 0; top: 46%; z-index: 40; display: grid; justify-items: center;
  gap: 8px; padding: 14px 7px; border: 1px solid var(--border); border-right: 0;
  border-radius: 12px 0 0 12px; background: var(--surface); color: var(--text-muted);
  font: inherit; cursor: pointer; transition: color .14s, border-color .14s; }
.angle-tab:hover { color: var(--text); border-color: var(--accent-border); }
.at-lbl { writing-mode: vertical-rl; font-size: 11.5px; letter-spacing: .02em; }
.at-chev { font-size: 14px; line-height: 1; }
.at-n { min-width: 20px; padding: 1px 6px; border-radius: 999px; background: var(--accent);
  color: var(--on-accent); font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }

.angle-drawer { position: fixed; right: 0; top: 64px; bottom: 0; width: min(520px, 92vw);
  z-index: 60; display: flex; flex-direction: column;
  border-left: 1px solid var(--border); background: var(--bg);
  box-shadow: -18px 0 46px rgba(0,0,0,.45); }
.ad-head { display: flex; align-items: baseline; gap: 10px; padding: 16px 18px 12px;
  border-bottom: 1px solid var(--border); }
.ad-head b { font-size: 16px; font-weight: 650; }
.ad-count { font-family: "Space Mono", ui-monospace, monospace; font-size: 11px;
  color: var(--text-faint); }
.ad-x { margin-left: auto; width: 26px; height: 26px; border-radius: 50%; flex: none;
  border: 1px solid var(--border); background: transparent; color: var(--text-muted);
  font-size: 15px; line-height: 1; cursor: pointer; }
.ad-x:hover { color: var(--text); border-color: var(--border-strong); }

/* The list scrolls; the footer does not. The two buttons that spend credits have to stay
   reachable from the bottom of a list of seven. */
.ad-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 14px 18px; display: grid; grid-auto-rows: max-content;
  gap: 8px; align-content: start; }
.ad-row { border: 1px solid var(--border); border-radius: 12px; background: var(--surface);
  transition: border-color .14s, background .14s; }
.ad-row.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.ad-top { display: flex; align-items: center; gap: 10px; padding: 11px 12px; }
/* The tick and the title choose it; the caret reads it. One control doing both is how somebody
   who wanted to read one ends up having committed to it. */
.ad-tick { flex: none; width: 21px; height: 21px; border-radius: 50%; cursor: pointer;
  border: 1.5px solid var(--border-hi); display: grid; place-items: center;
  font-size: 12px; line-height: 1; color: #fff; }
.ad-row.on .ad-tick { background: var(--accent); border-color: var(--accent); }
.ad-title { flex: 0 1 auto; min-width: 0; font-size: 14.5px; font-weight: 650; cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-chip { flex: none; padding: 2px 9px; border-radius: 999px; font-size: 11px;
  background: var(--surface-2); color: var(--text-muted); }
/* A BORDER, because it is a button. Borderless and faint it read as decoration on the row —
   and it is the only way to find out what an angle actually says, so it has to look pressable
   before anyone has hovered anything. */
.ad-caret { flex: none; margin-left: auto; width: 26px; height: 26px; border-radius: 7px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-muted);
  cursor: pointer; font-size: 12px; line-height: 1;
  transition: color .14s, border-color .14s, background .14s; }
.ad-caret:hover { color: var(--text); border-color: var(--border-strong); background: var(--card-2); }
.ad-row.on .ad-caret { border-color: var(--accent-border); color: var(--text); }

.ad-body { padding: 0 12px 12px 43px; display: grid; gap: 7px; }
.ad-body p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text); }
.ad-body .ad-dim { color: var(--text-muted); font-size: 12.5px; }
.ad-body-foot { display: flex; align-items: center; gap: 10px; }
.ad-tone { flex: 1; font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .04em; color: var(--text-faint); }
.ad-body-acts { display: flex; align-items: center; gap: 6px; }
.ad-del { width: 24px; height: 24px; border-radius: 7px; border: 1px solid var(--border);
  background: transparent; color: var(--text-faint); cursor: pointer; font-size: 13px; }
.ad-del:hover { color: var(--danger); border-color: var(--danger); }

/* WAITING, WITH SOMETHING TO LOOK AT. The writer takes about twenty seconds and the list was
   empty for all of it — an empty panel after a press reads as a button that did nothing. */
.ad-think { display: grid; justify-items: center; gap: 10px; padding: 54px 24px; text-align: center; }
.ad-think b { font-size: 14px; font-weight: 640; }
.ad-think-sub { font-size: 12px; color: var(--text-faint); max-width: 30ch; line-height: 1.5; }
.ad-bulb { width: 54px; height: 54px; border-radius: 50%; display: grid; place-items: center;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  animation: adGlow 1.8s ease-in-out infinite; }
.ad-bulb svg { width: 26px; height: 26px; }
@keyframes adGlow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 34%, transparent); opacity: .72; }
  50%      { box-shadow: 0 0 0 12px color-mix(in srgb, var(--accent) 0%, transparent); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .ad-bulb { animation: none; } }

.ad-foot { flex: none; padding: 12px 18px 16px; border-top: 1px solid var(--border);
  display: grid; gap: 10px; }
.ad-note { font-size: 12px; color: var(--text-muted); }
.ad-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.angle-price { font-weight: 500; color: var(--text-faint); }

/* The editor, in place of the row it edits. */
.ad-row.editing { padding: 12px; display: grid; gap: 8px; }
.angle-field { display: grid; gap: 3px; }
.angle-field > span { font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-faint); }
.angle-field input, .angle-field textarea { width: 100%; padding: 7px 9px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  font: inherit; font-size: .82rem; line-height: 1.45; resize: vertical; }
.angle-field input:focus, .angle-field textarea:focus { outline: none; border-color: var(--accent); }
.angle-edit-foot { display: flex; justify-content: flex-end; gap: 8px; }

@media (max-width: 720px) { .angle-drawer { width: 100vw; top: 0; } }

/* An actionable toast: the message names a screen, this goes there.
   The base .toast sets pointer-events:none so it never blocks what's underneath it — correct
   for a message, fatal for one with a button. Re-enable it only on the button itself, so the
   rest of the toast still lets clicks through. */
.toast.has-act { display: flex; align-items: center; gap: 14px; }
.toast .toast-act { pointer-events: auto; }
.toast-act { flex: none; padding: 5px 12px; border-radius: var(--r-pill); cursor: pointer;
  border: 1px solid currentColor; background: none; color: inherit;
  font: inherit; font-size: .8rem; font-weight: 700; white-space: nowrap; }
.toast-act:hover { background: var(--text); color: var(--bg); border-color: var(--text); }


/* ---------- segmented pill: two exclusive choices, side by side ----------
   Liquid glass. The selected state is a single pane that SLIDES between the two halves rather
   than a background switching off one label and on the other: the movement is what tells you a
   choice was made, and it survives being watched out of the corner of your eye.

   The pane is one element (::before) precisely so it can travel. Two elements fading in and out
   cannot slide, and that is the whole effect. */
/* N options, not two. The track was `1fr 1fr` with a half-width thumb and a single "last child
   checked → translateX(100%)" rule, so a third option wrapped the grid onto two rows and left
   the thumb covering an area no longer under any label. Both the columns and the thumb are
   derived from --seg-n now, and the thumb steps by whole slots. */
.seg-pill {
  --seg-n: 2;
  position: relative; display: grid; grid-template-columns: repeat(var(--seg-n), 1fr); gap: 0; padding: 5px;
  border-radius: var(--r-pill); isolation: isolate;
  /* The TRACK is a hollow: darker than the page, so the thumb has something to sit proud of. */
  background: linear-gradient(180deg, rgba(0,0,0,.22), rgba(0,0,0,.10));
  border: 1px solid rgba(255,255,255,.08);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.35), inset 0 -1px 0 rgba(255,255,255,.05);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  backdrop-filter: blur(14px) saturate(150%);
}
.seg-pill::before {
  content: ""; position: absolute; z-index: 0; top: 5px; bottom: 5px; left: 5px;
  width: calc((100% - 10px) / var(--seg-n)); border-radius: var(--r-pill);
  /* Glass, not paint. The old thumb was an opaque violet capsule with a sheen drawn on top —
     a coloured button, which is a different object entirely. Real glass has no colour of its
     own: what you see through it is the page, lifted. `brightness()` inside backdrop-filter is
     what does that lifting, and it is the single cue that reads as glass rather than as a
     translucent overlay. The gradient on top is only the sheen the surface catches. */
  background: linear-gradient(180deg,
    rgba(255,255,255,.26), rgba(255,255,255,.06) 42%, rgba(255,255,255,.13));
  border: 1px solid rgba(255,255,255,.38);
  box-shadow:
    inset 0 1px 1px rgba(255,255,255,.6),     /* the rim where light catches the top edge */
    inset 0 -1px 1px rgba(255,255,255,.2),    /* and the weaker one underneath */
    inset 0 0 20px rgba(255,255,255,.05),     /* body, so the middle is not flat */
    0 8px 22px rgba(0,0,0,.45),               /* the shadow that lifts it off the track */
    0 1px 2px rgba(0,0,0,.3);
  -webkit-backdrop-filter: blur(12px) saturate(200%) brightness(1.35);
  backdrop-filter: blur(12px) saturate(200%) brightness(1.35);
  /* Overshoots a little on the way — the "liquid" part. */
  transition: transform .5s cubic-bezier(.34, 1.42, .42, 1);
}
/* By position, so it works for any count — the thumb is one slot wide, so one slot is 100%. */
.seg-pill:has(.seg-opt:nth-child(2) input:checked)::before { transform: translateX(100%); }
.seg-pill:has(.seg-opt:nth-child(3) input:checked)::before { transform: translateX(200%); }
.seg-pill:has(.seg-opt:nth-child(4) input:checked)::before { transform: translateX(300%); }

.seg-opt { position: relative; z-index: 1; cursor: pointer; }
/* The radio still exists and still carries the value — it is only visually replaced, so keyboard
   focus, form semantics and every `input[name=…]:checked` reader keep working. */
.seg-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.seg-face {
  display: flex; flex-direction: column; gap: 1px; align-items: center;
  padding: 9px 12px; border-radius: var(--r-pill); text-align: center;
  color: var(--muted); transition: color .35s, text-shadow .35s;
}
.seg-face b { font-size: .86rem; font-weight: 600; }
.seg-note { font-size: .7rem; opacity: .85; line-height: 1.25; }
/* Three narrow columns leave no room for a comfortable inline note; the label carries the
   choice and the note explains it underneath in a smaller, tighter measure. */
.seg-pill[style*="--seg-n: 3"] .seg-face, .seg-pill[style*="--seg-n:3"] .seg-face { padding: 9px 8px; }
.seg-pill[style*="--seg-n: 3"] .seg-face b, .seg-pill[style*="--seg-n:3"] .seg-face b { font-size: .82rem; }
.seg-pill[style*="--seg-n: 3"] .seg-note, .seg-pill[style*="--seg-n:3"] .seg-note { font-size: .66rem; }
/* Narrow screens keep every pill HORIZONTAL. Stacking used to kick in here, and it threw away
   the one thing the shape is for: mutually exclusive states read as a single choice when they sit
   left and right, and as a row of separate switches when they sit above and below. The type
   gives way instead — the labels are one or two words, and it is the notes under them that
   stopped fitting, not the choice itself. */
@media (max-width: 620px) {
  .seg-face { padding: 8px 6px; }
  .seg-face b { font-size: .82rem; }
  .seg-note { font-size: .64rem; line-height: 1.2; }
  /* Three across is where a phone actually runs out of room: ~110px a column. */
  .seg-pill:has(.seg-opt:nth-child(3)) .seg-face { padding: 8px 3px; }
  .seg-pill:has(.seg-opt:nth-child(3)) .seg-face b { font-size: .78rem; }
  .seg-pill:has(.seg-opt:nth-child(3)) .seg-note { font-size: .6rem; }
}
.seg-opt:hover .seg-face { color: var(--text); }
/* Neutral shadow, not violet: there is no violet left to sit on, and a coloured shadow under
   white text on clear glass reads as a printing error. */
.seg-opt input:checked + .seg-face {
  color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.55);
}
.seg-opt input:checked + .seg-face .seg-note { opacity: .92; }
/* Hiding the native radio hides the native focus ring with it; without this a keyboard user
   cannot see where they are. */
.seg-opt input:focus-visible + .seg-face {
  box-shadow: 0 0 0 2px rgba(255,255,255,.55), 0 0 0 4px hsl(258 90% 60% / .45);
}
@media (prefers-reduced-motion: reduce) {
  .seg-pill::before { transition: none; }
}
@media (max-width: 520px) {
  .seg-note { display: none; }          /* the label alone still says which is which */
}

/* Reel length sits under the Content style pill and only exists in story mode. */
/* ---------- starred workspaces ---------- */
/* Top-right, out of the hover action bar at the bottom — a pin is a property of the card, not
   one of the things you do to it, and it has to be readable without hovering to be worth having. */
.wsp-star {
  position: absolute; top: 12px; right: 12px; z-index: 3;
  display: grid; place-items: center; width: 28px; height: 28px; padding: 0;
  background: none; border: 0; border-radius: 8px; cursor: pointer;
  color: var(--faint); opacity: 0; transition: opacity .15s, color .15s, transform .15s;
}
/* Dissolved on a desktop, so the star and the status stay the card's own absolutely
   positioned children exactly as before. It is a real box only on a phone. */
.wsp-tail { display: contents; }
.wsp-star svg { width: 17px; height: 17px; fill: none; }
.wsp-card:hover .wsp-star { opacity: 1; }
.wsp-star:hover { color: #f5c451; transform: scale(1.12); }
.wsp-star:focus-visible { opacity: 1; box-shadow: 0 0 0 2px var(--accent-border); }
/* Starred stays lit whether or not the pointer is anywhere near it — that is the entire point. */
.wsp-star.on { opacity: 1; color: #f5c451; }
.wsp-star.on svg { fill: #f5c451; }
.wsp-card:has(.wsp-star.on) { border-color: rgba(245,196,81,.28); }

/* The ★ chip is a glyph, not a word — it needs its own width or it sits half the size of its
   neighbours, and its own colour when active so it reads as the same star on the cards. */
.ws-filter-b[data-f="starred"] { min-width: 34px; font-size: 1rem; line-height: 1; }
.ws-filter-b[data-f="starred"].is-on { color: #f5c451; }

/* ---------- pagination ---------- */
.pager { display: flex; align-items: center; justify-content: center; gap: 4px;
  margin: 22px 0 8px; flex-wrap: wrap; }
.pager:empty { display: none; }          /* one page → no chrome at all */

/* Numbers and arrows share a footprint so the row does not jog as the digits grow. */
.pager-n, .pager-b {
  min-width: 34px; height: 34px; padding: 0 9px; border-radius: 8px; cursor: pointer;
  font: inherit; font-size: .85rem; font-weight: 600; font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent; color: var(--muted);
  transition: background .12s, color .12s, border-color .12s;
}
.pager-n:hover, .pager-b:hover:not(:disabled) { background: var(--card-2); color: var(--text); }
.pager-n.on {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
  box-shadow: 0 2px 10px hsl(258 90% 55% / .35);
}
.pager-n.on:hover { background: var(--accent); color: var(--on-accent); }
.pager-b.pager-arrow { font-size: 1.15rem; line-height: 1; }
.pager-b:disabled { opacity: .3; cursor: default; }
/* Not a button: it is the shape of a gap, and making it look clickable invites a click that
   cannot do anything. */
.pager-gap { min-width: 26px; text-align: center; color: var(--faint); user-select: none; }
.pager-at { margin-left: 10px; font-size: .78rem; font-variant-numeric: tabular-nums; }

/* The References list is a narrow column beside the preview, so its pager shrinks. */
.pager-compact { margin: 10px 0 2px; gap: 2px; }
.pager-compact .pager-n, .pager-compact .pager-b { min-width: 28px; height: 28px; padding: 0 6px; font-size: .78rem; }


/* ---- "Vary between clips": the named axes ---- */
/* Auto-fit rather than a fixed column count: this pane is the same markup in the Presets editor
   (wide) and inside the new-preset drawer (narrow), and a hard-coded grid would leave one of
   the two either cramped or half empty. */
.vary-grid { display: grid; gap: 8px; margin-top: 8px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.vary-opt { display: flex; align-items: flex-start; gap: 9px; padding: 9px 11px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2);
  transition: border-color .15s, background .15s; }
.vary-opt:hover { border-color: var(--border-hi); }
.vary-opt input { margin: 2px 0 0; accent-color: var(--accent); flex: none; }
.vary-opt.on { border-color: var(--accent-border); background: var(--accent-weak); }
.vary-opt b { display: block; font-size: .86rem; font-weight: 600; }
.vary-opt span { display: block; font-size: .76rem; color: var(--muted); margin-top: 2px; }

/* "Active, but nothing is there to run it." Amber rather than the paused grey: the creator did
   not do this, and it needs looking at — unlike a workspace they paused on purpose. */
.wsp-status.stalled { color: var(--warn); }
.wsp-status.stalled .orb-dot { background: var(--warn); }

/* Matches the 96px subtracted above (72 top + 24 bottom). The page does not scroll here, so the
   generous bottom padding every other view wants is only dead space. */
.app:has(.view-references.active) .main { padding-bottom: 24px; overflow: hidden; }

/* A <video> with no metadata yet falls back to the CSS default 300x150, and `max-height: 100%`
   never fires because 150px is already under it — so the current slide rendered as a squashed
   strip with black above and below until it loaded. An explicit height takes the intrinsic size
   out of it; object-fit still preserves the aspect inside that box. */
.clip-slide video { height: 100%; }

/* "▶ Playing" sat at the same top-left corner as the workspace pill and overlapped it. Folded
   into the overlay's own column so the two stack instead, with the pill first. */
.lib-card.playing .lib-thumb-wrap::after { content: none; }
.lib-card.playing .lib-overlay::after {
  content: "▶ Playing"; order: 1;
  padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--accent); color: var(--on-accent);
  font-size: .64rem; font-weight: 700; letter-spacing: .04em;
}
.lib-overlay .lib-actions { order: 2; }

/* ---- admin: workspace settings drawer ---- */
/* Slides over the page rather than pushing it: the table underneath is the context you clicked
   from, and reflowing it on open loses your place in a 100-row list. */
.admin-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(460px, 92vw); z-index: 60;
  background: var(--surface); border-left: 1px solid var(--border);
  display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .28s cubic-bezier(.22,.61,.36,1);
  box-shadow: -20px 0 48px rgba(0,0,0,.42);
}
.admin-drawer.open { transform: translateX(0); }
.admin-drawer-head {
  flex: none; display: flex; align-items: center; gap: 10px;
  padding: 16px 18px; border-bottom: 1px solid var(--border);
}
.admin-drawer-head h2 { margin: 0; font-size: 1rem; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-drawer-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 4px 18px 28px; }
.admin-drawer-body .log-settings { width: 100%; }

/* The Autopilots table is a list of things to open, so it has to look like one. */
.log-ap-row { cursor: pointer; }
.log-ap-row:hover, .log-ap-row:focus-visible { background: var(--accent-weak); outline: none; }

/* Started by hand, not by the schedule — the same ⚡ the activity feed uses. */
.log-manual { color: var(--accent); margin-left: 4px; }

/* ---- combo: free-text input with a full suggestion list (replaces <datalist>) ---- */
.combo { position: relative; }
/* The caret is the input's own, drawn here so it reads as a control rather than decoration.
   Bigger than a text glyph wants to be: at .8rem it was a few pixels of ink that looked like
   something to aim at and was not — pointer-events are off, so the click lands on the input
   underneath, and the target is the whole field. Sizing it to match says so. */
.combo::after {
  content: "▾"; position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
  color: var(--muted); pointer-events: none; font-size: 1.05rem; line-height: 1;
}
.combo:focus-within::after { color: var(--accent); }
/* Room for the caret so a long value does not run under it. */
.combo > input { padding-right: 36px; }
.combo-list {
  /* fixed + body-mounted: see attachCombo. Any scrolling ancestor would clip an absolute one. */
  position: fixed; z-index: 200; overflow-y: auto;
  background: var(--surface-2); border: 1px solid var(--border-hi); border-radius: 10px;
  box-shadow: 0 18px 40px rgba(0,0,0,.45); padding: 4px;
}
.combo-opt {
  display: block; width: 100%; text-align: left; padding: 8px 10px; border: 0;
  border-radius: 7px; background: none; color: var(--text); font: inherit;
  font-size: .86rem; cursor: pointer;
}
.combo-opt:hover { background: var(--accent-weak); }
.combo-opt.on { color: var(--accent); font-weight: 600; }
.combo-none { padding: 8px 10px; color: var(--muted); font-size: .8rem; }
/* A list that scrolls has to look like one — with the default overlay scrollbar there was
   nothing on screen to say the seventh row was not the last. */
.combo-list { scrollbar-width: thin; scrollbar-color: var(--border-hi) transparent; }
.combo-list::-webkit-scrollbar { width: 8px; }
.combo-list::-webkit-scrollbar-thumb { background: var(--border-hi); border-radius: 99px; }

/* ---- number inputs: dark steppers ---- */
/* The native spinner is painted by the browser in its own light palette and is not styleable;
   hidden here and replaced by buttons that belong to this theme. See enhanceNumberInputs. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

.numfield { position: relative; display: block; }
.numfield > input { width: 100%; padding-right: 34px; }
.num-steps {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 1px;
}
.num-step {
  display: flex; align-items: center; justify-content: center;
  width: 20px; height: 13px; padding: 0; border: 0; border-radius: 4px;
  background: rgba(255,255,255,.05); color: var(--muted);
  font-size: 7px; line-height: 1; cursor: pointer;
  transition: background .12s, color .12s;
}
.num-step:hover { background: var(--accent-weak); color: var(--accent); }
.num-step:active { transform: translateY(.5px); }
/* Hidden until the field is worth interacting with — a permanent pair of arrows on every
   number field is visual noise on a form that is mostly read. */
.num-steps { opacity: 0; transition: opacity .15s; }
.numfield:hover .num-steps, .numfield:focus-within .num-steps { opacity: 1; }

/* ---- schedule card: a timezone that fits its row ---- */
/* The label and the select were a full-width flex row, so the select stretched to the card edge
   and the word "Timezone" sat marooned at the far left of a gap. The select says "UTC+8" — it
   does not need a word in front of it — and it is sized to its content. */
.sched-tz { flex: none; width: auto; max-width: 140px; font-size: .8rem; padding: 7px 30px 7px 11px; }

/* A posting time is editable in place — the label is a button, and it says so on hover. */
/* font-FAMILY, not the `font` shorthand: the shorthand resets size and weight, and this rule
   comes after the one above that makes the time bold — so `font: inherit` would quietly undo it. */
/* Two ways in, because a clickable label advertises nothing: the pencil sits beside the trash
   where the row's other action already is, and the time itself stays clickable as the shortcut
   for anyone who tries it. The dotted underline is what says "this text is the field". */
/* Both carry `margin-left: auto` from .time-row-x, which would push each to the right of the
   other and split the pair across the row. The first keeps the auto (it moves the pair right);
   the one that follows it sits flush against it. */

/* Library toolbar pickers — sized to their content so they sit beside the search box rather
   than stretching to a column each. */
.lib-pick { width: auto; min-width: 132px; flex: none; padding: 9px 30px 9px 12px; font-size: .85rem; }


/* ================= phone: card menu + step bar =================
   These sit at the END on purpose. The desktop rules they have to beat — `.wsp-card:hover
   .wsp-actions { opacity: 1 }` among them — are declared further down the file than the phone
   media query above, and at equal specificity the later rule wins. Written up there, every one
   of these was silently overridden: the action menu opened on any hover and the ⋯ landed at the
   head of the row instead of its tail. */
@media (max-width: 760px) {
  /* Tail of the row. It is the first child in the DOM because the menu it opens must render
     above the card's own content; `order` moves it without changing the stacking. */
  .wsp-more { order: 9; margin-left: auto; }

  /* Hover is not an input a phone has. Without these the desktop reveal fires on the tap that
     focuses the card and the menu appears without anyone asking for it. */
  .wsp-card:hover .wsp-actions, .wsp-card:focus-within .wsp-actions {
    opacity: 0; transform: scale(.96); pointer-events: none; }
  .wsp-card.menu-open .wsp-actions,
  .wsp-card.menu-open:hover .wsp-actions,
  .wsp-card.menu-open:focus-within .wsp-actions { opacity: 1; transform: none; pointer-events: auto; }
  .wsp-actions {
    position: absolute; right: 8px; top: 46px; left: auto; bottom: auto; z-index: 20;
    flex-direction: column; gap: 2px; padding: 6px; border-radius: 12px;
    background: var(--card); border: 1px solid var(--border-hi); box-shadow: var(--shadow);
    transition: opacity .12s, transform .12s;
  }
  .wsp-act { width: 38px; height: 38px; }
  /* The star was absolutely positioned into the same corner the status pill occupies in a row
     layout, so the two sat on top of each other. In the flow it becomes what the row already
     reads as: a mark on the name, before the status. */
  .wsp-id { order: 1; }
  /* A column at the end of the row: status on top, the star it belongs to underneath. Both were
     absolutely positioned into the card's top-right corner, which in a row layout is the same
     spot — they sat on top of each other. */
  /* The tile at the end of the list goes: the header carries "+ New workspace" a thumb-width
     away, and as a list row this was a second entry point wearing the same clothes as the
     workspaces around it. The EMPTY state keeps its own create control — that is .ws-empty,
     a different element, and the only thing on the screen when it shows. */
  .wsp-card.new { display: none; }

  /* A screenful, then the rest on request. Sixteen rows push the whole page below them out of
     reach, and the list is not why most visits happen. The cut is by ROW COUNT, not a pixel
     height — a row with a progress bar is taller than one without, and a max-height sized for
     one clips the other mid-line. */
  .ws-picker-grid.is-clamped > .wsp-card:nth-child(n+5) { display: none; }
  .ws-picker-grid { position: relative; }
  /* The fade is a MASK on the rows, so the button cannot live inside it — a masked element
     fades its children too, and the control would dim along with the row it sits on. It is
     positioned over the grid instead, which the mask does not reach. */
  /* The row ABOVE the pill is the one that fades, and nothing is drawn below it — a half-visible
     row underneath reads as content the pill happens to be covering, not as the list running out.
     Its own bottom hairline goes too: a hard line under a fading row is the fade contradicting
     itself. */
  .ws-picker-grid.is-clamped > .wsp-card:nth-child(4) {
    -webkit-mask-image: linear-gradient(#000 6%, rgba(0,0,0,.3) 55%, transparent 96%);
    mask-image: linear-gradient(#000 6%, rgba(0,0,0,.3) 55%, transparent 96%);
    border-bottom: 0; pointer-events: none; }
  /* Room for the half of the pill that hangs below the last row. */
  .ws-picker-grid.is-clamped { padding-bottom: 24px; }

  /* Floating over the fade, sized to its label — the shape says "there is more underneath",
     which a full-width bar sitting below the list does not. */
  /* No hairline. A border draws a second edge around a shape whose silhouette is already the
     whole point, and against a row that is fading out it reads as an outline sitting on top of
     the content. The pill is DARKER than the rows it floats over — that separation is what a
     border would otherwise have to do. */
  .ws-more { display: inline-block; margin: 12px auto 0; padding: 11px 22px;
    border: 0; border-radius: 999px; background: var(--bg);
    box-shadow: 0 6px 24px rgba(0,0,0,.5);
    color: var(--text); font: inherit; font-size: .9rem; font-weight: 600; cursor: pointer;
    white-space: nowrap; -webkit-tap-highlight-color: transparent; }
  .ws-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  /* Centred ON the faded row, not below it — that row is the thing being faded out, and the
     button standing in front of it is what makes the cut read as deliberate. */
  /* `left: 50%` alone caps the shrink-to-fit width at HALF the grid — an absolutely positioned
     box gets only the space from its left edge to the container's right edge — so the label wrapped
     to two lines and the pill inflated into a blob. nowrap above keeps it one line; the transform
     still centres it. */
  /* Centred on the line where the list ends — `bottom: 24px` is the content edge (the grid's own
     padding sits outside it), and `translateY(50%)` drops the pill by half its height so that
     line runs through its middle, whatever the label's length does to its size. */
  .ws-picker-grid.is-clamped > .ws-more {
    position: absolute; left: 50%; bottom: 24px; transform: translate(-50%, 50%);
    margin: 0; z-index: 4; }

  .ws-more:active { background: var(--surface-2); }
  .ws-more.hidden { display: none; }

  .wsp-tail { order: 3; display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
    flex: none; }
  .wsp-star { position: static; flex: none; width: 24px; height: 24px; opacity: 1; }
  .wsp-status { position: static; flex: none; align-self: flex-end; }

  /* The step bar used to be dropped here entirely: five words across the top of every screen in
     the flow, on a viewport that has none to spare. A rail and one line of small type cost about
     20px, so it stays — it is now cheaper than the ✕ beside it. */

  /* ---- "Your workspaces" header ----
     Four stacked rows, each sized to its content: a title, a search box that stopped short of
     the edge, a chip row, and a button floating alone under it. The pieces are the same; what
     was missing is that a phone has one axis, so anything not sharing a row has to earn its
     own — and "New workspace" does not, it belongs beside the title it acts on. */
  /* `display: contents` above dissolves this group on a desktop; here it has to be a real box
     again so the title and the button can share a row of their own. The desktop `order`s go
     with it — they only mean anything while the children are the header's. */
  .ws-head { display: block; }
  .ws-head-titles { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
  .ws-head-title, .ws-head-tools, .ws-head-new { order: 0; }
  .ws-head-tools { display: block; margin: 12px 0 0; }
  .ws-search { display: flex; width: 100%; }
  .ws-search input { width: 100%; }
  /* Full width, shared evenly. Sized to their labels they left a gap at the right end that read
     as a sixth chip that had failed to load, and the row is a segmented control — the segments
     of one of those are equal by definition. ★ keeps its own width: it is a glyph, and giving
     it the same share as "Generating" would make it a mostly-empty box. */
  .ws-filter { display: flex; flex-wrap: nowrap; width: 100%; margin-top: 10px; }
  /* Shared by LABEL LENGTH, not equally: equal shares cut "Generating" to "Generati…" on a
     390px phone while "All" sat in a mostly empty box (launch audit, 2026-10-12). */
  .ws-filter-b { flex: 1 1 auto; min-width: 0; padding: 8px 6px; font-size: .8rem;
    white-space: nowrap; }
  .ws-filter-b[data-f="starred"] { flex: 0 0 auto; padding: 8px 12px; }
  /* Into the title row, and sized to its label — the full-width bar it was reads as the page's
     primary action, which it is not; the list underneath is. */
  .ws-head-new { flex: none; margin: 0; padding: 9px 14px; font-size: .85rem; }
  .ws-head-new svg { width: 15px; height: 15px; }

  /* ---- Library on a phone ---- */
  /* One 9:16 thumbnail per row is nearly a full screen of scrolling per clip — you cannot
     compare two takes, and finding the one you want means remembering it. Two columns turn
     the page back into something you scan. */
  .lib-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .lib-card { border-radius: 10px; }
  .lib-meta { padding: 8px 9px; }
  .lib-meta .cap { font-size: .74rem; }
  /* The per-clip detail lines are the reason a card was tall. They are all repeated in the
     full-screen preview, so on a 170px-wide card they are cost without benefit. */
  .lib-lines, .lib-badges { display: none; }
  .lib-foot { padding: 8px 9px; }
  .lib-st { font-size: .7rem; gap: 4px; }
  .lib-st-ico { width: 12px; height: 12px; }
  .lib-ws { padding: 2px 7px; font-size: .58rem; }
  .lib-overlay { top: 6px; left: 6px; gap: 4px; max-width: calc(100% - 12px); }
  /* Hover does not exist here, so the actions open from a ⋯ on the card rather than sitting on
     every thumbnail (the bin was one slip away from a tap meant for the preview). */
  .lib-more { display: flex; }
  .lib-card .lib-actions { opacity: 0; pointer-events: none; }
  .lib-card.acts-open .lib-actions { opacity: 1; pointer-events: auto; }
  .lib-act { width: 26px; height: 26px; border-radius: 7px; }
  .lib-act svg { width: 14px; height: 14px; }

  /* ---- Clip preview: the whole screen, not a panel beside the page ---- */
  /* A 440px drawer sliding in from the right is a desktop shape — on a phone it covers
     everything anyway, so the border, the shadow and the sliver of page behind it are all
     pretending there is something to see underneath. */
  .clip-drawer {
    width: 100%; border-left: 0; box-shadow: none; background: var(--bg);
    padding-bottom: env(safe-area-inset-bottom); }
  .clip-drawer-head { padding: 12px 14px; padding-top: max(12px, env(safe-area-inset-top)); }
  .clip-drawer-head h2 { font-size: .95rem; }

  /* Text a narrow screen drops. One class, because it is one idea — four tabs on one line,
     "Copy prompt" as "Copy", "Manage users" as "Users" — and it had grown a name per site. */
  .narrow-x { display: none; }
  .lib-tabs { flex-wrap: nowrap; gap: 2px; padding: 3px; }
  /* Equal shares of the row rather than shrink-to-label, so the group fills the box it sits in
     — the leftover strip on the right otherwise reads as a fifth tab that failed to render. */
  .lib-tab { flex: 1 1 0; min-width: 0; justify-content: center;
    gap: 4px; padding: 6px 3px; font-size: .74rem; }
  .lib-tab-dot { width: 6px; height: 6px; }
  .lib-tab-n { font-size: .66rem; }

  /* The bar was a wrapping flex row with space-between, which on a phone left the two pickers
     pinned to opposite edges with a hole between them. As a two-column grid the full-width
     controls span both tracks and the pickers take one each — no hole, and no guessing. */
  .lib-bar { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px; }
  .lib-tabs, .lib-search-wrap { grid-column: 1 / -1; }
  .lib-search-wrap { flex: none; min-width: 0; }
  .lib-pick { width: 100%; min-width: 0; }

  /* ---- References on a phone ---- */
  /* The view is a fixed-height column on desktop by design — the three panes fill the screen
     and the page itself never scrolls. On a phone that same rule has to fit a header, a clip
     list, a video and the reference grid into one viewport, so the list collapsed to half a
     row with its pager sitting on top of it. Here it is an ordinary scrolling page. */
  .view-references.active { display: block; height: auto; }
  .app:has(.view-references.active) .main { overflow: visible; padding-bottom: 28px; }
  .ref-split { min-height: 0; margin-top: 14px; gap: 14px; }
  .ref-list-col, .ref-refs, .ref-detail { height: auto; max-height: none; overflow: visible; }

  /* `flex: 1 1 auto` sized this against a column that no longer has a definite height, so the
     video resolved to nothing and rendered as a bare controls bar with a sliver of frame. */
  .ref-preview { flex: none; width: 100%; max-width: 100%; }
  .ref-preview video { max-height: 52vh; margin: 0 auto; }
  .ref-detail { gap: 12px; }

  /* The action row is gone: placeRefActions() moves the group down onto the clip's own header,
     beside the model chip, where there was already an empty half-line. In production
     .ref-head-right holds nothing but the DEV_MODE mask toggle, so it collapses to nothing. */
  .ref-head { gap: 8px; flex-wrap: wrap; }
  .ref-head-right { margin-left: auto; width: auto; }

  /* The select's face already reads "toys-clone · Yesterday, 6:38 PM"; the clip header repeated
     both, one line apart. What is left is the model chip — and now the two actions. */
  .ref-clip-title, .ref-clip-when { display: none; }
  .ref-clip-head { align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
  .ref-clip-head .ref-actions { margin-left: auto; }
  .ref-act { height: 32px; padding: 0 12px; font-size: .78rem; }
  .ref-grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 10px; }

  /* The picker is a select. Shut, it is one line naming the clip you are on; open, the list
     floats OVER what follows. Expanding in place would push the video — the thing you are here
     to look at — off the screen every time you went looking for another clip. */
  .ref-list-col { position: relative; overflow: visible; border-radius: var(--r-md); }
  .ref-list-head { cursor: pointer; border-bottom: 0; }
  .ref-head-all { display: none; }
  .ref-head-sel { display: block; flex: 1 1 auto; min-width: 0; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
  .ref-list-caret { display: block; width: 16px; height: 16px; flex: none;
    color: var(--muted); transition: transform .18s ease; }
  .ref-list-col.open .ref-list-caret { transform: rotate(180deg); }

  .ref-drop {
    display: block; position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 30;
    max-height: 62vh; overflow-y: auto; padding: 8px;
    background: var(--surface); border: 1px solid var(--border-hi); border-radius: 12px;
    box-shadow: 0 18px 44px rgba(0,0,0,.6); }
  .ref-list-col:not(.open) .ref-drop { display: none; }
  .ref-drop .pager { border-top: 1px solid var(--border); margin: 6px 0 0; padding: 8px 0 0;
    background: none; }

  /* The whole page, scrolling inside the dropdown — .ref-drop caps it at 62vh. */
  .ref-list-col .ref-list { max-height: none; overflow: visible; padding: 0; }

  /* ---- Accounts on a phone ---- */
  .view-accounts .ap-head { gap: 10px; margin-bottom: 16px; }
  /* Add account leads, Sync is the smaller sibling — stacked full width they read as a pair of
     equals, and Sync is something you press roughly never. */
  .view-accounts .ap-head .row-wrap:last-child { display: flex; gap: 8px; }
  #acctAdd { flex: 1 1 auto; justify-content: center; }
  #guideToggle { flex: 0 0 auto; }
  .acct-group { margin-bottom: 18px; }
  .acct-group-head h3 { font-size: .95rem; }

  /* Name, state and menu all competed for one line, so a handle of any length pushed
     "Connected" into the kebab. Two rows: identity on top, state under it, menu spanning both. */
  .acct-row {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center; gap: 2px 10px; padding: 12px; }
  .acct-av { grid-row: 1 / span 2; width: 34px; height: 34px; }
  .acct-row-main { grid-column: 2; grid-row: 1; }
  .acct-kebab { grid-column: 3; grid-row: 1 / span 2; }
  .acct-state { grid-column: 2; grid-row: 2; justify-self: start; font-size: .76rem; }
  .acct-row-sub { font-size: .76rem; }
  .acct-add { padding: 11px; font-size: .84rem; }

  /* The status bar said the same thing twice — the headline and the line under it are one
     sentence split in half — and the button sat off to the side of both. */
  .acct-status { flex-wrap: wrap; gap: 10px; padding: 14px; }
  .acct-status .acct-row-sub { display: none; }
  .acct-status .btn-ghost { width: 100%; justify-content: center; }

  /* ---- Presets index on a phone ---- */
  /* Same shape as the workspace list it already shares a grid class with: two lines of text on
     the left, one status on the right, rows divided by a hairline. As a card it was a 132px box
     holding two short lines — three presets to a screen. */
  .preset-card {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    align-items: center; gap: 3px 10px; min-height: 0; padding: 13px 4px; }
  .preset-card-name { grid-column: 1; grid-row: 1; font-size: 1rem; }
  .preset-card-gist { grid-column: 1; grid-row: 2; flex: none; font-size: .8rem;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .preset-card-foot { grid-column: 2; grid-row: 1 / span 2; justify-content: flex-end; }

  /* ---- Preset editor on a phone ---- */
  /* Four actions on one short line meant "Copy prompt" alone was wider than the icon-only
     Rename, so the group squeezed and shoved itself past the screen edge. Full width, four
     equal cells, icon over label — and Rename gets its name back, since the tooltip that
     explains it on a desktop needs a hover a phone does not have. */
  #presetEditor .ref-head-right { width: 100%; margin-left: 0; }
  #presetEditor .ref-actions { display: flex; width: 100%; border-radius: 12px; }
  #presetEditor .ref-act { flex: 1 1 0; min-width: 0; flex-direction: column; gap: 4px;
    height: auto; padding: 9px 2px; font-size: .68rem; letter-spacing: .01em; }
  #presetEditor .ref-act svg { width: 17px; height: 17px; }
  #presetEditor .ref-act-ico { width: auto; border-right: 0; }
  #presetEditor .ref-act + .ref-act { border-left: 1px solid var(--border-hi); }
  #presetEditor .pe-act-lbl { display: block; }

  /* The one thing you came to press, at the width of every other control on the page. It was a
     shrink-to-label pill in the corner of a sticky bar that is otherwise empty. */
  .pe-foot { padding: 12px 0 calc(12px + env(safe-area-inset-bottom)); margin-top: 16px; }
  .pe-foot-actions { width: 100%; gap: 8px; }
  #brainSaveBtn { flex: 1 1 auto; justify-content: center; padding: 12px 18px; }
  #brainRevertBtn { flex: 0 0 auto; }
  #brainMsg { flex: 1 0 100%; }

  /* ---- Admin tabs on a phone ---- */
  /* "Manage users / Manage models / Manage pricing / Logs" wraps every tab onto two lines to
     repeat a word that is on three of the four. Dropping it leaves the noun, which is the part
     that actually distinguishes them — and `capitalize` only here, so the desktop label stays
     "Manage users" rather than "Manage Users". */
  .atab-n { text-transform: capitalize; }
  .admin-tabs { gap: 2px; }
  .admin-tab { flex: 1 1 0; min-width: 0; padding: 9px 4px; font-size: .82rem;
    text-align: center; white-space: nowrap; }

  /* ---- Admin pane headers on a phone ---- */
  /* A 30px square icon button next to a neon pill reads as two unrelated controls that happen to
     be adjacent — different heights, different corners, different weight. They are one pair:
     refresh this list, add to this list. Matching their height and radius is what says so. */
  /* The generic phone rule stacks .ap-head into a column (title, then actions). That is right
     for a heading with a long action row; here the title is one word and the pair beside it is
     ~130px, so a whole line was being spent to separate "Users" from the two buttons that act
     on users. `flex-direction` is the property doing the stacking — overriding flex-wrap alone
     left it a column. */
  .admin-pane .ap-head { flex-direction: row; align-items: center; flex-wrap: nowrap;
    gap: 10px; margin-bottom: 4px; }
  .admin-pane .ap-head h2 { flex: 0 1 auto; min-width: 0; font-size: 1.1rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .admin-pane .ap-head .row-wrap { flex: none; margin-left: auto; display: flex; gap: 8px;
    flex-wrap: nowrap; align-items: stretch; }
  .admin-pane .ap-head .icon-btn {
    width: 38px; height: 38px; border-radius: var(--r-pill); background: var(--surface-2); }
  .admin-pane .ap-head .btn-neon {
    height: 38px; padding: 0 16px; border-radius: var(--r-pill); font-size: .85rem;
    display: inline-flex; align-items: center; white-space: nowrap; }
  /* Pricing has a refresh and nothing else, so it has no .row-wrap to be pushed by. */
  #adminPricingPane .ap-head > .icon-btn { margin-left: auto; }
  .admin-pane > p.muted.small { margin: 6px 0 14px; }
  /* Neither Users nor Models has an explanatory line under its header any more, so the header
     owns that gap instead of borrowing it from a paragraph. */
  #adminUsers, #adminModels, #adminPricing { margin-top: 14px; }

  /* Logs: the email and its button are one action, and on a phone that action is the width of
     the screen — the input was capped at 320px and the button sat in the leftover strip. */
  #adminLogsPane .row-wrap { flex-wrap: wrap; }
  #adminLogEmail { max-width: none !important; flex: 1 1 100%; }
  #adminLogLoad { flex: 1 1 100%; justify-content: center; }

  /* ---- Admin: the global image-model card ---- */
  /* Four controls of four different fixed widths wrapped into a grid of leftovers — a select on
     one line, then "or custom model id…" beside a square box showing a bare 0, then Save alone.
     One control per line, each the width of the card, in the order they are used. */
  .imgm-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .imgm-model, .imgm-custom, .imgm-field { max-width: none; }
  #imgModelSave { width: 100%; justify-content: center; }

  /* ---- the tab bar ---- */
  /* Nearly opaque, and that is deliberate. Glass works when what is behind it is IMAGERY; behind
     a tab bar is a scrolling list of text, and at any transparency low enough to still read as
     glass, workspace names bled through and collided with the labels — two sets of words in the
     same place, neither readable. The blur keeps a hint of the page moving underneath, which is
     all that was ever needed to say "this floats over the content". */
  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
    display: grid; grid-template-columns: repeat(5, 1fr); align-items: end;
    padding: 8px 4px calc(6px + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--bg) 94%, transparent);
    border-top: 1px solid rgba(255,255,255,.08);
    box-shadow: 0 -8px 24px rgba(0,0,0,.45);
    -webkit-backdrop-filter: blur(24px) saturate(160%);
    backdrop-filter: blur(24px) saturate(160%);
  }
  .tab-item {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 4px 2px; border: 0; background: none; cursor: pointer;
    color: var(--text-faint); font: inherit; font-size: .62rem; font-weight: 600;
    -webkit-tap-highlight-color: transparent;
    transition: color .18s ease;
  }
  .tab-ico { display: flex; }
  .tab-ico svg { width: 22px; height: 22px; }
  .tab-item.active { color: var(--text); }
  .tab-item:active { color: var(--text); }

  /* The one act that MAKES something, lifted out of the row. It is not a destination, so it
     never takes the active state — nothing it opens is a page you can be "on". */
  .tab-create { position: relative; }
  .tab-fab {
    display: flex; align-items: center; justify-content: center;
    width: 46px; height: 46px; margin-top: -14px; border-radius: 50%;
    background: linear-gradient(145deg, hsl(258 90% 66%), hsl(210 92% 58%));
    border: 1px solid rgba(255,255,255,.28); color: #fff;
    /* The last ring is the bar's own colour: the circle pokes ABOVE the bar, so the bar cannot
       cover what is behind it, and the page showed through the gap either side of it. */
    box-shadow: 0 6px 20px hsl(258 90% 50% / .45),
                inset 0 1px 0 rgba(255,255,255,.45),
                0 0 0 5px color-mix(in srgb, var(--bg) 94%, transparent);
    transition: transform .14s ease;
  }
  .tab-fab svg { width: 22px; height: 22px; }
  .tab-create:active .tab-fab { transform: scale(.94); }

  /* The drawer IS navigation, and a full-page one: Home, Library, References and Accounts are
     all in it. Leaving the tab bar on top of it puts the same four destinations on screen twice
     and buries the drawer's own footer (Credits) under a bar that duplicates it. The ✕ is the
     way out, which is where the eye already is. */
  .app.nav-open .tabbar { display: none; }
  /* INSIDE THE CREATE / EDIT FLOW the step bar IS the navigation (Next, Back, the ✕). The tab
     bar sat on top of it — z-index 90 over 40 — and on a phone the Brief's Next could not be
     pressed at all: a new workspace could not get past its first step (launch audit,
     2026-10-12). The flow has its own way out, so the tab bar steps aside while it is open. */
  /* `.picking` is Home's workspace list (home.js); without it the same view is the Brief step. */
  .app:has(.view-ask.active:not(.picking)) .tabbar,
  .app:has(.view-setup.active) .tabbar { display: none; }

  /* Things that dock to the bottom have to clear the bar, not sit under it. */
  .pe-foot { bottom: calc(70px + env(safe-area-inset-bottom)); }
  .toast { bottom: calc(78px + env(safe-area-inset-bottom)); }
}

/* ==========================================================================================
   STYLES — the gallery page.

   A wall of moving product film, laid out to be READ across rather than scrolled through: the
   cards are portrait because the footage is, they are wide enough that the product in the poster
   is recognisable at a glance, and everything below the picture is set at one rhythm so five
   cards scan as one object instead of five. The only colour on the page is what is inside the
   films — the chrome stays on the app's neutrals so nothing competes with the footage.
   ========================================================================================== */
.sty-head { padding: 2px 0 14px; }
.sty-title { margin: 0; font-family: var(--font-display); font-size: 30px; font-weight: 800; letter-spacing: -.025em; }

/* THE SHELF BAR (redesign 2026-10-10): one segmented track with a sliding marker, an icon and a
   count per shelf; search and the admin's Arrange on the right. Sticky, so the shelves stay in
   reach while the wall scrolls under them. */
.sty-bar { position: sticky; top: 52px; z-index: 20; display: flex; align-items: center; gap: 12px;
  margin: 0 -4px 22px; padding: 10px 4px;
  background: var(--bg); }
.sty-seg { position: relative; display: inline-flex; gap: 2px; padding: 4px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--border); min-width: 0;
  overflow-x: auto; scrollbar-width: none; }
.sty-seg::-webkit-scrollbar { display: none; }
.sty-seg-ind { position: absolute; top: 4px; bottom: 4px; left: 0; width: 0; border-radius: 10px;
  background: var(--sidebar-raised); border: 1px solid var(--border-strong);
  box-shadow: 0 1px 0 rgba(255,255,255,.05) inset, 0 6px 16px -6px rgba(0,0,0,.6);
  transition: transform .28s cubic-bezier(.3,.8,.3,1), width .28s cubic-bezier(.3,.8,.3,1); }
.sty-tab { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; border: 0; border-radius: 10px; background: none; cursor: pointer;
  color: var(--text-muted); font: 600 13.5px var(--font-sans); white-space: nowrap;
  transition: color .15s; }
.sty-tab svg { width: 16px; height: 16px; flex: none; opacity: .8; }
.sty-tab em { font-style: normal; font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums;
  min-width: 20px; padding: 1px 6px; border-radius: 999px; text-align: center;
  color: var(--text-faint); background: rgba(255,255,255,.05); transition: color .15s, background .15s; }
.sty-tab:hover { color: var(--text); }
.sty-tab.on { color: var(--text); }
.sty-tab.on svg { opacity: 1; color: var(--accent); }
.sty-tab.on em { color: var(--on-accent); background: var(--accent); }
.sty-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.sty-tools { margin-left: auto; display: flex; align-items: center; gap: 8px; flex: none; }
.sty-search { box-sizing: border-box; margin: 0; display: flex; align-items: center; gap: 8px; height: 42px; padding: 0 12px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--surface);
  color: var(--text-faint); transition: border-color .15s, width .2s; width: 220px; }
.sty-search:focus-within { border-color: var(--accent); color: var(--text-muted); }
.sty-search svg { width: 16px; height: 16px; flex: none; }
.sty-search input, .sty-search input:focus { flex: 1; min-width: 0; height: auto; padding: 0; margin: 0;
  border: 0 !important; outline: 0 !important; box-shadow: none !important; background: none !important;
  color: var(--text); font: 500 13.5px var(--font-sans); }
.sty-search input::-webkit-search-cancel-button { filter: invert(.7); cursor: pointer; }
.sty-search input::placeholder { color: var(--text-faint); }
.sty-arrange { display: inline-flex; align-items: center; gap: 7px; height: 42px; padding: 0 14px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted);
  font: 600 13.5px var(--font-sans); cursor: pointer; transition: color .15s, border-color .15s, background .15s; }
.sty-arrange svg { width: 16px; height: 16px; }
.sty-arrange:hover { color: var(--text); border-color: var(--border-strong); }
.sty-arrange:active { transform: scale(.98); }
#styArrange.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

/* Which shelf a card is from, on the All tab only — a glass label over the film. */
.sty-tag { position: absolute; top: 10px; left: 10px; z-index: 3; padding: 3px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 600; color: rgba(255,255,255,.92); background: rgba(12,11,16,.5);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); border: 1px solid rgba(255,255,255,.08); }
.sty-tag:empty { display: none; }
.sty-none { padding: 48px 0; text-align: center; color: var(--text-faint); font-size: 14px; }

@media (max-width: 720px) {
  .sty-bar { flex-wrap: wrap; gap: 8px; }
  .sty-seg { order: 2; width: 100%; }
  .sty-tools { order: 1; width: 100%; }
  .sty-search { flex: 1; width: auto; }
  .sty-tab { padding: 8px 11px; }
}
@media (prefers-reduced-motion: reduce) { .sty-seg-ind { transition: none; } }

.sty-grid { display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); align-items: start; }

/* THE CARD IS THE FILM. Everything sits inside the frame — a title block under the picture is a
   second thing competing with it for the same glance, and the picture wins that argument every
   time. 4:3 because a landscape frame reads as a piece of film at thumbnail size, where a tall
   one reads as a phone screenshot. */
.sty-card { position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 3; border-radius: 14px; background: var(--surface-2);
  border: 1px solid var(--border); cursor: pointer;
  transition: transform .16s cubic-bezier(.2,.7,.3,1), border-color .16s, box-shadow .16s; }
.sty-card:hover { transform: translateY(-3px); border-color: var(--border-strong);
  box-shadow: 0 14px 34px rgba(0,0,0,.45); }
.sty-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.sty-shot { position: absolute; inset: 0; overflow: hidden; }
.sty-shot img, .sty-shot video { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block; }
.sty-shot img { transition: transform .5s cubic-bezier(.2,.7,.3,1); }
.sty-card:hover .sty-shot img { transform: scale(1.04); }
.sty-shot video { opacity: 0; transition: opacity .25s; }
.sty-card:hover .sty-shot video.ready { opacity: 1; }

.sty-empty-shot { position: absolute; inset: 0;
  background:
    repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 9px, transparent 9px 18px),
    var(--surface-2); }

/* The caption band. Blur AND a gradient, not either alone: blur keeps the footage readable as
   footage behind the words, and the gradient is what guarantees contrast when the frame under
   it happens to be pale — a scrim that depends on the picture being dark fails on the one card
   that is not. */
.sty-cap { position: absolute; inset: auto 0 0 0; z-index: 2;
  padding: 30px 14px 13px; display: grid; gap: 3px;
  background: linear-gradient(to top, rgba(8,7,11,.86) 12%, rgba(8,7,11,.55) 55%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  -webkit-mask-image: linear-gradient(to top, #000 62%, transparent);
  mask-image: linear-gradient(to top, #000 62%, transparent); }
.sty-name { margin: 0; font-size: 15px; font-weight: 640; letter-spacing: -.01em; color: #fff; }
.sty-blurb { margin: 0; font-size: 12px; line-height: 1.45; color: rgba(255,255,255,.72);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  /* THE NAME AT REST, THE SENTENCE ON HOVER (owner, 2026-10-09): a wall where every card also
     carries two lines of text is a wall of text over the films. A phone has no hover, so there
     the sentence lives in the style's sheet, one tap away. */
  max-height: 0; opacity: 0; transition: max-height .22s ease, opacity .18s ease; }
@media (hover: hover) {
  .sty-card:hover .sty-blurb, .sty-card:focus-visible .sty-blurb { max-height: 3em; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .sty-blurb { transition: none; } }

/* How many briefs run this style — a number, unlabelled. On a wall of pictures a badge earns
   its place only if it costs one glance, and "3 briefs" is a sentence. */
.sty-used { position: absolute; top: 10px; right: 10px; z-index: 3;
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px;
  display: grid; place-items: center; font-size: 10.5px; font-weight: 650;
  font-variant-numeric: tabular-nums; color: #fff; background: rgba(16,15,20,.6);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }

/* Loading. Same box as a real card so the grid does not reflow under a cursor already reaching
   for it — that is how a misclick happens. */
.sty-skel { pointer-events: none; animation: sty-pulse 1.5s ease-in-out infinite; }
@keyframes sty-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .55 } }
@media (prefers-reduced-motion: reduce) {
  .sty-card, .sty-shot img, .sty-skel { transition: none; animation: none; }
  .sty-card:hover, .sty-card:hover .sty-shot img { transform: none; }
}

@media (max-width: 720px) {
  .sty-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .sty-title { font-size: 21px; }
  .sty-grid { gap: 11px; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
  .sty-cap { padding: 26px 11px 11px; }
  .sty-name { font-size: 13.5px; }
  .sty-blurb { font-size: 11.5px; }
}

/* ---- the wizard's one-line echo of the choice ---------------------------------------------
   The gallery is the place a style is CHOSEN; the brief only has to say which one is in force,
   or the same decision has two homes and they drift apart. */
.sty-pick { display: flex; align-items: center; gap: 10px; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2); }
.sty-pick-thumb { flex: none; width: 52px; aspect-ratio: 4 / 3; border-radius: 6px;
  overflow: hidden; background: var(--surface); }
.sty-pick-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sty-pick-txt { flex: 1; min-width: 0; display: grid; gap: 2px; }
.sty-pick-name { font-size: 13px; font-weight: 620; }
.sty-pick-blurb { font-size: 11.5px; color: var(--text-muted); line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sty-pick-none { font-size: 12.5px; color: var(--text-muted); }

/* ---- admin: curating the style demo films -------------------------------------------------- */
.style-demo-admin { display: grid; }
/* align-items: start, not center. Centred, the three buttons floated in the middle of a 131px
   row with nothing beside them — level with no line of text, so they read as a second, detached
   thing. Pinned to the top they land on the title's line: "Hot and pouring ........ ▶ ⟳ 🗑". */
.sd-row { display: grid; grid-template-columns: 84px 1fr auto; gap: 14px; align-items: start;
  padding: 12px 18px; border-bottom: 1px solid var(--border); }
.sd-row:last-child { border-bottom: 0; }
.sd-row:hover { background: var(--surface-2); }
.sd-row > div:nth-child(2) { min-width: 0; }
.sd-thumb { width: 84px; aspect-ratio: 9 / 14; border-radius: 7px; overflow: hidden;
  background: var(--card); display: grid; place-items: center; }
.sd-thumb img, .sd-thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
.sd-thumb .muted { font-size: 10px; text-align: center; padding: 4px; }
.sd-name { font-weight: 650; font-size: .95rem; color: var(--text); }
.sd-blurb { font-size: .8rem; color: var(--text-muted); line-height: 1.5; margin-top: 2px; }
.sd-acts { display: grid; gap: 6px; justify-items: stretch; }


/* ==========================================================================================
   STYLE DETAIL SHEET — what the card cannot say.

   The card sells the look; this answers "what is it, who is in it, and is it current", which is
   what decides whether to spend an afternoon on it. The film plays at the top at the shape it
   was shot in, and everything under it is a short spec list rather than prose, because that is
   how a spec is read.
   ========================================================================================== */
.sty-sheet { position: relative; width: min(520px, 100%); max-height: 90vh; overflow: auto;
  border: 1px solid var(--border-strong); border-radius: 16px; background: var(--surface);
  box-shadow: 0 30px 80px rgba(0,0,0,.6); }
/* THE FILM WHOLE, SIDE BY SIDE. The demos are mostly 9:16, and a 4:3 box over the sheet cropped
   them to a strip across the middle. Wide screens put the film on the left at its own shape
   (--ar, read from the video) and as tall as the window allows, the facts on the right. */
@media (min-width: 721px) {
  .sty-sheet { display: flex; width: auto; max-width: min(1080px, 100%); overflow: hidden; }
  /* Height is also capped by the width left over after the 340px spec column, or a landscape film
     overflows the sheet and the facts get cut off by the overflow:hidden above. Portrait meets
     this cap only below 829px — where the old fixed 780px was already overflowing anyway, so it
     never shrinks a film that used to fit. The max-width is the belt to that pair of braces:
     100vw counts a classic scrollbar and the fixed overlay's 100% does not, which is 15px of
     overflow on Windows otherwise. */
  .sty-sheet .sty-sheet-shot { flex: none; aspect-ratio: var(--ar, 9 / 16);
    height: min(80vh, 780px, calc((min(1080px, 100vw - 48px) - 340px - 2px) * var(--arh, 16) / var(--arw, 9)));
    max-width: min(60vw, calc(100% - 340px)); background: #000; }
  .sty-sheet .sty-sheet-body { flex: none; width: 340px; max-height: min(80vh, 780px); overflow: auto;
    display: flex; flex-direction: column; gap: 10px; padding-top: 52px; }
  /* The button lives in the bottom-right corner whatever the film's shape or the text's length. */
  .sty-sheet .sty-sheet-foot { margin-top: auto; }
}
.sty-sheet .modal-close { position: absolute; top: 12px; right: 12px; z-index: 3;
  background: rgba(16,15,20,.62); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border-color: transparent; color: #fff; }
.sty-sheet-shot { position: relative; aspect-ratio: 4 / 3; background: var(--surface-2);
  overflow: hidden; }
.sty-sheet-shot img, .sty-sheet-shot video { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: contain; display: block; background: #000; }
.sty-sheet-shot video { cursor: pointer; }
.sty-sheet-sound { position: absolute; left: 12px; bottom: 12px; z-index: 2; width: 36px; height: 36px;
  display: grid; place-items: center; border: 0; border-radius: 999px; padding: 0; cursor: pointer;
  color: #fff; background: rgba(16,15,20,.62);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.sty-sheet-sound svg { width: 18px; height: 18px; }
.sty-sheet-sound:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sty-sheet-shot .sty-empty-shot { border-radius: 0; }
.sty-sheet-body { padding: 18px 20px 20px; display: grid; gap: 10px; }
.sty-sheet-name { margin: 0; font-size: 20px; font-weight: 660; letter-spacing: -.02em; }
.sty-sheet-blurb { margin: 0; font-size: 13px; line-height: 1.6; color: var(--text-muted); }

/* A definition list, not sentences: these are four facts of the same kind, and a reader
   comparing two styles is scanning down the values, never reading across. */
.sty-sheet-specs { margin: 6px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 7px 16px;
  font-size: 12.5px; }
.sty-sheet-specs dt { color: var(--text-faint); }
.sty-sheet-specs dd { margin: 0; color: var(--text); }
/* Two rows: when it was last updated, then the actions — the primary one takes the width, so
   "Use this style" never wraps onto two lines beside the date (owner, 2026-10-10). */
.sty-sheet-foot { display: grid; gap: 12px;
  margin-top: 8px; padding-top: 14px; border-top: 1px solid var(--border); }
.sty-sheet-acts { display: flex; gap: 8px; }
.sty-use-btn, .sty-edit-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 46px; border-radius: 12px; font: 650 14.5px var(--font-sans); white-space: nowrap; cursor: pointer;
  transition: transform .15s, background .15s, box-shadow .15s, border-color .15s, color .15s; }
.sty-use-btn { flex: 1; padding: 0 18px; border: 0; color: var(--on-accent); background: var(--accent);
  box-shadow: 0 8px 22px -8px color-mix(in srgb, var(--accent) 70%, transparent), inset 0 1px 0 rgba(255,255,255,.18); }
.sty-use-btn svg { width: 17px; height: 17px; transition: transform .18s; }
.sty-use-btn:hover { background: color-mix(in srgb, var(--accent) 88%, #fff); box-shadow: 0 10px 26px -8px color-mix(in srgb, var(--accent) 85%, transparent), inset 0 1px 0 rgba(255,255,255,.2); }
.sty-use-btn:hover svg { transform: translateX(3px); }
.sty-use-btn:active, .sty-edit-btn:active { transform: scale(.98); }
.sty-use-btn:focus-visible, .sty-edit-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sty-edit-btn { flex: none; padding: 0 16px; border: 1px solid var(--border-strong); background: var(--surface-2);
  color: var(--text-muted); }
.sty-edit-btn svg { width: 15px; height: 15px; }
.sty-edit-btn:hover { color: var(--text); border-color: var(--text-faint); }
.sty-edit-btn.hidden { display: none; }
.sty-sheet-stamp { font-size: 11px; line-height: 1.5; color: var(--text-faint);
  font-variant-numeric: tabular-nums; }
.sty-ver { display: inline-block; margin-left: 7px; padding: 1px 6px; border-radius: 5px;
  font-size: 10.5px; font-weight: 650; letter-spacing: .02em;
  background: var(--sidebar-raised); color: var(--text-muted); }

/* ---- NEW WORKSPACE ------------------------------------------------------------------------
   It used to be a heading, a hint and a bare input — a form, in a product whose whole subject is
   pictures. It is still one field, because one field is all it needs; what changed is that it
   carries the decision the creator just made into the moment they name the thing. */
.ws-sheet { position: relative; width: min(440px, 100%);
  border: 1px solid var(--border-strong); border-radius: 16px; background: var(--surface);
  box-shadow: 0 30px 80px rgba(0,0,0,.6); padding: 26px 24px 22px; }
.ws-sheet .modal-close { position: absolute; top: 14px; right: 14px; }
.ws-sheet-style { display: flex; align-items: center; gap: 11px; margin-bottom: 18px;
  padding: 8px; border: 1px solid var(--border); border-radius: 11px; background: var(--surface-2); }
.ws-sheet-thumb { flex: none; width: 62px; aspect-ratio: 4 / 3; border-radius: 7px;
  overflow: hidden; background: var(--surface); }
.ws-sheet-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ws-sheet-styletxt { display: grid; gap: 1px; min-width: 0; }
.ws-sheet-eyebrow { font-size: 10px; font-weight: 650; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-faint); }
.ws-sheet-styletxt b { font-size: 14px; font-weight: 640; }
.ws-sheet-title { margin: 0 0 5px; font-size: 19px; font-weight: 650; letter-spacing: -.015em; }
.ws-sheet-sub { margin: 0 0 18px; font-size: 12.5px; line-height: 1.55; color: var(--text-muted); }
.ws-sheet-field { display: grid; gap: 6px; }
.ws-sheet-field span { font-size: 11.5px; font-weight: 600; color: var(--text-muted); }
.ws-sheet-field input { width: 100%; padding: 11px 12px; font-size: 14px;
  border: 1px solid var(--border-strong); border-radius: 9px;
  background: var(--surface-2); color: var(--text); }
.ws-sheet-field input:focus { outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-weak); }
.ws-sheet-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 20px; }
.ws-sheet-msg { margin: 0; flex: 1; min-width: 0; font-size: 12px; color: var(--err); }
.ws-sheet-foot .btn-neon { flex: none; }

/* Phone: stacked, the film first and whole, capped so the button is a short scroll away. */
@media (max-width: 720px) {
  .sty-sheet .sty-sheet-shot { aspect-ratio: auto; height: min(60vh, 640px); background: #000; }
  /* Pinned to the sheet's bottom edge while the facts scroll under it. */
  .sty-sheet .sty-sheet-foot { position: sticky; bottom: -20px; margin-bottom: -20px;
    padding-bottom: 20px; background: var(--surface); }
}
@media (max-width: 560px) {
  .sty-sheet, .ws-sheet { width: 100%; }
  .ws-sheet { padding: 22px 18px 18px; }
}

/* ==========================================================================================
   HOME — the look comes first.

   The page used to open on a greeting and a grid of workspaces, which asks the creator to
   answer "which channel" before "what kind of film". This opens on the films themselves: a
   carousel of styles playing their own demos, with the workspace grid below it where the
   bookkeeping belongs.
   ========================================================================================== */
.home-hero { display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; flex-wrap: wrap; margin-bottom: 18px; }
.home-hello { margin: 0 0 6px; font-family: "Space Mono", ui-monospace, monospace;
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-faint); }
.home-title { margin: 0; font-family: "Bricolage Grotesque", -apple-system, sans-serif;
  font-size: 38px; line-height: 1.1; font-weight: 800; letter-spacing: -.02em;
  color: var(--text); text-wrap: pretty; }
/* A link, not a button: it leaves the page rather than doing something on it, and the underline
   is what says so on a page whose every other affordance is a filled pill. */
.home-browse { display: inline-flex; align-items: center; gap: 7px; flex: 0 0 auto;
  padding: 4px 2px 5px; border: 0; border-bottom: 1px solid #2B2933; background: none;
  color: var(--text-muted); font: inherit; font-size: 13px; font-weight: 600;
  letter-spacing: .01em; cursor: pointer; transition: color .15s, border-color .15s; }
.home-browse:hover { color: var(--text); border-color: var(--accent); }

.home-reel { position: relative; height: 396px; overflow: hidden; border-radius: 18px;
  background: radial-gradient(120% 100% at 50% 0%, #15141C 0%, #0D0C11 72%);
  border: 1px solid var(--surface-2); margin-bottom: 8px; }
.reel-stage { position: absolute; inset: 0; }
/* Every card sits in the same place and is moved by transform alone — no layout runs while the
   carousel turns, so the motion cannot stutter against a reflow. */
/* ONLY transform AND opacity ARE ANIMATED. Both are composited, so the browser moves the card
   without re-running layout or paint. What was animated before and should not have been:
     filter: blur(2px)  — re-rendered every frame across the whole card, the single worst offender
     box-shadow         — a 70px shadow repainting behind a moving element
   The receded look is a static overlay now (see .reel-card::after) and the shadow is fixed. */
.reel-card { position: absolute; top: 50%; left: 50%; width: min(470px, 58%);
  aspect-ratio: 4 / 3; border-radius: 16px; overflow: hidden; border: 1px solid #2B2933;
  box-shadow: 0 20px 44px rgba(0,0,0,.55); cursor: pointer;
  /* Back-loaded: the card leaves quickly and settles slowly, which reads as weight where a
     symmetrical ease over the same duration reads as a slideshow. */
  transition: transform .8s cubic-bezier(.16,.84,.3,1), opacity .5s ease;
  will-change: transform, opacity;
  -webkit-backface-visibility: hidden; backface-visibility: hidden; }
/* The dim that used to be a blur. One painted layer that never changes, so moving it is free. */
.reel-card::after { content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: rgba(9,8,12,.5); opacity: 1; transition: opacity .5s ease; }
.reel-card.front::after { opacity: 0; }
/* The caption trails the movement rather than riding it: at rest it is readable, and during the
   turn it is out of the way of the card that is arriving. */
.reel-cap { z-index: 4; transition: opacity .35s ease .18s; }
.reel-card video, .reel-card img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; }
.reel-card video { opacity: 0; transition: opacity .5s ease; }
.reel-card video.on { opacity: 1; }
.reel-scrim { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(9,8,12,0) 42%, rgba(9,8,12,.55) 68%, rgba(9,8,12,.94) 100%); }
.reel-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 16px 18px 15px;
  pointer-events: none; }
.reel-cap b { display: block; font-family: "Bricolage Grotesque", -apple-system, sans-serif;
  font-size: 19px; font-weight: 800; letter-spacing: -.015em; color: #fff; text-wrap: pretty; }
.reel-cap span { display: block; margin-top: 4px; font-size: 12.5px; line-height: 1.5;
  color: rgba(241,239,245,.76); text-wrap: pretty; }

.reel-nav, .reel-mute { position: absolute; z-index: 40; display: grid; place-items: center;
  border: 1px solid rgba(255,255,255,.16); background: rgba(9,8,12,.66);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); color: var(--text);
  cursor: pointer; transition: border-color .15s, background .15s; }
.reel-nav { top: 50%; width: 38px; height: 38px; border-radius: 50%; transform: translateY(-50%); }
.reel-prev { left: 14px; } .reel-next { right: 14px; }
.reel-nav:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 28%, transparent); }
.reel-mute { top: 14px; right: 18px; width: 34px; height: 34px; border-radius: 10px;
  background: rgba(9,8,12,.6); }
.reel-mute:hover { border-color: rgba(255,255,255,.42); }
.reel-nav:focus-visible, .reel-mute:focus-visible, .reel-card:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; }

/* Stat chips. The count is the content, so it gets the mono face and the full-strength colour
   while the label stays quiet — the row is read by scanning the numbers. */
.home-stats { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 20px 0 24px; border-bottom: 1px solid var(--surface-2); margin-bottom: 24px; }
.hstat { display: inline-flex; align-items: baseline; gap: 7px; padding: 6px 12px;
  border-radius: 999px; border: 1px solid var(--border); background: var(--surface);
  color: var(--text-muted); font: inherit; font-size: 12.5px; cursor: pointer;
  transition: border-color .12s, color .12s; }
.hstat:hover { border-color: var(--border-strong); color: var(--text); }
.hstat b { font-family: "Space Mono", ui-monospace, monospace; font-size: 13px;
  font-weight: 700; color: var(--text); }
.hstat.live { align-items: center; gap: 8px; border-color: var(--accent-border);
  background: var(--accent-weak); color: #C9D2FF; }
.hstat.live b { color: #fff; }
.hstat-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  animation: musePulse 1.4s ease-in-out infinite; }
@keyframes musePulse { 0%,100% { opacity: 1; transform: scale(1) } 50% { opacity: .35; transform: scale(.8) } }

@media (prefers-reduced-motion: reduce) {
  .reel-card, .reel-card video, .reel-cap { transition: none; }
  .reel-card { will-change: auto; }
  .hstat-dot { animation: none; }
}
@media (max-width: 760px) {
  .home-title { font-size: 27px; }
  .home-reel { height: 300px; }
  .reel-card { width: min(320px, 74%); }
  .reel-cap b { font-size: 16px; }
}
.sd-start { display: inline-flex; align-items: center; gap: 5px; justify-content: center;
  font-size: 11px; color: var(--text-faint); }
.sd-start input { width: 52px; padding: 4px 6px; text-align: right;
  font: inherit; font-size: 12px; font-variant-numeric: tabular-nums;
  border: 1px solid var(--border-strong); border-radius: 7px;
  background: var(--surface); color: var(--text); }
.sd-start input:focus { outline: none; border-color: var(--accent); }

/* ---- admin: the style demo row ------------------------------------------------------------- */
/* nowrap: the three never break to a second line, however narrow the pane gets — the title
   beside them is what gives, and it can. `margin-top` is optical, not structural: a 30px button
   next to a 13px title sits low unless it is lifted onto the cap height. */
.sd-acts { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap;
  justify-items: initial; margin-top: -3px; }
.sd-file { cursor: pointer; }
.btn-ghost.mini.danger:hover { border-color: var(--err); color: var(--err); }

/* ---- choosing the fifteen seconds -----------------------------------------------------------
   The film plays while the window is dragged, so the choice is made by watching rather than by
   typing a timestamp and reloading the page to find out what was at it. */
.trim-sheet { position: relative; width: min(560px, 100%); border-radius: 16px;
  border: 1px solid var(--border-strong); background: var(--surface);
  box-shadow: 0 30px 80px rgba(0,0,0,.6); overflow: hidden; }
.trim-head { display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 14px; border-bottom: 1px solid var(--border); }
.trim-titles { text-align: center; display: grid; gap: 1px; min-width: 0; }
.trim-titles b { font-size: 13.5px; font-weight: 640; }
.trim-x, .trim-done { border: 0; background: none; font: inherit; font-size: 13px;
  font-weight: 600; cursor: pointer; padding: 4px 2px; }
.trim-x { color: var(--text-muted); }
.trim-x:hover { color: var(--text); }
.trim-done { color: var(--accent); }
.trim-stage { position: relative; aspect-ratio: 4 / 3; background: #000; }
.trim-stage video { width: 100%; height: 100%; object-fit: contain; display: block; }
.trim-foot { padding: 14px 16px 16px; }

/* The track is the whole film; the window is what plays. Sized as a fraction of the duration, so
   a long film shows a narrow window and the proportion itself says how much is being taken. */
.trim-track { position: relative; height: 46px; border-radius: 9px; overflow: hidden;
  background: var(--surface-2); cursor: grab; touch-action: none; }
.trim-track:active { cursor: grabbing; }
.trim-strip { position: absolute; inset: 0; opacity: .5;
  background-size: auto 100%; background-repeat: repeat-x; }
.trim-window { position: absolute; top: 0; bottom: 0; left: 0; width: 25%;
  border: 2px solid #fff; border-radius: 9px; background: rgba(255,255,255,.1);
  box-shadow: 0 0 0 9999px rgba(9,8,12,.55); pointer-events: none;
  display: flex; align-items: center; justify-content: space-between; padding: 0 5px; }
.trim-grip { width: 3px; height: 18px; border-radius: 2px; background: rgba(255,255,255,.85); }
.trim-times { display: flex; justify-content: space-between; margin-top: 8px;
  font-family: "Space Mono", ui-monospace, monospace; font-size: 11.5px; color: var(--text-muted);
  font-variant-numeric: tabular-nums; }
.sd-meta { margin-top: 5px; font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px;
  color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* A <label> has to be told to look like the buttons beside it. */
.sd-file { cursor: pointer; }

/* ---- the brief, now a card in Setup ---------------------------------------------------------
   It was a page. The fields are unchanged; what is new is that they sit in the flow, so they
   need the grouping a page's own heading used to give them. */
.setup-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 4px; }
.setup-card-title { margin: 0; font-size: 14px; font-weight: 640; letter-spacing: -.01em; }
/* THE PADDING LIVES ON THE CARD HERE, and that is the exception worth stating: .setup-card
   deliberately carries none, because every other card in Setup is a stack of .setup-field rows
   that each bring their own 14/16 and a divider between them. This card is not that — it is one
   continuous form — so its children are .brain-field, which has no padding, and every heading,
   label and panel in it was sitting flush on the card's own border. Same 14/16 as a setup-field,
   so the two kinds of card line up where they sit side by side. */
#briefCard, #angleCard { display: grid; gap: 12px; padding: 14px 16px; }
#briefCard .brain-field { display: grid; gap: 6px; }
/* Sentence case, not uppercase tracking. The uppercase labels read as a form to be completed;
   these read as questions, which is what they are. */
#briefCard .brain-label, #angleCard .brain-label { font-size: 12.5px; font-weight: 640;
  letter-spacing: 0; text-transform: none; color: var(--text);
  display: flex; align-items: center; gap: 6px; }

/* FOLDED BY DEFAULT, AND THAT IS THE POINT. Ten of these eighteen fields have an answer a style
   already filled in; shown to someone making their first film they are ten questions they have
   no basis to answer, in front of the three only they can. */
.setup-more { border-top: 1px solid var(--border); padding-top: 10px; }
.setup-more > summary { cursor: pointer; list-style: none; display: flex; align-items: center;
  gap: 8px; font-size: 12.5px; font-weight: 620; color: var(--text-muted); padding: 4px 0; }
.setup-more > summary::-webkit-details-marker { display: none; }
.setup-more > summary::before { content: "▸"; color: var(--text-faint); font-size: 11px;
  transition: transform .15s; }
.setup-more[open] > summary::before { transform: rotate(90deg); }
.setup-more > summary:hover { color: var(--text); }
.setup-more-body { display: grid; gap: 12px; padding: 8px 0 4px; }

.brief-save { display: flex; align-items: center; gap: 10px; padding-top: 4px; }

/* The Brief row at the top of the card above still exists as a pointer — the card is below the
   fold on a laptop. A flash is how a jump says "this, the thing you just asked for". */
@keyframes briefFlash { from { box-shadow: 0 0 0 2px var(--accent); } to { box-shadow: 0 0 0 2px transparent; } }
#briefCard.flash { animation: briefFlash .9s ease-out; }
@media (prefers-reduced-motion: reduce) { #briefCard.flash { animation: none; } }

/* ---- Setup: one column ----------------------------------------------------------------------
   The two-column grid was right for four fields and a reference panel. With the brief folded in
   it holds twenty, and the second column made every one of them half-width — which is the wrong
   shape for the three that matter most, because "why it is worth buying" is a sentence.

   .step-grid (the later wizard cards) keeps its two columns: those cards are a short list of
   settings beside a live preview, which is what two columns are for. */
/* width + align-self, NOT `margin: 0 auto`. .ask-wrap is a column flex container, and an auto
   side margin on a flex item cancels the stretch it would otherwise get — the grid collapsed to
   58px, its own content width, with 636px of margin either side. Measured, not guessed. */
.view-ask { --rail: 780px; }          /* …and the action bar below it, see .bar-inner */
.view-ask .home-grid { grid-template-columns: minmax(0, 1fr); width: 100%; max-width: var(--rail);
  align-self: center; gap: 16px; }
.view-ask .ref-panel { max-width: none; }

/* The reference slots belong to the style above them, so they read as part of that decision
   rather than as a second panel with its own agenda. */
.view-ask .ref-panel { border-top: 0; }
.view-ask #briefCard { gap: 14px; }

/* Section headings inside the one column. Without them a single column of twenty fields is a
   form; with them it is three questions. */
.setup-sec { font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-faint); padding-top: 4px; }

/* ---- create-workspace: step 2, the style ----------------------------------------------------
   Cards, not a dropdown. A style is a LOOK, and the only honest way to offer a look is to show
   one — the poster is the same still the gallery uses, so the choice made here and the choice
   made there are visibly the same choice. */
.ws-style-grid { display: grid; grid-auto-rows: max-content; gap: 16px; max-height: 46vh; overflow-y: auto; padding: 2px; }
.ws-style-group { display: grid; gap: 8px; }
.ws-style-glabel { font-size: 10.5px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-faint); }
.ws-style-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(146px, 1fr));
  gap: 10px; }
.ws-style-card { display: grid; gap: 6px; padding: 8px; text-align: left; cursor: pointer;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface);
  color: var(--text); font: inherit; transition: border-color .14s, background .14s; }
.ws-style-card:hover { border-color: var(--accent-border); background: var(--surface-2); }
.ws-style-card.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.ws-style-shot { display: block; aspect-ratio: 4 / 3; border-radius: 8px; overflow: hidden;
  background: var(--surface-2); }
.ws-style-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ws-style-card b { font-size: 12.5px; font-weight: 640; }
.ws-style-blurb { font-size: 11px; color: var(--text-muted); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Named, at the bottom, in its own words. It is a real choice — and it must not be the one
   somebody lands on by not being asked. */
/* A card of its own, not an underlined link: read as a footnote, choosing it felt like having
   skipped something, and the brief afterwards looked broken to people who had chosen it. */
.ws-style-skip { margin-top: 12px; width: 100%; display: grid; gap: 2px; text-align: left;
  border: 1px dashed var(--border); border-radius: 10px; background: none; cursor: pointer;
  padding: 10px 12px; font: inherit; color: var(--text); }
.ws-style-skip b { font-size: 12.5px; font-weight: 640; }
.ws-style-skip span { font-size: 11px; color: var(--text-muted); }
.ws-style-skip:hover { border-color: var(--accent); }
.ws-sheet-foot { display: flex; align-items: center; gap: 10px; }
.ws-sheet-foot .btn-ghost { margin-left: auto; }

/* The sheet is a name box on step 1 and a wall of films on step 2. Widened only for the second,
   so choosing a style here is the same act as choosing one in the gallery — four across, not two
   in a scrolling slot. */
.ws-sheet:has(#wsStepStyle:not(.hidden)) { width: min(780px, 94vw); max-width: 780px; }
.ws-sheet:has(#wsStepStyle:not(.hidden)) .ws-style-grid { max-height: 52vh; }

/* The brief's fields were spaced for a page of four; at twenty the gaps read as gaps in the
   THINKING. Tighter, with the rule between groups doing the separating instead. */
#briefCard .brain-field { gap: 5px; }
#briefCard > .brain-field + .brain-field { border-top: 1px solid var(--border); padding-top: 12px; }

/* ---- the style's own questions ---------------------------------------------------------------
   Set apart from the generic brief fields, because they are a different kind of question: the
   ones above are true of any film, and these are true of THIS kind of product. A creator who has
   just chosen "Night and running" should see the car questions arrive as a consequence. */
/* The style's own questions are questions like any other — the tinted box around them made
   them look like a warning, and they are the most ordinary thing on the page. */
.pf-asks:not(:empty) { display: grid; }
.pf-asks-head { font-size: 12px; font-weight: 700; letter-spacing: 0; text-transform: none;
  color: var(--accent); }
.pf-asks .brain-field { gap: 5px; }
.pf-asks .note-hint { line-height: 1.45; }

/* The model sits at the top of the references panel now — it is the control that decides what
   that panel asks for. Padded off the head below it so the two read as two things. */
.ref-model { padding: 0 0 12px; border-bottom: 1px solid var(--border); margin-bottom: 10px; }

/* ---- reference slots, as cards that say what they want ---------------------------------------
   The name and the style's explanation were in a `title` tooltip on the icon: invisible on a
   phone, invisible without a hover, invisible in a screenshot — so six grey rows with six
   different icons were all a creator had to go on. */
.anchor-cat-txt { display: grid; gap: 2px; min-width: 0; flex: 1 1 200px; }
.anchor-cat-line { display: flex; align-items: baseline; gap: 8px; }
.anchor-cat-line b { font-size: 13.5px; font-weight: 640; }
.anchor-cat-hint { font-size: 11.5px; line-height: 1.45; color: var(--text-muted); }
/* NEEDED, IN ONE CHARACTER. Used on the brief's questions and on the reference slots alike —
   one convention for "this one is not optional" across the whole setup page. Optional things
   carry nothing: silence is what optional looks like on every form ever printed. */
.req { font-style: normal; font-weight: 400; color: var(--danger); font-size: .78em;
  line-height: 1; margin-left: 1px; vertical-align: .32em; }

.ref-model .select { width: 100%; }

/* ---- References: what the run drew ----------------------------------------------------------
   The panel answered "what did you give it". The other half — what the run drew out of that — is
   the half that decides the clip, and it was only visible in a folder on the machine that drew
   it. It sits under the clip's own video on References, because it is a fact about one clip. */
.gen-sec { margin-top: 14px; }

/* THE SHEET FIRST, and captioned. Four frames that came out of one generation is the whole
   argument for this path, and it is invisible unless the uncut canvas is on screen beside them. */
.gen-sheets { display: grid; gap: 8px; }
.gen-sheet img { width: 100%; border-radius: 9px; display: block; cursor: zoom-in;
  border: 1px solid var(--border); }
.gen-sheet figcaption, .gen-shot figcaption { font-size: 11px; color: var(--text-faint);
  display: flex; align-items: center; gap: 6px; padding-top: 4px; }

.gen-shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.gen-shot { margin: 0; }
.gen-shot img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 8px;
  display: block; cursor: zoom-in; border: 1px solid var(--border); }
.gen-shot.is-bad img { border-color: var(--warn); }
.gen-shot figcaption b { color: var(--text); font-weight: 640; }
.gen-missing { aspect-ratio: 16 / 9; display: grid; place-items: center; border-radius: 8px;
  border: 1px dashed var(--border-hi); color: var(--text-faint); font-size: 11px; }

/* The tag says WHERE the frame came from, which is the one thing a picture cannot show: two
   shot 4s look identical and one of them cost a whole extra generation. */
.gen-tag { margin-left: auto; padding: 1px 6px; border-radius: 999px; font-size: 10px;
  font-weight: 650; background: var(--surface-2); color: var(--text-muted); }
.gen-tag.bad { background: rgba(255,179,64,.14); color: var(--warn); }
.gen-why { margin: 3px 0 0; font-size: 10.5px; line-height: 1.4; color: var(--warn); }
.gen-redraw { border: 0; background: none; padding: 0; font: inherit; font-size: 11px;
  color: var(--text-faint); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.gen-redraw:hover { color: var(--accent); }

/* THE PROMPT, folded away. It is the answer to "why did it draw THAT" and it is four hundred
   words long — open by default it would bury the eight pictures it is about. */
.gen-prompt { margin-top: 4px; }
.gen-prompt > summary { cursor: pointer; font-size: 10.5px; color: var(--text-faint);
  list-style: none; }
.gen-prompt > summary::-webkit-details-marker { display: none; }
.gen-prompt > summary::before { content: "▸ "; }
.gen-prompt[open] > summary::before { content: "▾ "; }
.gen-prompt > summary:hover { color: var(--accent); }
.gen-prompt p { margin: 4px 0 0; padding: 7px 9px; border-radius: 8px; font-size: 10.5px;
  line-height: 1.5; color: var(--text-muted); background: var(--surface-2);
  max-height: 200px; overflow-y: auto; white-space: pre-wrap; }

/* ---- admin: running now ---------------------------------------------------------------------
   The owner column is the point of the table. "Why is that still generating" almost always ends
   at "because the one still going belongs to a different account", and that answer took a
   database session to find. */
.watch-row { border: 1px solid var(--border); border-radius: 10px; margin-bottom: 8px; background: var(--surface, transparent); }
.watch-row summary { cursor: pointer; padding: 10px 12px; font-size: 13px; display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.watch-row .watch-t { margin-left: auto; }
.watch-kind { font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--danger, #f87171); border: 1px solid currentColor; border-radius: 6px; padding: 1px 6px; }
.watch-row pre { margin: 0; padding: 0 12px 12px; font-size: 11.5px; white-space: pre-wrap; word-break: break-word; color: var(--text-muted); }
.run-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.run-table th, .run-table td { padding: 8px 10px; border-bottom: 1px solid var(--border);
  text-align: left; }
.run-table th { font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint); }
.run-table td.n { font-variant-numeric: tabular-nums; color: var(--text-muted); }
.run-table tr.is-live td { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.run-owner { color: var(--text-muted); font-size: 11.5px; }
.run-live { display: inline-flex; align-items: center; gap: 5px; font-weight: 650; color: var(--ok); }
.run-live::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 22%, transparent); }
.run-due { color: var(--warn); font-weight: 640; }

/* ---- create-workspace, step 2: choosing on the left, the film on the right -------------------
   Before a style is picked the sheet is a wall of posters, which is the right thing to show
   when the question is "which look". After one is picked the question is "is this the look",
   and only one film can answer it — so the wall folds to a single row and the clip takes the
   space it was using. */
.ws-style-split { display: grid; gap: 18px; }
#wsStepStyle.has-pick .ws-style-split { grid-template-columns: minmax(0, 1fr) minmax(0, 300px); }
.ws-style-left { min-width: 0; }

.ws-style-chosen { display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border: 1px solid var(--accent-border); border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 6%, transparent); }
.ws-chosen-txt { display: grid; gap: 2px; min-width: 0; }
.ws-chosen-eyebrow { font-size: 10px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent); }
.ws-style-chosen b { font-size: 14px; font-weight: 650; }
.ws-style-chosen .btn-ghost { margin-left: auto; flex: none; }

/* PREVIEW, labelled like the one on the Format step — same panel, same job: this is what the
   choice above will look like. */
.ws-style-preview { display: grid; gap: 8px; align-content: start; }
.ws-prev-head { display: flex; align-items: center; justify-content: space-between;
  font-family: "Space Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .1em;
  color: var(--text-faint); }
.ws-prev-tag { padding: 1px 7px; border-radius: 999px; background: var(--surface-2);
  color: var(--text-muted); letter-spacing: .04em; }
.ws-prev-stage { aspect-ratio: 4 / 3; border-radius: 12px; overflow: hidden;
  background: #000; border: 1px solid var(--border); }
.ws-prev-stage video, .ws-prev-stage img { width: 100%; height: 100%; object-fit: cover;
  display: block; }
.ws-prev-none { width: 100%; height: 100%; display: grid; place-items: center;
  color: var(--text-faint); font-size: 12px; }
.ws-prev-blurb { margin: 0; font-size: 11.5px; line-height: 1.5; color: var(--text-muted); }

@media (max-width: 760px) {
  #wsStepStyle.has-pick .ws-style-split { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Brief: the style panel and the question column --------------------------------------
   Two columns, and they are two different kinds of thing: the left is context you look AT (the
   film this style makes, its name, the way out of this step) and the right is work you look
   THROUGH (one question after another). Mixing them — the old layout put a spec list and a
   progress bar beside the form — meant every glance at the film cost a scan of a list. */
/* 430, not 360. At 360 everything in the panel was pressed against its own border: the slot
   note "1 slot for this style" ended ON the edge, the pool counter could not share a line with
   the word References, and the hint under the uploads broke over two lines. The column holds a
   film, a model, and every upload the style asks for — it is the raw material, not a sidebar. */
/* Declared on the VIEW, not the grid: the action bar is fixed to the bottom of the same view
   and has to land on this width too, and it is not a descendant of the grid. */
.view-ask:has(#briefRail:not(.hidden)) { --rail: 1290px; }
.view-ask .home-grid:has(#briefRail:not(.hidden)) {
  grid-template-columns: minmax(0, 430px) minmax(0, 1fr); max-width: var(--rail);
  align-items: start; gap: 22px; }
/* :not(#briefRail) is load-bearing, not tidiness: `:has(#briefRail…)` carries that id into this
   selector's specificity, so a bare `> *` outranks the `#briefRail` rule below and would drag
   the panel itself into the question column. */
.view-ask .home-grid:has(#briefRail:not(.hidden)) > *:not(#briefRail) { grid-column: 2; }
.brief-col { display: grid; gap: 20px; align-content: start; min-width: 0; }
/* NOT STICKY. It was, back when it held a film and four lines of text; it now carries the model
   and every upload slot the style asks for, so sticking it pinned a column taller than the
   viewport — the left side simply stopped scrolling part way down while the right carried on.
   (This is the second time: the rule came back when this section was rewritten. If it looks
   tempting again, the panel has to be shorter than a screen first.) */
#briefRail { grid-column: 1; grid-row: 1 / -1; align-self: start; }

/* NO BOX. The column is not a card sitting on the page — it IS the page's left half: the film,
   the model and the upload slots each already carry their own frame, so a box around all three
   was a fourth border drawn around three borders. Frameless, the film reads as the biggest
   thing on the left, which is what it is; the hairlines between the sections do the separating
   a border was being asked to do. */
/* A CARD AGAIN (2026-10-15, option B): it carries .setup-card, the same box as the brief beside it,
   and is stretched to that box's height. See "Setup: the style card" at the end of this file. */
.brief-side { display: grid; gap: 12px; }
.bs-eyebrow { font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--accent); }
.bs-stage { aspect-ratio: 4 / 3; border-radius: 12px; overflow: hidden; background: #000;
  border: 1px solid var(--border); }
.bs-stage video, .bs-stage img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* "Let Muse choose": the styles it picks from, in turn, crossfading. */
.bs-stage.auto-reel { position: relative; }
.bs-stage.auto-reel .ar-layer { position: absolute; inset: 0; opacity: 0; transition: opacity .6s ease; }
.bs-stage.auto-reel .ar-layer.on { opacity: 1; }
.ar-dots { position: absolute; left: 0; right: 0; bottom: 10px; display: flex; justify-content: center; gap: 5px; z-index: 2; }
.ar-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.4); transition: width .3s, background .3s; }
.ar-dots i.on { width: 16px; border-radius: 3px; background: #fff; }
@media (prefers-reduced-motion: reduce) { .bs-stage.auto-reel .ar-layer { transition: none; } }

.bs-pick { display: flex; align-items: center; gap: 10px; padding-top: 12px;
  border-top: 1px solid var(--border); }
.bs-thumb { flex: none; width: 46px; aspect-ratio: 1; border-radius: 9px; overflow: hidden;
  background: var(--surface-2); }
.bs-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bs-txt { display: grid; gap: 2px; min-width: 0; }
.bs-txt b { font-size: 14px; font-weight: 640; }
.bs-txt > span { font-size: 11.5px; line-height: 1.4; color: var(--text-muted); }
.bs-pick .btn-ghost { flex: none; margin-left: auto; align-self: start; }
/* No style: there is no film to show and nothing of the style's to answer, so only the line
   that says so and the uploads remain. */
/* …and the eyebrow: "The style you are shooting in" over a line saying there is none. */
.brief-side.no-style .bs-eyebrow,
.brief-side.no-style .bs-stage, .brief-side.no-style .bs-thumb,
.brief-side.no-style .brief-progress, .brief-side.no-style .brief-progress-txt { display: none; }
.brief-side.no-style .bs-pick { border-top: 0; padding-top: 0; }

/* The one action of this step, on the panel rather than in a bar at the bottom of a long scroll.
   The footer still owns it — this presses the same form — so there is one submit path. */
.brief-progress { height: 4px; border-radius: 3px; background: var(--surface-2); overflow: hidden; }
.brief-progress > div { height: 100%; width: 0; background: var(--accent); border-radius: 3px;
  transition: width .3s ease; }
.brief-progress-txt { font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px;
  color: var(--text-faint); }
/* The uploads sit inside the panel, so they lose their own frame — one box drawn inside another
   box reads as two things when it is one. */
/* box-shadow AND border-radius too, not just the border: .ref-panel's frame is three
   properties, and killing two of them leaves the third drawing the same box — a soft rounded
   halo around the model and the uploads, which is what was still on screen after the border
   went. Anything that removes a card here has to remove all of it. */
.brief-side .ref-panel { border: 0; background: none; padding: 0; box-shadow: none;
  border-radius: 0; border-top: 1px solid var(--border); padding-top: 14px; margin-top: 2px; }
/* A 360px column, so the heading's counters wrap under it instead of pushing the badge out
   past the panel's own edge. */
/* Title on one line, the counters on the next — at 360px they were fighting for the same row
   and losing three lines to it. */
.brief-side .anchor-head { display: grid; grid-template-columns: 1fr auto; row-gap: 4px;
  align-items: baseline; }
.brief-side .anchor-head > .ref-count, .brief-side .anchor-head > .ref-refresh { grid-column: 1 / -1; }

/* ---- a slot is a card, and the card says what goes in it ------------------------------------
   Dashed, because that is what an empty drop target has looked like since drop targets existed,
   and these are empty until someone fills them. Two to a row: the hint is a sentence, and a
   sentence in a 170px column is four words a line. */
/* Outranks `.view-ask .ref-panel .anchor-drops`, which is where the column layout is set for
   this view — a two-class selector loses to a three-class one, and the cards stacked one to a
   row for exactly that reason. */
.view-ask .brief-side .anchor-drops { display: grid;
  /* THE TRACK IS MEASURED FROM WHAT IT HAS TO HOLD, not chosen. A card spends 11px of left
     padding, 25px of inset for the icon sitting over the name, and 60px reserved at the right
     for the AI pill — 96px before a letter is drawn. "Environment" is the longest slot name at
     93px, so the minimum track is 190px.
     At 132px it fitted three to a row in the 430px panel and left 40px for the name, so every
     card read "Ch…", "Wa…", "En…" — the one word on the card that says what it is for. */
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px; max-height: none; overflow: visible; }
/* A ROW THAT WRAPS, not a column. As a column each of the card's three parts — the thumbnails,
   the ＋, the AI toggle — took a line of its own, so a 42px button sat alone on a 42px row and
   the card was three times taller than its contents. The heading is given a full-width basis so
   it still breaks the line under itself; everything after it flows and folds. */
.view-ask .brief-side .anchor-drop { flex-direction: row; flex-wrap: wrap; align-items: center;
  gap: 6px; padding: 12px 11px; border-radius: 14px; border: 1.5px dashed var(--border-hi);
  min-height: 0; }
.brief-side .anchor-drop.filled { border-style: solid; }
/* The disc is gone here: at card size it read as an avatar, and three coloured avatars over
   three sentences is a cast list. The icon keeps the slot's own shape and takes the accent. */
.brief-side .anchor-cat-head { width: auto; height: auto; border-radius: 0; background: none;
  border: 0; color: var(--accent); display: inline-flex; }
.brief-side .anchor-drop:hover .anchor-cat-head { transform: none; }
.brief-side .anchor-ico { width: 19px; height: 19px; }
.brief-side .anchor-cat-txt { flex: none; }
.brief-side .anchor-cat-line { align-items: center; }
.brief-side .anchor-cat-line b { font-size: 15px; font-weight: 700; }
/* TWO ROWS, ALWAYS — and this time by construction rather than by arithmetic. Three attempts
   at "make it fit" failed for the same reason: every part of the card was in the same wrapping
   flex, so the width of a name decided whether the toggle got its own line, and one card
   growing dragged its neighbour up with it. So the toggle is lifted out of the flow entirely
   (absolute, top-right) and the name is forbidden to wrap. What is left to lay out is one row
   of pictures, which cannot be anything but one row. */
.view-ask .brief-side .anchor-cat-txt { flex: 0 0 100%; }
/* The pill is 48px wide and sits 11px off the right edge, so the text has to stop 59px in. It
   stopped at 58 — one pixel under the thing it was reserving room for. */
.view-ask .brief-side .anchor-drop { padding-right: 60px; }
.view-ask .brief-side .anchor-ai-wrap { position: absolute; top: 11px; right: 11px;
  margin: 0; width: auto; }
.view-ask .brief-side .anchor-cat-line { flex-wrap: nowrap; min-width: 0; }
.view-ask .brief-side .anchor-cat-line b { overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.view-ask .brief-side .req { flex: none; }
/* Scrolling sideways inside a 160px card hides what is in it; wrap instead. */
.view-ask .brief-side .anchor-thumbs { flex: 0 1 auto; width: auto; flex-wrap: wrap;
  overflow: visible; padding: 0; margin: 0; }
/* AN EMPTY BOX STILL COSTS A GAP. With no uploads this container is 0 wide but the flex gap
   after it is not, so the ＋ in an empty slot sat a few pixels further in than the thumbnail in
   a filled one — three cards side by side, none of them lining up. */
.view-ask .brief-side .anchor-thumbs.is-empty { display: none; }
.view-ask .brief-side .anchor-addslot { width: auto; }
/* The icon belongs on the name's line, which means lifting it out of the column flow. */
.brief-side .anchor-drop { position: relative; padding-left: 14px; }
.brief-side .anchor-cat-head { position: absolute; top: 13px; left: 14px; }
.view-ask .brief-side .anchor-cat-txt { padding-left: 25px; min-width: 0; }
.view-ask .brief-side .anchor-cat-line { flex-wrap: wrap; row-gap: 2px; }
/* A grid item's default min-width is its own content, so one long hint would widen its track
   and shove the second card off the panel instead of wrapping inside its own. */
.view-ask .brief-side .anchor-drop { min-width: 0; }
/* THE CONTROLS WRAP INSIDE THE CARD. .anchor-ai-wrap is a fixed three-track grid — 30 + 92 + 62
   plus gaps, 200px — laid out for a full-width row and pushed right by `margin-left: auto`. In
   a 160px card that overflowed, so the AI button was drawn outside the card it belongs to and,
   on the right-hand column, outside the panel. Flex here: same controls, allowed to fold. */
.view-ask .brief-side .anchor-ai-wrap { display: flex; flex-wrap: wrap; gap: 6px;
  grid-template-columns: none; margin-left: auto; width: auto; justify-items: start; }
/* 38, not 42 — see the note above the card. The thumbnail, the ＋ and the AI placeholder all
   take it together, so they stay the same size as each other, which is the thing that matters. */
.view-ask .brief-side .anchor-thumb-item,
.view-ask .brief-side .anchor-ai-tile,
.view-ask .brief-side .anchor-add { width: 38px; height: 38px; }
.view-ask .brief-side .anchor-thumbs { gap: 5px; }
.view-ask .brief-side .anchor-ai-wrap > * { grid-column: auto; }

/* It saved, and that is all this line ever has to say. */
.brief-saved { font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px;
  color: var(--text-faint); }
/* The two words that decide when this workspace stops. Amber is the colour this app already
   uses for "a limit applies" — the REQUIRED tag on a reference slot, the over-budget count. */
.cap-hi { color: var(--warn); font-weight: 650; }

/* The story block in a clip's Settings tab. The source tag matters as much as the text: "picked
   from the shortlist" and "written for this run" are two different explanations for why the next
   clip may not say the same thing. */
.clip-story-t { margin: 0 0 4px; font-size: 13.5px; font-weight: 650; color: var(--text); }
.clip-story-m { margin: 6px 0 0; font-size: 11.5px; color: var(--text-faint); }
.clip-story-src { font-family: "Space Mono", ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint);
  font-weight: 400; margin-left: 6px; }
.brief-save { display: flex; justify-content: flex-end; padding-top: 6px; }

/* ---- one question, one row ------------------------------------------------------------------
   Title, what it is for in one line, and the box. Separated by a hairline rather than boxed:
   eighteen cards down a page is eighteen objects to parse, and these are not eighteen things —
   they are one brief. */
.qrow { display: grid; gap: 5px; padding: 15px 0; border-top: 1px solid var(--border); }
.qrow:first-child { border-top: 0; padding-top: 4px; }
.qrow-head { display: flex; align-items: baseline; gap: 9px;
  font-size: 14px; font-weight: 640; color: var(--text); }
/* MISSING, and nothing when it is answered. A green tick on every finished field is nineteen
   ticks competing with the three things still to do. */
/* SAID OUT LOUD, not hidden behind the ⓘ. One of these answers is a sequence and the arrow
   between its steps is not on anybody's keyboard — a creator who never hovers the icon types
   commas, and the style then reads one step where there were four. */
.qrow-key { font-family: "Space Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .04em; color: var(--text-faint); border: 1px solid var(--border);
  border-radius: 5px; padding: 1px 5px; white-space: nowrap; }
.qrow-tag { font-family: "Space Mono", ui-monospace, monospace; font-style: normal;
  font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); }
.qrow.done .qrow-tag { display: none; }
/* .qrow-hint is gone — the guidance moved into the ⓘ beside each label, which is hover-only.
   The tooltip needs room to open downward under a label at the top of the column. */
/* ABOVE THE ICON AND OPENING RIGHT. Below-left put the bubble over the answers the question is
   about — the cards or the box you are on your way to — and hid the next question under it. */
.qrow-head .help-q::after { bottom: calc(100% + 8px); top: auto; left: -4px; right: auto;
  transform: translateY(4px); }
.qrow-head .help-q:hover::after, .qrow-head .help-q:focus-visible::after { transform: translateY(0); }
.qrow .select { width: 100%; }
#briefCard .qrow .brain-label { display: none; }

/* The style block belongs to the side panel while there is one. "Change" over there adds
   .picking here, which is the only way back in — so the choice has exactly one home on screen
   at a time instead of two that can disagree. */
/* (#pfStyleField is the body of #styleSheet now, outside the grid: see "Setup: the style card".) */

/* The footer stays. It carries the number this step is actually judged on — "6 credits per
   clip · 0.2/s at 720p x 30s · about 12 a day at 2 posts" — which is the one thing on screen a
   creator cannot work out for themselves. */

/* ---- the style: one row, and a wall of films behind it --------------------------------------
   It was a line of text and a button to another page. A style decides more about the finished
   clip than every field under it, and the only honest way to offer a look is to show one — but
   only while the look is being chosen. The row is the permanent state; the wall is the visit
   where the creator changes their mind.

   NAMED sty-g*, NOT sty-grid/sty-card. The Styles gallery's own container is #styGrid.sty-grid,
   and a `.sty-grid` rule down here quietly won the cascade there: its 268px cards became 150px
   ones, seven to a row with their blurbs cut off. Every class in this block is the picker's. */
.sty-summary { display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 12px 8px 8px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface);
  color: var(--text); font: inherit; text-align: left; cursor: pointer;
  transition: border-color .14s, background .14s; }
.sty-summary:hover { border-color: var(--accent-border); }
.sty-summary[aria-expanded="true"] { border-color: var(--accent); }
.sty-sthumb { flex: none; width: 60px; aspect-ratio: 4 / 3; border-radius: 8px; overflow: hidden;
  position: relative; background: var(--surface-2); }
.sty-sthumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sty-stxt { display: grid; gap: 2px; min-width: 0; }
.sty-stxt b { font-size: 13.5px; font-weight: 640; }
.sty-stxt > span { font-size: 11.5px; color: var(--text-muted); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sty-scta { flex: none; margin-left: auto; font-family: "Space Mono", ui-monospace, monospace;
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); }

.sty-gwall { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px; margin-top: 10px; }
/* THE CARD IS THE FILM — the same call the gallery makes, for the same reason. A title block
   UNDER the picture is a second surface competing with it for one glance, and it is also where
   the gap between the word and the card came from: the caption sat on the card's background
   instead of on the picture. Inside the frame there is no gap to have. */
.sty-gcard { position: relative; display: block; overflow: hidden; padding: 0; cursor: pointer;
  aspect-ratio: 4 / 3; border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface-2); color: var(--text); font: inherit; text-align: left;
  transition: border-color .14s, box-shadow .14s; }
.sty-gcard:hover { border-color: var(--accent-border); }
.sty-gcard.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.sty-gshot { position: absolute; inset: 0; }
.sty-gshot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sty-gempty { position: absolute; inset: 0;
  background: repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 9px, transparent 9px 18px),
              var(--surface-2); }
/* Blur AND a gradient: the blur keeps the footage readable as footage behind the words, and the
   gradient is what guarantees contrast on the one card whose frame happens to be pale. */
.sty-gcap { position: absolute; inset: auto 0 0 0; z-index: 2; display: grid; gap: 2px;
  /* Same inset as the gallery's caption. At 10px the name sat on the card's edge — a word
     touching a border reads as a mistake before it reads as a label. */
  padding: 28px 14px 12px;
  background: linear-gradient(to top, rgba(8,7,11,.88) 14%, rgba(8,7,11,.55) 58%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  -webkit-mask-image: linear-gradient(to top, #000 62%, transparent);
  mask-image: linear-gradient(to top, #000 62%, transparent); }
.sty-gname { font-size: 13px; font-weight: 640; color: #fff; }
/* The count is the cost of the choice, and it belongs on the card rather than being discovered
   after it: a style that asks three questions is three more things to answer. */
.sty-gasks { font-family: "Space Mono", ui-monospace, monospace; font-size: 9.5px;
  letter-spacing: .08em; color: rgba(255,255,255,.64); }
.sty-gcard.on .sty-gasks { color: #fff; }
/* FITS YOUR PRODUCT — the References page's AI corner ribbon (.ref-mark .rm-ai), same gold
   triangle and diagonal word, a little larger for a card this size. Advice (brain.style_fit). */
.fit-mark { position: absolute; top: 0; right: 0; z-index: 3; width: 54px; height: 54px;
  pointer-events: none; }
.fit-mark i { position: absolute; inset: 0; display: block; font-style: normal;
  background: linear-gradient(135deg, var(--warn), #ffd089);
  clip-path: polygon(0 0, 100% 0, 100% 100%); }
.fit-mark i b { position: absolute; top: 33%; left: 66%; transform: translate(-50%, -50%) rotate(45deg);
  color: #0a0c12; font-size: .56rem; font-weight: 800; letter-spacing: .06em; line-height: 1;
  white-space: nowrap; }
/* The ticked style does not suit the product: said once, under the row, with the way out. */
.sty-misfit { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 8px;
  padding: 10px 12px; border: 1px solid var(--warn); border-radius: 12px;
  background: color-mix(in srgb, var(--warn) 10%, var(--surface)); font-size: 12.5px;
  line-height: 1.45; color: var(--text); }
.sty-misfit-txt { flex: 1 1 260px; min-width: 0; }
.sty-misfit-acts { display: flex; gap: 8px; flex-wrap: wrap; }


/* A deleted clip's slot in the activity feed: the same box the thumbnail occupies, so the rows
   stay aligned, holding the reason rather than a black rectangle. */
.feed-thumb.gone { display: grid; place-items: center; color: var(--text-faint);
  background: var(--surface-2); border: 1px dashed var(--border); }
.feed-thumb.gone svg { width: 18px; height: 18px; }

/* ---- the read-only workspace window (wsview.js) ---------------------------------------------
   The first version was forty label/value rows, and the subject of every one of them is a
   picture: the film this style makes, the photographs it was given, the shape it renders at,
   the clock it runs on. Each of those is drawn here instead of described. */
/* The card sizes itself the way the reference modal does, and the padding lives on the block
   inside it — the first version put a width on this and no padding, so the content sat flush
   against the card's own edge on both sides. */
.modal-card:has(.wsv) { max-width: 760px; }
.wsv { display: grid; gap: 16px; padding: 24px 26px 26px; }
/* Clear of the ✕, which is absolutely positioned in the card's corner. */
.wsv-title { display: flex; align-items: center; gap: 10px; margin: 0; padding-right: 40px;
  font-size: 1.05rem; }
.wsv-ro { font-family: "Space Mono", ui-monospace, monospace; font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint); border: 1px solid var(--border);
  border-radius: 6px; padding: 2px 7px; }
.wsv-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); }
.wsv-tab { border: 0; background: none; padding: 9px 13px; margin-bottom: -1px; cursor: pointer;
  font: inherit; font-size: .88rem; color: var(--muted); border-bottom: 2px solid transparent; }
.wsv-tab:hover { color: var(--text); }
.wsv-tab.on { color: var(--text); border-bottom-color: var(--accent); }
/* overscroll-behavior: the horizontal swipe between pages must not also drag the page behind
   the modal, and a vertical flick that reaches the end of this list must not scroll the app. */
.wsv-body { max-height: min(64vh, 560px); overflow-y: auto; overflow-x: hidden;
  padding-right: 6px; overscroll-behavior: contain; }
.wsv-block { margin-bottom: 18px; }
.wsv-block > h4 { margin: 0 0 8px; font-size: .66rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint); }
.wsv-empty { margin: 0; font-size: .85rem; color: var(--muted); }

/* The style, as the film it is. */
.wsv-hero { display: flex; gap: 14px; align-items: stretch; padding: 12px; border-radius: 14px;
  border: 1px solid var(--border); background: var(--surface); }
.wsv-hero-art { flex: none; width: 92px; aspect-ratio: 9 / 16; border-radius: 10px;
  overflow: hidden; background: #000; display: grid; place-items: center; }
.wsv-hero-art img, .wsv-hero-art video { width: 100%; height: 100%; object-fit: cover;
  display: block; }
.wsv-hero-none { font-size: 10px; color: var(--text-faint); text-align: center; padding: 0 6px; }
.wsv-hero-txt { display: grid; align-content: center; gap: 4px; min-width: 0; }
.wsv-hero-txt b { font-size: 1.02rem; font-weight: 650; }
.wsv-hero-txt > span { font-size: .85rem; color: var(--muted); line-height: 1.45; }
.wsv-eyebrow { font-family: "Space Mono", ui-monospace, monospace; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent) !important; }
.wsv-model { font-size: .78rem !important; color: var(--text-faint) !important; }

/* Facts: the label above its value, two to a row — a sentence gets the whole row. */
.wsv-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 8px; }
.wsv-fact { display: grid; gap: 3px; padding: 9px 11px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--card); min-width: 0; }
.wsv-fact.wide { grid-column: 1 / -1; }
.wsv-fk { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); }
.wsv-fv { font-size: .88rem; color: var(--text); overflow-wrap: anywhere; line-height: 1.4; }

/* References, as pictures with their category under them. */
.wsv-refs { display: flex; flex-wrap: wrap; gap: 10px; }
.wsv-ref { margin: 0; display: grid; gap: 4px; justify-items: center; }
.wsv-ref img { width: 68px; height: 68px; object-fit: cover; border-radius: 10px;
  border: 1px solid var(--border); }
.wsv-ref figcaption { font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--faint); }

/* The shape, drawn at the film's real aspect ratio. */
.wsv-shape { display: flex; gap: 16px; align-items: center; padding: 14px; border-radius: 14px;
  border: 1px solid var(--border); background: var(--surface); }
.wsv-screen { flex: none; border-radius: 8px; border: 1.5px solid var(--border-hi);
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 10%, transparent), transparent);
  display: grid; place-items: center; }
.wsv-screen span { font-family: "Space Mono", ui-monospace, monospace; font-size: 11px;
  color: var(--muted); }
.wsv-shape-txt { display: grid; gap: 3px; }
.wsv-shape-txt b { font-size: 1rem; font-weight: 650; text-transform: capitalize; }
.wsv-shape-txt span { font-size: .84rem; color: var(--muted); }

/* One box per shot — countable. */
.wsv-shots { display: flex; flex-wrap: wrap; gap: 6px; }
.wsv-shot { display: grid; place-items: center; gap: 1px; width: 52px; height: 52px;
  border-radius: 9px; border: 1px solid var(--border); background: var(--card); font-style: normal; }
.wsv-shot b { font-size: .84rem; font-weight: 650; }
.wsv-shot u { text-decoration: none; font-size: 10px; color: var(--faint); }

.wsv-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px; }
.wsv-tile { display: grid; gap: 2px; padding: 11px 12px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--card); }
.wsv-tile b { font-size: 1.25rem; font-weight: 650; line-height: 1.1; }
.wsv-tile b u { text-decoration: none; font-size: .8rem; color: var(--faint); }
.wsv-tile span { font-size: .72rem; color: var(--muted); }
.wsv-cap { display: block; height: 3px; margin-top: 6px; border-radius: 2px;
  background: var(--surface-2); overflow: hidden; }
.wsv-cap em { display: block; height: 100%; background: var(--accent); }

/* The schedule, on the same 24-hour track the Posting card uses. */
.wsv-track-wrap { margin-bottom: 12px; }
.wsv-track { position: relative; height: 30px; border-radius: 10px; border: 1px solid var(--border);
  margin-top: calc(22px + (var(--lanes, 1) - 1) * var(--lane-h, 22px));
  background: linear-gradient(90deg, #141319 0%, #1C1B22 25%, #232128 50%, #1C1B22 75%, #141319 100%); }
.wsv-mark { position: absolute; top: calc(-18px - var(--lane, 0) * var(--lane-h, 22px)); transform: translateX(-50%); display: grid;
  justify-items: center; gap: 2px; font-style: normal; }
.wsv-mark b { padding: 2px 7px; border-radius: 999px; background: var(--accent); color: var(--on-accent);
  font-family: "Space Mono", ui-monospace, monospace; font-size: 10px; white-space: nowrap; }
.wsv-mark::after { content: ""; width: 2px; height: calc(30px + var(--lane, 0) * var(--lane-h, 22px)); border-radius: 2px; background: var(--accent); }
.wsv-axis { margin-top: 6px; display: flex; justify-content: space-between;
  font-family: "Space Mono", ui-monospace, monospace; font-size: 10px; color: var(--text-faint); }
.wsv-tz { margin: 8px 0 0; font-size: .78rem; color: var(--faint); }
/* .sday-chip does the work (same pills as the Posting card); these are read-only, so they lose
   the pointer and the hover the real buttons have. */
.wsv-days .sday-chip { cursor: default; display: inline-flex; align-items: center; }
.wsv-days .sday-chip:hover { background: transparent; border-color: #2E2C38; color: var(--text-muted); }
.wsv-days .sday-chip.on:hover { background: var(--accent-weak); border-color: var(--accent-border);
  color: #CBD6FF; }

.wsv-dest { display: grid; gap: 8px; }
/* The destination is the one thing on this page with a platform behind it, so it gets the
   chip the account picker already uses for exactly that — same pill, same cyan, one size up. */
.wsv-chip { display: inline-flex; align-items: center; gap: 7px; justify-self: start;
  padding: 6px 13px; border-radius: 999px; background: rgba(0,229,255,.09);
  border: 1px solid var(--cyan-dim); color: var(--text); font-size: .88rem; white-space: nowrap; }
.wsv-chip svg { width: 16px; height: 16px; }
.wsv-dest-note { font-size: .8rem; color: var(--muted); }

/* ---- the one-box brief (composer.js) --------------------------------------------------------
   The same card, radius, hairlines and type as the Format and Schedule steps — nothing here is a
   new kind of control. A chat composer is the shape because that is what this is now: photos
   above, words in the middle, the two choices that shape the film as pills under it. */
#briefCard {
  /* One colour per photo, so a chip in the sentence and a thumbnail in the strip can be matched
     at a glance. Muted against the night canvas; none of them is the accent or the danger red,
     which already mean "the action" and "something is wrong". */
  --mc-c0:#7C93FF; --mc-c1:#3CC9A4; --mc-c2:#E6B04B; --mc-c3:#D883E6;
  --mc-c4:#5CC3E8; --mc-c5:#EE8F6A; --mc-c6:#A3C95A; --mc-c7:#B79CFF;
}
.mc { position: relative; display: grid; gap: 12px; padding: 12px 14px 10px;
  border: 1px solid var(--border-strong); border-radius: 14px; background: var(--bg);
  transition: border-color .15s, box-shadow .15s; }
.mc:focus-within { border-color: var(--accent-border); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent); }
.mc.dragover { border-style: dashed; border-color: var(--accent); background: var(--accent-weak); }

/* The empty state: one big dashed target, the way every upload on this app already looks. */
.mc-drop { display: flex; align-items: center; gap: 14px; width: 100%; padding: 14px 16px;
  border: 1.5px dashed var(--border-strong); border-radius: 12px; background: var(--surface);
  color: var(--text); font: inherit; text-align: left; cursor: pointer;
  transition: border-color .15s, background .15s; }
.mc-drop:hover { border-color: var(--accent); background: var(--surface-2); }
.mc-badges { display: inline-flex; flex: none; padding-left: 10px; }
.mc-badge { width: 34px; height: 34px; margin-left: -10px; border-radius: 50%;
  display: grid; place-items: center; background: var(--surface-2); color: var(--accent);
  border: 2px solid var(--surface); }
.mc-badge:nth-child(2) { color: var(--mc-c1, #3CC9A4); }
.mc-badge:nth-child(3) { color: var(--mc-c2, #E6B04B); }
.mc-badge svg { width: 17px; height: 17px; }
.mc-drop-txt { display: grid; gap: 1px; min-width: 0; }
.mc-drop-txt b { font-size: 14px; font-weight: 640; }
.mc-drop-txt span { font-size: 12px; color: var(--text-muted); }

/* The strip: each photo, its number, and what it is used as. */
.mc-strip { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; }
.mc-att { position: relative; width: 76px; display: grid; gap: 5px; }
.mc-att-img { width: 76px; height: 76px; padding: 0; border-radius: 10px; overflow: hidden;
  border: 2px solid var(--c, var(--border)); background: var(--surface-2); cursor: zoom-in; }
.mc-att-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mc-att.off .mc-att-img img { opacity: .45; }
.mc-att-x { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; padding: 0;
  border-radius: 50%; border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-muted); font-size: 13px; line-height: 1; cursor: pointer; opacity: 0;
  transition: opacity .12s; }
.mc-att:hover .mc-att-x, .mc-att-x:focus-visible { opacity: 1; }
@media (hover: none) { .mc-att-x { opacity: 1; } }
.mc-att-x:hover { color: var(--text); border-color: var(--danger); }
.mc-att-meta { display: grid; gap: 3px; justify-items: start; }
.mc-att-n { padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--font-mono); font-size: 10.5px; color: var(--c, var(--text-muted)); }
.mc-att-n:hover { text-decoration: underline; }
.mc-att-cat { max-width: 100%; padding: 1px 7px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text-muted);
  font: 600 10.5px/1.5 var(--font-sans); cursor: pointer; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
.mc-att-cat:hover { color: var(--text); border-color: var(--accent-border); }
.mc-att-cat:disabled { cursor: default; }
.mc-att-cat.warn { color: var(--warn); border-color: rgba(224,169,58,.45); background: var(--warn-weak); }
.mc-att-add { width: 76px; height: 76px; border-radius: 10px; border: 1.5px dashed var(--border-strong);
  background: none; color: var(--text-muted); font-size: 22px; cursor: pointer; }
.mc-att-add:hover { border-color: var(--accent); color: var(--text); }

/* The box. A contenteditable, not a textarea: the photo chips are elements, and a textarea can
   only draw them by overlaying a mirrored copy that drifts a pixel per line on every zoom level. */
.mc-edit { position: relative; min-height: 112px; max-height: 340px; overflow-y: auto;
  padding: 2px 2px 4px; outline: none; white-space: pre-wrap; overflow-wrap: anywhere;
  font: 400 15px/1.65 var(--font-sans); color: var(--text); caret-color: var(--accent); }
.mc-edit.is-empty::before { content: attr(data-placeholder); position: absolute; left: 2px; top: 2px;
  color: var(--text-faint); pointer-events: none; }
.mc-tok { display: inline-flex; align-items: center; gap: 4px; vertical-align: baseline;
  margin: 0 1px; padding: 0 7px 0 2px; border-radius: var(--r-pill); line-height: 22px;
  background: color-mix(in srgb, var(--c) 17%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 45%, transparent);
  color: var(--text); font-size: 13.5px; cursor: pointer; user-select: all; white-space: nowrap; }
.mc-tok img, .mc-tok-ph { width: 18px; height: 18px; border-radius: 50%; object-fit: cover;
  display: block; background: var(--surface-2); }
.mc-tok b { font-weight: 600; color: var(--c); }
.mc-tok-cat { font-style: normal; font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-muted); }
.mc-tok.gone { background: none; border-style: dashed; border-color: var(--border-strong); }
.mc-tok.gone b { color: var(--text-faint); }
.mc-tag { display: inline-block; margin: 0 1px; padding: 0 6px; border-radius: 6px; line-height: 21px;
  background: var(--accent-weak); color: #AFC0FF; font-size: 13.5px; font-weight: 600;
  white-space: nowrap; }

.mc-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding-top: 10px; border-top: 1px solid var(--border); }
.mc-pill { display: inline-flex; align-items: center; gap: 7px; height: 32px; padding: 0 12px;
  border-radius: var(--r-pill); border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); font: 600 12.5px var(--font-sans); cursor: pointer; min-width: 0;
  transition: border-color .15s; }
.mc-pill:hover { border-color: var(--accent-border); }
.mc-pill-k { font-family: var(--font-mono); font-size: 9.5px; font-weight: 400; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-faint); }
.mc-pill b { font-weight: 600; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-caret { font-size: 10px; color: var(--text-faint); }
/* The real select, dressed as the pill's value — it stays the control home.js drives. */
#mcModelPill .select { width: auto; max-width: 260px; min-width: 0; padding: 0 18px 0 0; border: 0;
  border-radius: 0; background-color: transparent; background-position: right 0 center;
  box-shadow: none; font: 600 12.5px var(--font-sans); color: var(--text); text-overflow: ellipsis;
  cursor: pointer; }
#mcModelPill .select:disabled { cursor: not-allowed; color: var(--text-muted); background-image: none; padding-right: 0; }
#mcModelPill:has(.select:disabled) { cursor: not-allowed; border-style: dashed; }
#mcModelPill:has(.select:disabled)::after { content: "set by style"; font-family: var(--font-mono);
  font-size: 9.5px; color: var(--text-faint); }
.mc-keys { margin-left: auto; font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faint); }

/* "Muse understood": quiet, under the card, and every part of it is the field it fills. */
/* min-width:0 because this is a grid item: without it the track takes this row's min-content —
   a nowrap chip's full text — and a long field drags the whole card, and the page, off screen. */
.mc-understood { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: -4px;
  min-width: 0; font-size: 12.5px; color: var(--text-muted); }
.mc-u-k { font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-faint); margin-right: 2px; }
.mc-u-sep { color: var(--text-faint); }
/* Wraps rather than ellipsises: "why it's worth buying" is the field that decides what the film
   shows, so a creator has to be able to read all of it. Needs its own min-width:0 — the old
   overflow:hidden was what used to flatten this button's automatic minimum size. The radius
   drops from a pill because a pill around four lines of text reads as a lozenge, not a chip. */
.mc-u-chip { min-width: 0; max-width: 100%; padding: 3px 10px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  font: 500 12.5px var(--font-sans); cursor: text; text-align: left;
  white-space: normal; overflow-wrap: anywhere; }
.mc-u-chip i { font-style: normal; color: var(--text-faint); }
.mc-u-chip:hover { border-color: var(--accent-border); }
.mc-u-chip.miss { border-style: dashed; border-color: rgba(224,169,58,.5); color: var(--warn); }
/* Optional and unanswered is not a problem, so it is not amber. */
.mc-u-chip.opt { border-style: dashed; color: var(--text-faint); }
.mc-u-chip .mc-u-in { width: 220px; max-width: 60vw; padding: 0; border: 0; background: none;
  box-shadow: none; font: inherit; color: var(--text); }

/* The @ / # menu. Fixed, so a scrolled column cannot clip it. */
.mc-pop { position: fixed; z-index: 1200; max-height: 300px; overflow-y: auto; padding: 6px;
  border-radius: 12px; border: 1px solid var(--border-strong); background: var(--surface);
  box-shadow: var(--shadow-pop); }
.mc-pop-h { padding: 4px 8px 6px; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-faint); }
.mc-pop-row { display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 8px;
  border: 0; border-radius: 8px; background: none; color: var(--text); font: 500 13px var(--font-sans);
  text-align: left; cursor: pointer; }
.mc-pop-row.on, .mc-pop-row:hover { background: var(--accent-weak); }
.mc-pop-row b { font-weight: 600; }
.mc-pop-th { flex: none; width: 30px; height: 30px; border-radius: 7px; overflow: hidden;
  border: 2px solid var(--c, var(--border)); background: var(--surface-2); }
.mc-pop-th img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mc-pop-k { margin-left: auto; font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mc-pop-row.off .mc-pop-k { color: var(--warn); }
.mc-pop-cur { color: var(--accent); font-size: 12px; }
.mc-pop-add { flex: none; width: 30px; height: 30px; border-radius: 7px; display: grid; place-items: center;
  border: 1.5px dashed var(--border-strong); color: var(--text-muted); }

/* WHAT THE BOX REPLACED, hidden and kept. These are the value stores the composer writes into
   (readConfig still reads every one of them), and the upload slots whose lists it fills — deleting
   them would take the save path and the launch upload with them. */
#briefCard .qrow[data-q="pfProduct"], #briefCard .qrow[data-q="pfProductPoints"],
#briefCard .qrow[data-q="pfAudience"], #briefCard .qrow[data-q="pfIdeaQuick"] { display: none !important; }
/* TODO(composer): the style's own questions come out of the box's text in a later pass. */
#briefCard #pfAsks { display: none !important; }
/* The rail keeps the style's film; its model row and upload slots are the box's now. The
   references dialog borrows the same panel (.in-modal) and still shows it there. */
.brief-side .ref-panel:not(.in-modal) { display: none !important; }
/* "0 of 3 answered" counted questions that are no longer on screen. */
.brief-side .brief-progress, .brief-side .brief-progress-txt { display: none !important; }
/* TEMPORARILY OFF: the per-slot ✨AI auto-fill, the "N in pool · N sent / N per run" counter and
   the "Every post" redraw toggle. The code behind them is untouched; a workspace that already
   has AI auto-fill saved keeps it. */
.anchor-ai, #anchorCount, #refRefresh { display: none !important; }

/* Desktop first; under 900px one column, the box above the film. The two-column rule above is
   written with :has(#briefRail…), whose id outranks the generic 900px .home-grid rule — which is
   why the phone layout stayed two 150px columns. */
@media (max-width: 900px) {
  .view-ask .home-grid:has(#briefRail:not(.hidden)) { grid-template-columns: minmax(0, 1fr); }
  .view-ask .home-grid:has(#briefRail:not(.hidden)) > *:not(#briefRail) { grid-column: 1; }
  #briefRail { grid-column: 1; grid-row: auto; order: 2; }
  .mc-keys { display: none; }
  .mc-att, .mc-att-img, .mc-att-add { width: 64px; }
  .mc-att-img, .mc-att-add { height: 64px; }
  .mc-edit { min-height: 96px; font-size: 16px; }   /* 16px: iOS zooms into anything smaller */
}

/* ============================== SKELETONS ============================== */
/* Every page that waits on data shows the SHAPE of what is coming — grey blocks the size of the
   real cards, rows and tables, with one soft light sweeping across them — instead of a spinner
   and a sentence. The page does not jump when the data lands, and it reads as "almost there"
   rather than "working on it". Built by core.js skeleton(kind, n). */
.skel {
  position: relative; overflow: hidden; pointer-events: none;
  background: var(--surface-2); border-radius: 12px;
}
.skel::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.045), transparent);
  animation: skelSweep 1.4s ease-in-out infinite;
}
@keyframes skelSweep { to { transform: translateX(100%); } }
.skel-wrap { grid-column: 1 / -1; display: grid; gap: 14px; }
.skel-wrap.clips { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }
.skel-wrap.tiles { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.skel-wrap.rows, .skel-wrap.table { gap: 8px; }
.skel-wrap.refs { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 10px; }
.skel.clip { aspect-ratio: 9 / 16; }
.skel.ref { aspect-ratio: 3 / 4; }
.skel.tile { min-height: 150px; border-radius: 14px; }
.skel.row { height: 64px; }
.skel.trow { height: 40px; border-radius: 8px; }
.skel.trow.head { height: 30px; opacity: .6; }
.skel.line { height: 12px; border-radius: 6px; }
/* Inside a card that is still decoding its first frame (Library thumbnails). */
.thumb-skel { position: absolute; inset: 0; border-radius: 0; background: var(--surface-2); }
@media (prefers-reduced-motion: reduce) { .skel::after { animation: none; } }

/* "Let Muse choose" — the first card on both style walls. No film to show, so an icon on the
   accent tint instead of the striped "no sample yet" panel, which read as a style that failed. */
.sty-auto-ico { display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--accent) 28%, transparent), color-mix(in srgb, var(--accent) 6%, transparent) 70%), var(--surface-2);
  color: var(--accent); }
.sty-auto-ico svg { width: 34%; max-width: 46px; height: auto; }
.sty-sthumb.sty-auto-ico svg { width: 55%; }
.ws-style-card.ws-auto .ws-style-shot { display: flex; align-items: center; justify-content: center; }

/* The Setup style wall's shelf filter — the Styles page's chips, smaller. */
/* The Setup wall's shelves — the same segmented look as the Styles page (.sty-seg). */
.sty-wchips { display: inline-flex; gap: 2px; margin-top: 12px; padding: 4px; border-radius: 12px; max-width: 100%;
  background: var(--surface); border: 1px solid var(--border); overflow-x: auto; scrollbar-width: none; }
.sty-wchips.hidden { display: none; }
.sty-wchips::-webkit-scrollbar { display: none; }
.sty-wtab { display: inline-flex; align-items: center; gap: 7px; padding: 7px 12px; border: 0; border-radius: 9px;
  background: none; color: var(--text-muted); font: 600 13px var(--font-sans); white-space: nowrap; cursor: pointer;
  transition: color .15s, background .15s; }
.sty-wtab em { font-style: normal; font-size: 11px; font-weight: 600; min-width: 18px; padding: 1px 6px; border-radius: 999px;
  text-align: center; color: var(--text-faint); background: rgba(255,255,255,.05); }
.sty-wtab:hover { color: var(--text); }
.sty-wtab.on { color: var(--text); background: var(--sidebar-raised); box-shadow: inset 0 0 0 1px var(--border-strong); }
.sty-wtab.on em { color: var(--on-accent); background: var(--accent); }
.sty-wtab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* STORY ANGLE IS HIDDEN (owner, 2026-10-10: "should be totally hide first"). A style writes the
   film; the angle only matters when no style fits the product, and then the backend writes one
   on its own (scheduler: "story (written for this run)"). The markup stays for that fallback. */
#angleCard, #angleDrawer, #angleTab { display: none !important; }

/* The workspace chip stops short of the top-right action column. */
.lib-overlay .lib-ws { max-width: calc(100% - 40px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- Styles page: admin arrange + edit (styles.js) ---- */
.sty-grid.arranging .sty-card { cursor: grab; outline: 1px dashed var(--border-strong); outline-offset: 3px; }
.sty-grid.arranging .sty-card:hover { transform: none; }
.sty-grid.arranging .sty-card.dragging { opacity: .4; cursor: grabbing; }
.sty-grid.arranging .sty-card.drop-to { outline: 2px solid var(--accent); }
.sty-move { position: absolute; top: 8px; left: 8px; right: 8px; z-index: 3; display: flex;
            align-items: center; justify-content: space-between; pointer-events: none; }
.sty-move button { pointer-events: auto; width: 32px; height: 32px; border-radius: 50%; border: 0;
                   background: rgba(0,0,0,.6); color: #fff; font-size: 15px; cursor: pointer;
                   backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.sty-move button:hover { background: var(--accent); }
.sty-move span { min-width: 28px; height: 24px; padding: 0 8px; border-radius: 999px; display: grid;
                 place-items: center; background: rgba(0,0,0,.6); color: #fff; font-size: 12px; font-weight: 600; }
.sty-ed { width: 100%; box-sizing: border-box; font: inherit; color: var(--text); background: var(--surface-2);
          border: 1px solid var(--border-strong); border-radius: 10px; padding: 8px 10px; resize: vertical; }
.sty-ed:focus { outline: none; border-color: var(--accent); }
input.sty-ed { font-family: var(--font-display); font-weight: 800; font-size: 1.2rem; }

/* ---- Library: the clip an email linked to (library.js focusClip) ---- */
.lib-card.lib-focus { position: relative; z-index: 2; border-color: var(--accent) !important;
  box-shadow: 0 0 0 2px var(--accent), 0 0 28px 4px color-mix(in srgb, var(--accent) 55%, transparent);
  animation: lib-focus-glow 1.6s ease-in-out infinite; }
@keyframes lib-focus-glow {
  0%, 100% { box-shadow: 0 0 0 2px var(--accent), 0 0 18px 2px color-mix(in srgb, var(--accent) 40%, transparent); }
  50%      { box-shadow: 0 0 0 2px var(--accent), 0 0 36px 8px color-mix(in srgb, var(--accent) 70%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .lib-card.lib-focus { animation: none; } }

/* ---- workspace view: a drama's episodes (wsview.js briefPage) ---- */
.wsv-eps { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.wsv-ep { display: flex; gap: 12px; align-items: flex-start; padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--border); }
.wsv-ep-n { flex: none; min-width: 44px; padding: 2px 8px; border-radius: 999px; text-align: center;
  font-size: 11.5px; font-weight: 650; color: var(--text-muted); background: rgba(255,255,255,.05); }
.wsv-ep:first-child .wsv-ep-n { color: var(--on-accent); background: var(--accent); }
.wsv-ep-t { display: grid; gap: 2px; min-width: 0; }
.wsv-ep-t b { font-size: 14px; font-weight: 650; color: var(--text); }
.wsv-ep-t i { font-style: normal; font-size: 12.5px; line-height: 1.5; color: var(--text-muted); }

/* ---- workspace view: image numbers that match the sentence's @image chips ---- */
.wsv-block { --mc-c0:#7C93FF; --mc-c1:#3CC9A4; --mc-c2:#E6B04B; --mc-c3:#D883E6;
  --mc-c4:#5CC3E8; --mc-c5:#EE8F6A; --mc-c6:#A3C95A; --mc-c7:#B79CFF; }
.wsv-ref[style*="--c"] img { box-shadow: 0 0 0 2px color-mix(in srgb, var(--c) 70%, transparent); }
.wsv-ref figcaption b { color: var(--c, var(--text-muted)); text-transform: none; letter-spacing: 0;
  font-size: 12px; font-weight: 650; }
.wsv-story { line-height: 1.9; }
.wsv-story .mc-tok { cursor: default; user-select: text; vertical-align: middle; }
.wsv-eps-more { margin-top: 6px; }
.wsv-eps-more > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface-2);
  color: var(--text-muted); font-size: 12.5px; font-weight: 600; }
.wsv-eps-more > summary::-webkit-details-marker { display: none; }
.wsv-eps-more > summary::before { content: "▸"; transition: transform .15s; }
.wsv-eps-more[open] > summary::before { transform: rotate(90deg); }
.wsv-eps-more > summary:hover { color: var(--text); border-color: var(--border-strong); }
.wsv-eps-more > .wsv-eps { margin-top: 6px; }
.wsv-eps-more .wsv-ep:first-child .wsv-ep-n { color: var(--text-muted); background: rgba(255,255,255,.05); }
.cfg-season { margin-left: 8px; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--accent-border);
  background: var(--accent-weak); color: #B9C6FF; font: 600 12px var(--font-sans); cursor: pointer;
  transition: background .15s, color .15s; }
.cfg-season:hover { background: var(--accent); color: var(--on-accent); }
.cfg-season:disabled { opacity: .5; cursor: default; }
.wsv-ref img, .wsv-story .mc-tok img { cursor: zoom-in; transition: transform .15s; }
.wsv-ref img:hover { transform: scale(1.04); }

/* ---- workspace view: episodes clamp, the same pattern as Home's "View all N workspaces" ---- */
.wsv-eps-wrap { position: relative; }
.wsv-eps-wrap.is-clamped .wsv-ep-extra { display: none; }
.wsv-eps-wrap.is-clamped { padding-bottom: 8px; }
.wsv-eps-wrap.is-clamped .wsv-ep-fade {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 95%);
  mask-image: linear-gradient(to bottom, #000 0%, transparent 95%); }
.wsv-eps-all { display: block; margin: 10px auto 0; padding: 11px 22px; border: 0; border-radius: 999px;
  background: var(--bg); box-shadow: 0 6px 24px rgba(0,0,0,.5); color: var(--text);
  font: inherit; font-size: .9rem; font-weight: 600; cursor: pointer; white-space: nowrap; }
.wsv-eps-wrap.is-clamped .wsv-eps-all { position: absolute; left: 50%; bottom: 22px;
  transform: translate(-50%, 50%); margin: 0; z-index: 2; }
.wsv-eps-all:hover { background: var(--surface-2); }
.wsv-eps-all:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- workspace view: an episode, opened (wsview.js episodeHtml) ---- */
.wsv-ep[data-ep] { cursor: pointer; transition: border-color .15s, background .15s; }
.wsv-ep[data-ep]:hover { border-color: var(--border-strong); background: color-mix(in srgb, var(--surface-2) 70%, var(--accent-weak)); }
.wsv-ep[data-ep]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.wsv-ep-go { margin-left: auto; align-self: center; font-size: 20px; line-height: 1; color: var(--text-faint);
  transition: transform .15s, color .15s; }
.wsv-ep[data-ep]:hover .wsv-ep-go { color: var(--text); transform: translateX(2px); }
.wsv-epv { display: grid; gap: 14px; }
.wsv-epv-back { justify-self: start; border: 0; background: none; padding: 4px 0; color: var(--text-muted);
  font: 600 13px var(--font-sans); cursor: pointer; }
.wsv-epv-back:hover { color: var(--text); }
.wsv-epv-head { display: flex; align-items: center; gap: 12px; }
.wsv-epv-head .wsv-ep-n { color: var(--on-accent); background: var(--accent); }
.wsv-epv-head h3 { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 800; letter-spacing: -.02em; }
.wsv-epv-sum { margin: 0; font-size: 14px; line-height: 1.65; color: var(--text-muted); }
.wsv-epv-end { padding: 12px 14px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border); }
.wsv-epv-end span { display: block; font-size: 10.5px; font-weight: 650; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 4px; }
.wsv-epv-end p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--text); }
.wsv-epv-k { margin: 6px 0 0; font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); }
.wsv-takes { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; counter-reset: take; }
.wsv-take { padding: 14px; border-radius: 14px; border: 1px solid var(--border); background: var(--surface-2); display: grid; gap: 10px; }
.wsv-take-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.wsv-take-h b { font-size: 13px; font-weight: 700; color: var(--text); }
.wsv-take-h span { font-family: "Space Mono", ui-monospace, monospace; font-size: 11px; color: var(--text-faint); }
.wsv-take-h em { font-style: normal; font-size: 11.5px; font-weight: 600; letter-spacing: .04em; color: #B9C6FF;
  padding: 2px 8px; border-radius: 999px; background: color-mix(in srgb, var(--accent) 12%, transparent); }
.wsv-cuts { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.wsv-cuts li { display: grid; grid-template-columns: 52px 1fr; gap: 10px; font-size: 13px; line-height: 1.6; color: var(--text-muted); }
.wsv-tc { font-family: "Space Mono", ui-monospace, monospace; font-size: 10.5px; color: var(--text-faint); padding-top: 3px; }
.wsv-lines { display: grid; gap: 6px; padding-top: 10px; border-top: 1px dashed var(--border); }
.wsv-say { margin: 0; display: flex; gap: 10px; align-items: baseline; font-size: 14.5px; line-height: 1.55; }
.wsv-say b { flex: none; min-width: 52px; font-size: 11px; font-weight: 700; letter-spacing: .05em; color: var(--accent); }
.wsv-say span { color: var(--text); }
.wsv-epv-watch { justify-self: start; display: inline-flex; align-items: center; gap: 8px; height: 44px; padding: 0 18px;
  border: 0; border-radius: 12px; background: var(--accent); color: var(--on-accent); font: 650 14px var(--font-sans); cursor: pointer;
  box-shadow: 0 8px 22px -8px color-mix(in srgb, var(--accent) 70%, transparent); }
.wsv-epv-watch:hover { background: color-mix(in srgb, var(--accent) 88%, #fff); }
.wsv-epv-watch:active { transform: scale(.98); }
@media (max-width: 600px) { .wsv-cuts li { grid-template-columns: 1fr; gap: 2px; } }

/* ---- clip settings: every shot's prompt (core.js loadShotPrompts) ---- */
.clip-shot-p { border-top: 1px solid var(--border); padding: 6px 0; }
.clip-shot-p > summary { cursor: pointer; font-size: 12px; font-weight: 650; color: var(--text-muted); }
.clip-shot-p[open] > summary { color: var(--text); }
.wsv-say span i { font-style: normal; font-size: 12px; color: var(--text-faint); }

/* ==========================================================================================
   CREDITS + TOP UP (topup.js), after Theater's /payment (owner, 2026-10-12): the balance and what
   it covers, then one card per tier with its own Pay button. Muse's blue where Theater has red.
   ========================================================================================== */
.view-credits > h1 { margin-bottom: 4px; }
.cr-sub { margin: 0 0 18px; font-size: 14px; font-weight: 500; color: var(--text-muted); }
.view-credits .cr-hero { position: relative; overflow: hidden; align-items: flex-end; padding: 28px 30px; border-radius: 24px;
  background: radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--accent) 22%, transparent), color-mix(in srgb, var(--accent) 0%, transparent) 55%),
              radial-gradient(1px 1px at 1px 1px, rgba(255,255,255,.06) 1px, transparent 0) 0 0 / 14px 14px, #13141c;
  border: 1px solid rgba(255,255,255,.07); }
.view-credits .cr-kicker { display: inline-block; padding: 3px 9px; border-radius: 4px; transform: skewX(-8deg);
  background: rgba(255,255,255,.1); color: var(--text-muted); font-size: 11px; letter-spacing: .06em; }
.view-credits .cr-bal span { font-family: var(--font-display); font-size: 56px; font-weight: 800; line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.cr-cap { margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 6px 18px; font-size: 14px; color: var(--text-muted); }
.cr-cap span { display: inline-flex; align-items: center; gap: 6px; }
.cr-cap svg { width: 16px; height: 16px; }
.view-credits .cr-topup { display: inline-flex; align-items: center; gap: 8px; height: 46px; padding: 0 20px; border-radius: 12px;
  background: #F4F5FA; color: #0E0F14; font: 700 14.5px var(--font-sans); box-shadow: 0 8px 22px -10px rgba(0,0,0,.8); }
.view-credits .cr-topup svg { width: 16px; height: 16px; }

.tp { margin: 34px 0 30px; scroll-margin-top: 70px; }
.tp-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px 24px; flex-wrap: wrap; margin-bottom: 18px; }
.tp-head h2 { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 700; letter-spacing: -.02em; }
.tp-head p { margin: 6px 0 0; font-size: 14px; font-weight: 500; color: var(--text-muted); }
.tp-secure { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-size: 12.5px; font-weight: 500; color: var(--text-faint); }
.tp-secure svg { width: 14px; height: 14px; }
.tp-grid { display: grid; gap: 16px; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tp-card { position: relative; display: flex; flex-direction: column; gap: 12px; padding: 16px 16px 0; border-radius: 20px; cursor: default;
  background: #15151b; border: 1px solid rgba(255,255,255,.06); transition: transform .3s ease, border-color .2s; outline: none; }
.tp-card:hover { transform: translateY(-2px); }
.tp-card.tone-bonus { background: linear-gradient(225deg, color-mix(in srgb, var(--accent) 14%, transparent), color-mix(in srgb, var(--accent) 4%, transparent) 30%, color-mix(in srgb, var(--accent) 0%, transparent) 62%), #15151b; }
.tp-card.tone-best { background: linear-gradient(225deg, color-mix(in srgb, var(--accent) 24%, transparent), color-mix(in srgb, var(--accent) 7%, transparent) 35%, color-mix(in srgb, var(--accent) 0%, transparent) 66%), #15151b;
  border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.tp-top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-height: 28px; }
.tp-cred { margin: 0 4px 0 0; font-size: 14px; font-weight: 500; color: var(--text-muted); }
.tp-cred b { font-family: var(--font-display); font-size: 26px; font-weight: 800; letter-spacing: -.04em; color: var(--text);
  font-variant-numeric: tabular-nums; }
.tp-chip { display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px; border-radius: 4px; transform: skewX(-8deg);
  font-size: 11px; font-weight: 800; letter-spacing: .03em; text-transform: uppercase; }
.tp-chip svg { width: 10px; height: 10px; }
.tp-chip.brand { background: var(--accent); color: var(--on-accent); }
.tp-chip.light { background: #F4F5FA; color: #0E0F14; }
.tp-rate { margin: 0; font-size: 12.5px; color: var(--text-faint); }
.tp-covers { display: grid; gap: 5px; padding: 12px; border-radius: 12px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.05); }
.tp-covers p { margin: 0; display: flex; align-items: center; gap: 7px; padding-left: 24px; font-size: 12.5px; font-weight: 500; color: var(--text-muted); }
.tp-covers p svg { width: 14px; height: 14px; color: var(--text-faint); }
.tp-covers .tp-covers-h { padding-left: 0; font-size: 14px; font-weight: 650; color: var(--text); }
.tp-covers .tp-covers-h svg { width: 16px; height: 16px; color: var(--text-muted); }
.tp-price { margin: auto 0 0; display: flex; align-items: flex-end; gap: 6px; }
.tp-price b { font-family: var(--font-display); font-size: 28px; font-weight: 800; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.tp-price span { padding-bottom: 4px; font-size: 12px; color: var(--text-faint); }
.tp-buy { margin: 0 -4px 12px; border-radius: 14px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.05); }
.tp-buy p { margin: 0; height: 32px; display: grid; place-items: center; font-size: 12px; color: var(--text-faint); }
.tp-pay { width: 100%; height: 48px; border: 0; border-radius: 12px; font: 700 15px var(--font-sans); cursor: pointer;
  transition: filter .15s, transform .15s; }
.tp-pay.light { background: #F4F5FA; color: #0E0F14; }
.tp-pay.brand { background: var(--accent); color: var(--on-accent); box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--accent) 90%, transparent); }
.tp-pay:hover:not(:disabled) { filter: brightness(1.08); }
.tp-pay:active:not(:disabled) { transform: scale(.98); }
.tp-pay:disabled, .tp-pay.busy { opacity: .6; }
.tp-bar { display: none; }

/* How would you like to pay? (in the shared modal) */
.tp-dlg { display: grid; gap: 12px; }
.tp-dlg h3 { margin: 0; font-family: var(--font-display); font-size: 22px; font-weight: 800; letter-spacing: -.02em; }
.tp-dlg > p { margin: 0; }
.tp-methods { display: grid; gap: 8px; margin-top: 4px; }
.tp-method { display: flex; align-items: center; gap: 12px; width: 100%; padding: 14px 16px; border-radius: 14px; text-align: left; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text); font: inherit; transition: border-color .15s, background .15s; }
.tp-method:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface-2)); }
.tp-method > span { display: grid; gap: 2px; flex: 1; min-width: 0; }
.tp-method b { font-size: 15px; font-weight: 700; }
.tp-method small { font-size: 12px; color: var(--text-faint); }
.tp-method em { font-style: normal; font-family: var(--font-display); font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.tp-method svg { width: 16px; height: 16px; color: var(--text-faint); flex: none; }
.tp-method.busy { opacity: .6; pointer-events: none; }
.tp-dlg .tp-secure { justify-content: center; margin-top: 2px; }

@media (max-width: 1100px) { .tp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* PHONE: a pick list paid from one sticky bar, as Theater does. */
@media (max-width: 760px) {
  .view-credits .cr-hero { flex-direction: column; align-items: stretch; padding: 22px 18px; }
  .view-credits .cr-bal span { font-size: 44px; }
  .view-credits .cr-topup { justify-content: center; }
  .tp-grid { grid-template-columns: 1fr; gap: 10px; }
  .tp-card { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 10px; padding: 14px 16px; border-radius: 18px; cursor: pointer; }
  .tp-card:hover { transform: none; }
  .tp-card.on { border-color: rgba(255,255,255,.35); }
  .tp-card .tp-covers, .tp-card .tp-buy { display: none; }
  .tp-card .tp-top { flex: 1 1 auto; min-height: 0; }
  .tp-card .tp-rate { flex-basis: 100%; order: 3; }
  .tp-card .tp-price { margin: 0; }
  .tp-card .tp-price span { display: none; }
  .tp-bar { position: sticky; bottom: calc(76px + env(safe-area-inset-bottom)); z-index: 5; display: flex; align-items: center;
    gap: 12px; margin-top: 12px; padding: 12px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border-strong);
    box-shadow: 0 -10px 30px -12px rgba(0,0,0,.8); }
  .tp-bar span { flex: 1; font-size: 13px; color: var(--text-muted); }
  .tp-bar span b { font-family: var(--font-display); font-size: 18px; color: var(--text); }
  .tp-bar .tp-pay { width: auto; padding: 0 22px; }
}
@media (prefers-reduced-motion: reduce) { .tp-card, .tp-pay { transition: none; } }
.tp-chip { flex: none; width: auto; }
.tp-pay { display: flex; align-items: center; justify-content: center; text-align: center; }
.tp-dlg { padding: 26px 24px 20px; min-width: min(460px, calc(100vw - 48px)); }
.tp-dlg h3 { padding-right: 36px; }
.tp-pay { padding: 0 16px; line-height: 1; }

/* ---- Credits: balance and its last 30 days side by side (credits.js renderUseCard) ---- */
.cr-top { display: grid; grid-template-columns: minmax(0, 3fr) minmax(260px, 2fr); gap: 16px; align-items: stretch; }
.cr-top .cr-hero { margin: 0; }
.cr-use { display: flex; flex-direction: column; gap: 6px; padding: 24px 24px 18px; border-radius: 24px;
  background: #15151b; border: 1px solid rgba(255,255,255,.07); }
.cr-use .cr-kicker { align-self: flex-start; }
.cu-row { display: flex; align-items: flex-end; gap: 14px; margin-top: 6px; }
.cu-used { margin: 0; flex: none; font-size: 14px; color: var(--text-muted); }
.cu-used b { font-family: var(--font-display); font-size: 34px; font-weight: 800; letter-spacing: -.03em; color: var(--text);
  font-variant-numeric: tabular-nums; }
.cu-spark { flex: 1; min-width: 0; height: 44px; }
.cu-spark svg { width: 100%; height: 100%; display: block; }
.cu-meta { margin: 0; font-size: 13.5px; color: var(--text-muted); }
.cu-last { margin: 2px 0 0; font-size: 14px; font-weight: 650; color: #3CC9A4; }
.cu-last.short { color: var(--err, #ff5d6c); }
.cu-more { margin-top: auto; align-self: flex-start; padding: 6px 0 0; border: 0; background: none; cursor: pointer;
  font: 600 13px var(--font-sans); color: var(--text-muted); }
.cu-more:hover { color: var(--text); }
#credHistoryPane .cr-grid { margin-bottom: 16px; }
@media (max-width: 900px) { .cr-top { grid-template-columns: 1fr; } }

/* ---- Model picker (home.js paintModelPicker), after Theater's: grouped by provider ---- */
#mcModelPill.mp-on { position: relative; padding: 0; border: 0; background: none; height: auto; cursor: default; }
#mcModelPill.mp-on > .mc-pill-k, #mcModelPill.mp-on > .select { display: none; }
#mcModelPill.mp-on::after { content: none !important; }
.mp-trigger { display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px 0 8px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text); cursor: pointer; max-width: 320px;
  font: 600 12.5px var(--font-sans); transition: border-color .15s; }
.mp-trigger:hover:not(:disabled) { border-color: var(--accent-border); }
.mp-trigger[aria-expanded="true"] { border-color: var(--accent); }
.mp-trigger:disabled { cursor: not-allowed; border-style: dashed; color: var(--text-muted); }
.mp-trigger .mp-ico { width: 20px; height: 20px; }
.mp-trigger .mp-txt { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.mp-k { font-family: var(--font-mono); font-size: 9.5px; font-weight: 400; letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); }
.mp-trigger b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.mp-ico { flex: none; display: grid; place-items: center; }
.mp-ico svg, .mp-ico .engine-ico { width: 18px; height: 18px; }
.mp-pop { position: absolute; left: 0; top: calc(100% + 8px); z-index: 60; width: 300px; max-height: 380px; overflow-y: auto;
  padding: 6px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border-strong);
  box-shadow: 0 24px 60px -18px rgba(0,0,0,.85); }
.mp-pop.hidden { display: none; }
.mp-group { margin: 10px 10px 4px; font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); }
.mp-group:first-child { margin-top: 6px; }
.mp-row { display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 10px; border: 0; border-radius: 12px;
  background: none; color: var(--text); text-align: left; cursor: pointer; font: inherit; transition: background .12s; }
.mp-row:hover { background: rgba(255,255,255,.05); }
.mp-row.on { background: var(--accent-weak); }
.mp-row .mp-ico { width: 38px; height: 38px; border-radius: 10px; background: rgba(255,255,255,.06); }
.mp-row .mp-ico svg, .mp-row .mp-ico .engine-ico { width: 20px; height: 20px; }
.mp-row .mp-txt { flex: 1; min-width: 0; }
.mp-row b { font-size: 14px; font-weight: 650; }
.mp-check { color: var(--accent); font-weight: 700; }
@media (max-width: 760px) { .mp-pop { width: min(300px, calc(100vw - 48px)); } .mp-trigger { max-width: 220px; } }
.mp-row b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-check { flex: none; width: 16px; text-align: center; }
.mp-pop { width: 360px; }
@media (max-width: 760px) { .mp-pop { width: min(360px, calc(100vw - 32px)); } }
/* Fixed to the viewport by home.js placeModelPop, above the Next bar (z 40). */
.mp-pop { z-index: 130; }

/* ---- Out of credits (credits.js outOfCreditsModal) --------------------------------------------
   Balance against the price of one clip, the gap between them, and which workspaces stopped —
   the three facts the person needs before deciding to top up. */
.modal-card:has(.ooc) { max-width: 440px; }
.modal-card:has(.ooc) .modal-close { display: none; }
.ooc { padding: 26px 26px 22px; }
.ooc-head { display: flex; gap: 14px; align-items: center; margin-bottom: 20px; }
.ooc-ico {
  flex: none; width: 40px; height: 40px; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--warn-weak); color: var(--warn);
}
.ooc-ico svg { width: 22px; height: 22px; }
.ooc-head h3 { margin: 0; font-family: var(--font-display); font-size: 1.2rem; font-weight: 650; color: var(--text); }
.ooc-k { display: block; font-family: var(--font-mono); font-size: .66rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 4px; }
.ooc-meter { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md); padding: 14px 16px; }
.ooc-nums { display: flex; justify-content: space-between; }
.ooc-nums .r { text-align: right; }
.ooc-nums b { font-family: var(--font-display); font-size: 1.5rem; font-weight: 650; color: var(--text); font-variant-numeric: tabular-nums; }
.ooc-nums div:first-child b { color: var(--warn); }
.ooc-bar { height: 6px; border-radius: var(--r-pill); background: var(--border-strong); margin: 12px 0 10px; overflow: hidden; }
.ooc-bar i { display: block; height: 100%; border-radius: inherit; background: var(--warn); }
.ooc-short { font-size: .84rem; color: var(--text-muted); }
.ooc-short b { color: var(--text); font-weight: 600; }
.ooc-paused { margin-top: 16px; }
.ooc-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ooc-chip {
  font-size: .82rem; padding: 4px 10px; border-radius: var(--r-pill);
  background: var(--sidebar-raised); border: 1px solid var(--border); color: var(--text);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ooc-acts { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }
.ooc-acts .btn-ghost, .ooc-acts .btn-neon { padding: 10px 18px; }
@media (max-width: 480px) {
  .ooc { padding: 22px 18px 18px; }
  .ooc-acts { flex-direction: column-reverse; }
  .ooc-acts button { width: 100%; }
}

/* Admin → Running: PostFast account slots (admin.js loadSlots) */
.slot-meter { display: flex; align-items: center; gap: 12px; margin: 6px 0 12px; color: var(--text-muted); }
.slot-bar { flex: 1; max-width: 320px; height: 6px; border-radius: var(--r-pill); background: var(--border-strong); overflow: hidden; }
.slot-bar i { display: block; height: 100%; border-radius: inherit; background: var(--accent); }
.slot-meter.low .slot-bar i { background: var(--warn); }
.slot-meter.low { color: var(--warn); }
.slot-meter.full .slot-bar i { background: var(--danger); }
.slot-meter.full { color: var(--danger); }

/* ---- Admin → Dashboard / Videos / Worker (web/js/adminops.js) ------------------------------- */
/* Page header for every Admin page (admin.js paintAdminHead): eyebrow, title, one line. */
.view-admin > h1, .view-admin .admin-sections, .view-admin #admOpsTabs { display: none !important; }
.adm-head { padding-bottom: 20px; margin-bottom: 22px; border-bottom: 1px solid var(--border); }
.adm-eyebrow { display: block; font-family: var(--font-mono); font-size: .7rem; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); margin-bottom: 8px; }
.adm-head h1 { margin: 0; font-family: var(--font-display); font-size: clamp(1.8rem, 3.2vw, 2.5rem); font-weight: 700; letter-spacing: -.02em; line-height: 1.1; color: var(--text); }
.adm-head p { margin: 8px 0 0; font-size: .98rem; color: var(--text-muted); max-width: 70ch; }
.view-admin .adm-dup { display: none; }
.view-admin .admin-pane > .ap-head:first-child:has(> .adm-dup:only-child) { display: none; }
/* Sidebar: Admin entries are a denser list than the everyday pages. */
.nav-item.nav-sub { padding: 8px 12px; font-size: .88rem; }
.nav { overflow-y: auto; min-height: 0; scrollbar-width: none; }
.nav::-webkit-scrollbar { display: none; }

/* Stat cards and panels (after Theater's admin) */
.ao-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
.ao-top { margin: 0 0 14px; }
.ao-st { margin-bottom: 18px; }
.ao-tile { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 16px 18px; min-width: 0; }
.ao-panel .ao-tile { background: var(--surface-2); border-radius: var(--r-md); padding: 14px 16px; }
.ao-tt-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.ao-k { font-size: .82rem; color: var(--text-muted); }
.ao-ic { flex: none; width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; background: var(--sidebar-raised); color: var(--text-muted); }
.ao-ic svg { width: 18px; height: 18px; }
.ao-tile.hi .ao-ic, .ao-tile.info .ao-ic { background: var(--accent-weak); color: var(--accent); }
.ao-tile.ok .ao-ic { background: var(--ok-weak); color: var(--ok); }
.ao-tile.bad .ao-ic { background: var(--danger-weak); color: var(--danger); }
.ao-tile.warn .ao-ic { background: var(--warn-weak); color: var(--warn); }
.ao-tile.brain .ao-ic { background: var(--brain-weak); color: var(--brain); }
.ao-tile.hi { border-color: var(--accent-border); background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 9%, var(--surface)), var(--surface)); }
.ao-tile b { display: block; font-family: var(--font-display); font-size: 2rem; font-weight: 700; letter-spacing: -.02em; line-height: 1.1; color: var(--text); font-variant-numeric: tabular-nums; margin-top: 6px; }
.ao-panel .ao-tile b { font-size: 1.6rem; }
.ao-tile.bad b { color: var(--danger); }
.ao-sub { display: block; margin-top: 6px; font-size: .8rem; color: var(--text-faint); }
.ao-sub .ok, td.ok { color: var(--ok); }
.ao-sub .bad, td.bad { color: var(--danger); }
td.warn { color: var(--warn); }
.ao-panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: 14px; margin-bottom: 14px; }
.ao-panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); margin-bottom: 14px; min-width: 0; overflow: hidden; }
.ao-panels .ao-panel { margin-bottom: 0; }
.ao-ph { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--border); background: color-mix(in srgb, var(--surface-2) 60%, var(--surface)); }
.ao-pic { flex: none; width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; background: var(--accent-weak); color: var(--accent); }
.ao-pic svg { width: 18px; height: 18px; }
.ao-pt { flex: 1; min-width: 0; }
.ao-pt h3 { margin: 0; font-family: var(--font-display); font-size: 1.05rem; font-weight: 650; color: var(--text); }
.ao-pt p { margin: 2px 0 0; font-size: .8rem; color: var(--text-muted); }
.ao-pb { padding: 16px 18px; }
.ao-seg { display: inline-flex; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-pill); padding: 2px; }
.ao-seg button { border: 0; background: none; color: var(--text-muted); font-size: .76rem; padding: 4px 10px; border-radius: var(--r-pill); cursor: pointer; }
.ao-seg button.on { background: var(--accent-weak); color: var(--text); }
.ao-rank { margin: 0; padding: 0; list-style: none; }
.ao-rank li { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.ao-rank li:last-child { border-bottom: 0; }
.ao-rk { flex: none; width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; background: var(--surface-2); font-size: .78rem; font-weight: 700; color: var(--text-muted); }
.ao-rank li:first-child .ao-rk { background: var(--accent-weak); color: var(--accent); }
.ao-rn { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ao-rn b { font-weight: 600; font-size: .9rem; }
.ao-rn .small, .ao-rv .small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ao-rv { text-align: right; display: flex; flex-direction: column; }
.ao-rv b { font-variant-numeric: tabular-nums; font-size: .95rem; }
.ao-pill { display: inline-block; font-size: .7rem; font-weight: 600; padding: 2px 8px; border-radius: var(--r-pill); white-space: nowrap; }
.ao-pill.ok { background: var(--ok-weak); color: var(--ok); }
.ao-pill.bad { background: var(--danger-weak); color: var(--danger); }
.ao-pill.info { background: var(--accent-weak); color: var(--accent); }
.ao-pill.mute { background: var(--sidebar-raised); color: var(--text-muted); }
/* videos */
.ao-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 10px 0 14px; }
.ao-filters .select { width: auto; min-width: 0; }
.ao-filters #avQ { flex: 1 1 240px; }
.ao-filters #avView { margin-left: auto; }
.ao-scroll { overflow-x: auto; }
.ao-vt tr[data-job] { cursor: pointer; }
.ao-vt tr[data-job]:hover td { background: var(--surface-2); }
.ao-tt { width: 76px; }
.ao-tt img, .ao-noth { display: grid; place-items: center; width: 64px; height: 40px; object-fit: cover; border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-faint); }
.ao-pr { max-width: 340px; }
.ao-cp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ao-pr .ao-err { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
#avModel, #avUser { max-width: 220px; }
.ao-err { display: block; color: var(--danger); font-size: .74rem; margin-top: 2px; }
.ao-dl { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-sm); border: 1px solid var(--border); color: var(--text-muted); text-decoration: none; }
.ao-dl:hover { color: var(--text); border-color: var(--accent); }
.ao-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.ao-card { display: flex; flex-direction: column; gap: 6px; text-align: left; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); padding: 8px; cursor: pointer; color: var(--text); font: inherit; font-size: .84rem; }
.ao-card:hover { border-color: var(--accent-border); }
.ao-th { position: relative; aspect-ratio: 9 / 16; max-height: 260px; border-radius: var(--r-sm); overflow: hidden; background: var(--surface-2); display: grid; place-items: center; }
.ao-th img { width: 100%; height: 100%; object-fit: cover; }
.ao-th .ao-pill { position: absolute; top: 6px; left: 6px; }
.ao-len { position: absolute; bottom: 6px; right: 6px; font-size: .7rem; padding: 1px 6px; border-radius: var(--r-pill); background: rgba(0,0,0,.6); color: #fff; }
.ao-pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin: 14px 0; }
/* video modal */
.modal-card:has(.ao-vd) { max-width: 720px; }
.ao-vd { padding: 22px; }
.ao-vh { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; padding-right: 36px; }
.ao-vh h3 { margin: 0; font-size: 1.05rem; }
.ao-vh code { margin-left: auto; }
.ao-player { display: block; width: 100%; max-height: 62vh; background: #000; border-radius: var(--r-md); }
.ao-novid { display: grid; place-items: center; height: 140px; border-radius: var(--r-md); background: var(--surface-2); color: var(--text-muted); }
.ao-errbox { margin-top: 12px; padding: 10px 12px; border-radius: var(--r-md); background: var(--danger-weak); color: var(--danger); }
.ao-errbox pre { margin: 4px 0 0; white-space: pre-wrap; word-break: break-word; font-size: .8rem; }
.ao-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px 16px; margin: 16px 0; }
.ao-facts dt { font-size: .72rem; color: var(--text-faint); }
.ao-facts dd { margin: 2px 0 0; font-size: .86rem; color: var(--text); word-break: break-word; }
.ao-vd h4 { margin: 14px 0 6px; font-size: .78rem; color: var(--text-muted); font-weight: 600; text-transform: uppercase; letter-spacing: .05em; }
.ao-text { margin: 0; font-size: .86rem; line-height: 1.5; white-space: pre-wrap; color: var(--text); }
.ao-refs { display: flex; flex-wrap: wrap; gap: 8px; }
.ao-refs img { width: 72px; height: 72px; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--border); }
.ao-shots { margin: 0; padding-left: 20px; font-size: .82rem; line-height: 1.5; color: var(--text); }
.ao-shots li { margin-bottom: 6px; }
.ao-acts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.ao-acts a { text-decoration: none; }
/* worker */
.ao-worker { display: flex; align-items: center; gap: 16px; padding: 18px 20px; margin-bottom: 14px; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); }
.ao-wic { position: relative; flex: none; width: 48px; height: 48px; border-radius: 12px; display: grid; place-items: center; background: var(--surface-2); color: var(--text-muted); }
.ao-wic svg { width: 24px; height: 24px; }
.ao-wic .ao-dot { position: absolute; top: -3px; right: -3px; border: 2px solid var(--surface); }
.ao-worker.down { border-color: color-mix(in srgb, var(--danger) 50%, var(--border)); }
.ao-worker.busy { border-color: var(--accent-border); }
.ao-dot { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--text-faint); }
.ao-worker.busy .ao-dot { background: var(--ok); box-shadow: 0 0 0 4px var(--ok-weak); }
.ao-worker.idle .ao-dot { background: var(--ok); }
.ao-worker.down .ao-dot { background: var(--danger); box-shadow: 0 0 0 4px var(--danger-weak); }
.ao-wmain { flex: 1; min-width: 0; }
.ao-wmain b { font-family: var(--font-display); font-size: 1.15rem; }
.ao-wmain .muted { margin-top: 4px; }
.btn-ghost.danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 50%, var(--border)); }
.ao-mt { margin-top: 10px; }
.ao-meter { display: block; height: 6px; margin-top: 8px; border-radius: var(--r-pill); background: var(--border-strong); overflow: hidden; }
.ao-meter.sm { display: inline-block; width: 60px; height: 5px; margin: 0 6px 0 0; vertical-align: middle; }
.ao-meter i { display: block; height: 100%; background: var(--text-faint); }
.ao-meter.ok i { background: var(--ok); }
.ao-meter.warn i { background: var(--warn); }
.ao-meter.bad i { background: var(--danger); }
.ao-bars { display: flex; align-items: flex-end; gap: 4px; padding-bottom: 18px; position: relative; }
.ao-col { flex: 1; height: 100%; display: flex; flex-direction: column-reverse; position: relative; min-width: 0; }
.ao-col i { display: block; width: 100%; }
.ao-col i:first-child { border-radius: 0 0 2px 2px; }
.ao-col i.done { background: var(--ok); }
.ao-col i.failed { background: var(--danger); }
.ao-col i.cancelled { background: var(--text-faint); }
.ao-xl { position: absolute; bottom: -18px; left: 0; font-size: .64rem; color: var(--text-faint); white-space: nowrap; }
.ao-legend { display: flex; gap: 14px; margin-top: 8px; font-size: .72rem; color: var(--text-muted); }
.ao-legend span::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 5px; vertical-align: middle; }
.ao-legend .done::before { background: var(--ok); }
.ao-legend .failed::before { background: var(--danger); }
.ao-legend .cancelled::before { background: var(--text-faint); }
@media (max-width: 640px) {
  .ao-worker { flex-wrap: wrap; }
  .ao-worker #aoRestart { width: 100%; }
  .ao-filters #avView { margin-left: 0; }
  .ao-panels { grid-template-columns: 1fr; }
  .ao-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ao-tile b { font-size: 1.5rem; }
}
.ao-brief { padding: 12px 14px; border-radius: var(--r-md); background: var(--surface-2); border: 1px solid var(--border); }
.ao-tag { display: inline-block; padding: 0 6px; border-radius: 6px; background: var(--accent-weak); color: var(--accent); font-weight: 600; }
.ao-h4n { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--text-faint); margin-left: 6px; }
/* video modal: the brief THIS run used (adminops.js runBrief) — one block: the text, a line when it
   was edited afterwards with its diff behind a toggle, the settings, and the edits around the run */
.ao-bblock h4 { display: flex; align-items: center; gap: 8px; }
.ao-src { padding: 1px 8px; border-radius: var(--r-pill); background: var(--surface-2); color: var(--text-faint);
  font-size: .68rem; font-weight: 500; text-transform: none; letter-spacing: 0; }
.ao-edited { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin: -2px 0 8px;
  font-size: .76rem; color: var(--warn); }
.ao-linkbtn { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-weight: 600; cursor: pointer; }
.ao-linkbtn:hover { text-decoration: underline; }
.ao-note { margin: 6px 0 0; font-size: .74rem; color: var(--text-faint); }
.ao-diff { padding: 10px 0; border-radius: var(--r-md); background: var(--surface-2); font-size: .86rem; line-height: 1.5; }
.ao-dline { display: flex; gap: 8px; padding: 0 14px; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text); }
.ao-dline i { flex: none; width: 10px; font-style: normal; font-weight: 700; }
.ao-dline > span { flex: 1; min-width: 0; }
.ao-dline.same { color: var(--text-faint); }
.ao-dline.add { background: var(--ok-weak); }
.ao-dline.add i { color: var(--ok); }
.ao-dline.del { background: var(--danger-weak); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--danger) 60%, transparent); }
.ao-dline.del i { color: var(--danger); }
.ao-set { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px 20px; margin: 12px 0 0; font-size: .78rem; line-height: 1.45; }
.ao-set > div { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 10px; padding: 3px 0; }
.ao-set dt { color: var(--text-faint); }
.ao-set dd { margin: 0; color: var(--text); overflow-wrap: anywhere; }
.ao-fold { margin-top: 10px; }
.ao-fold > summary { cursor: pointer; font-size: .78rem; color: var(--text-muted); font-weight: 600; text-transform: uppercase; letter-spacing: .05em; }
.ao-fold > summary .ao-h4n { text-transform: none; letter-spacing: 0; }
.ao-fold[open] > summary { margin-bottom: 8px; }
.ao-shotfold { margin-top: 16px; }
/* the one Details grid: 3 columns, 2 on a phone (adminops.js details) */
.ao-vd .ao-facts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ao-vd .ao-facts > .wide { grid-column: span 2; }
.ao-refs.sm { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.ao-refs.sm img { width: 32px; height: 32px; border-radius: 6px; }
.ao-cap { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* the timeline: grey before the run, the run itself, warning colour after */
.ao-tl-wrap { margin-top: 14px; padding: 10px 14px 12px; border-radius: var(--r-md); background: var(--surface-2); }
.ao-tl-k { display: flex; justify-content: space-between; gap: 10px; font-size: .72rem; color: var(--text-faint); }
.ao-tl-k span { color: var(--text-muted); }
.ao-tl { position: relative; display: flex; align-items: flex-start; gap: 0; margin: 10px 0 0; padding: 0; list-style: none; }
.ao-tl::before { content: ""; position: absolute; left: 0; right: 0; top: 5px; height: 2px; background: var(--border-strong); }
.ao-tl li { position: relative; flex: 1 1 0; display: flex; flex-direction: column; align-items: center; min-width: 0; }
.ao-tl li span { margin-top: 6px; font-size: .64rem; color: var(--text-faint); white-space: nowrap; }
.ao-tl-dot i { display: block; width: 10px; height: 10px; border-radius: 50%; background: var(--text-faint); }
.ao-tl-dot.after i { background: var(--warn); }
.ao-tl-dot.after span { color: var(--warn); }
.ao-tl-run { flex: 0 0 auto !important; padding: 0 10px; }
.ao-tl-run i { display: block; width: 4px; height: 12px; margin-top: -1px; border-radius: 2px; background: var(--accent); box-shadow: 0 0 0 4px var(--accent-weak); }
.ao-tl-run span { color: var(--text) !important; font-weight: 600; }
/* many sessions: the dots stay, their times go to the title */
.ao-tl:has(> li:nth-child(10)) .ao-tl-dot span { display: none; }
.ao-tl-more { display: none !important; }
@media (max-width: 640px) {
  .ao-set { grid-template-columns: 1fr; }
  .ao-vd .ao-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ao-tl { flex-direction: column; gap: 6px; overflow: visible; }
  .ao-tl::before { left: 4px; right: auto; top: 0; bottom: 0; width: 2px; height: auto; }
  .ao-tl li { flex-direction: row; align-items: center; gap: 10px; }
  .ao-tl li span, .ao-tl:has(> li:nth-child(10)) .ao-tl-dot span { display: inline; margin: 0; }
  .ao-tl-run { padding: 4px 0; }
  .ao-tl-run i { width: 12px; height: 4px; margin: 0 -1px; }
  .ao-tl:not(.all) .ao-tl-dot.far { display: none; }
  .ao-tl:not(.all) .ao-tl-more { display: flex !important; padding-left: 20px; font-size: .74rem; }
}
.ao-seen { font-size: .78rem; color: var(--ok); white-space: nowrap; }
.ao-unseen { font-size: .78rem; color: var(--warn); white-space: nowrap; }
/* composer: @image named in the brief with nothing attached (composer.js renderMissing) */
.mc-missing { margin: 8px 2px 0; padding: 8px 12px; border-radius: var(--r-md); background: var(--warn-weak);
  color: var(--warn); font-size: .82rem; line-height: 1.45; }

/* an edit made while a run is in progress applies from the next one (runnotice.js) — told,
   not warned: nothing is wrong, so the mark is the accent, not the warning colour */
.run-edit-note { display: flex; width: fit-content; max-width: 100%; align-items: center; gap: 6px; margin: 6px 2px 0;
  padding: 3px 10px 3px 6px; border-radius: var(--r-pill); background: var(--accent-weak);
  color: var(--text-muted); font-size: .74rem; line-height: 1.4; }
.run-edit-note::before { content: "i"; flex: none; display: grid; place-items: center; width: 14px; height: 14px;
  border-radius: 50%; background: var(--accent); color: #0C0C0E; font: 800 9px/1 var(--font-sans); }
.view-setup .run-edit-note { margin: 0 0 10px; }

/* ---- Why a workspace stopped (workspaces.js paintFailBanner) — owner-approved design 2026-10-13 */
.fail-banner { display: flex; gap: 14px; align-items: flex-start; padding: 16px 18px; margin-bottom: 14px;
  border-radius: var(--r-lg); border: 1px solid var(--border); }
.fail-banner.bad { background: var(--danger-weak); border-color: color-mix(in srgb, var(--danger) 45%, var(--border)); }
.fail-banner.warn { background: var(--warn-weak); border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.fb-ic { flex: none; width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center; font-weight: 700; }
.fail-banner.bad .fb-ic { background: color-mix(in srgb, var(--danger) 22%, transparent); color: var(--danger); }
.fail-banner.warn .fb-ic { background: color-mix(in srgb, var(--warn) 22%, transparent); color: var(--warn); }
.fb-body { flex: 1; min-width: 0; }
.fb-title { margin: 0 0 4px; font-weight: 650; font-size: 1rem; color: var(--text); }
.fb-note { margin: 0 0 4px; font-size: .86rem; color: var(--text-muted); }
.fb-why { margin: 10px 0 12px; padding: 10px 12px; border-radius: var(--r-md); background: var(--surface);
  font-size: .84rem; line-height: 1.6; color: var(--text); word-break: break-word; }
.res-free { color: var(--text-faint); font-size: .8em; }
.wsp-status.paused.failed { color: var(--danger); }
.notif-item.notif-fail .notif-item-ws { color: var(--danger); }
.auth-msg.ok { color: var(--ok); }
.auth-msg .link-ghost { display: inline; margin-left: 4px; }
.set-pw { flex-wrap: wrap; gap: 8px; }
.set-pw .select { max-width: 200px; }
.bs-brief-led { width: 100%; height: 100%; box-sizing: border-box; display: flex; flex-direction: column; justify-content: center;
  gap: 8px; padding: 28px; background: radial-gradient(120% 90% at 20% 10%, var(--accent-weak), var(--surface-2)); }
.bs-brief-led b { font-family: var(--font-display); font-size: 1.6rem; color: var(--text); }
.bs-brief-led span { color: var(--text-muted); font-size: .92rem; line-height: 1.5; }
.bs-thumb:empty { display: none; }
.ao-rst { display: block; margin-top: 6px; font-size: .74rem; color: var(--text-faint); }

/* ---- Admin → Users, after Theater's (admin.js paintUsers) ---------------------------------- */
.ut-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 4px 0 14px; }
.ut-bar .select { width: auto; min-width: 0; }
.ut-bar #utSearch { flex: 1 1 240px; max-width: 360px; }
.ut-bar #utCount { margin-left: auto; }
.ut-wrap { border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; background: var(--surface); }
.ut-table { margin: 0; }
.ut-table th { font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint);
  font-weight: 600; background: color-mix(in srgb, var(--surface-2) 60%, var(--surface)); }
.ut-table td.n, .ut-table th.n { text-align: right; font-variant-numeric: tabular-nums; }
.ut-table tbody tr:hover td { background: var(--surface-2); }
.ut-user { display: flex; align-items: center; gap: 12px; min-width: 0; }
.ut-av { flex: none; width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; font-weight: 700;
  font-size: .85rem; color: hsl(var(--h) 70% 82%); background: hsl(var(--h) 45% 22%); }
.ut-id { display: flex; flex-direction: column; min-width: 0; }
.ut-id b { font-weight: 600; color: var(--text); }
.ut-id .small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ut-unv { color: var(--warn); }
.ut-badge { display: inline-block; font-size: .72rem; font-weight: 600; padding: 2px 9px; border-radius: var(--r-pill);
  background: var(--sidebar-raised); color: var(--text-muted); text-transform: capitalize; }
.ut-badge.admin { background: var(--accent-weak); color: var(--accent); }
.ut-badge.paid, .ut-badge.on { background: var(--ok-weak); color: var(--ok); }
.ut-badge.off { background: var(--danger-weak); color: var(--danger); }
.ut-pill { font-size: .76rem; white-space: nowrap; color: var(--text-faint); }
.ut-pill.run { color: var(--ok); }

/* ---- every admin page, one look (after Theater admin) ----------------------------------------
   Pages are built from the same parts: a toolbar row (.ut-bar), stat tiles (.ao-tile), and panels
   (.ao-panel: icon, title, one line, body). Tables share one header style; a table in a panel
   runs edge to edge (.ao-pb.flush) and lines its first and last columns up with the header. */
.ao-tools { display: flex; align-items: center; gap: 8px; flex: none; }
.ao-ph > .ao-pill, .ao-ph > .btn-ghost, .ao-ph > .icon-btn { flex: none; }
.ao-ph > .ao-pill:empty { display: none; }
.ao-pb.flush { padding: 0; }
.ao-grid.g5 { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
#statsKpis, .log-tiles { margin-bottom: 14px; }
.log-tiles .ao-tile b { font-size: 1.15rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ut-bar .ut-note { margin-left: auto; }
.ut-bar #adminLogEmail { flex: 1 1 240px; max-width: 360px; }
.view-admin .admin-table th, .view-admin .run-table th {
  font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint); font-weight: 600;
  background: color-mix(in srgb, var(--surface-2) 60%, var(--surface)); }
.view-admin .admin-table tbody tr:hover td { background: var(--surface-2); }
.ao-pb.flush .admin-table th:first-child, .ao-pb.flush .admin-table td:first-child,
.ao-pb.flush .run-table th:first-child, .ao-pb.flush .run-table td:first-child { padding-left: 18px; }
.ao-pb.flush .admin-table th:last-child, .ao-pb.flush .admin-table td:last-child,
.ao-pb.flush .run-table th:last-child, .ao-pb.flush .run-table td:last-child { padding-right: 18px; }
.ao-pb.flush .run-table tr:last-child td { border-bottom: 0; }
.ao-pb.flush .log-scroll { border: 0; border-radius: 0; }
.ao-pb.flush .log-pager { padding: 0 18px 12px; }
.ao-pb > .run-table th:first-child, .ao-pb > .run-table td:first-child { padding-left: 0; }
#adminSlots .run-table { margin-top: 4px; }
#adminWatch .watch-row:last-child { margin-bottom: 0; }


/* ---- Admin → Credits (after Theater admin's Credits page) ---- */
#acTiles { margin-bottom: 14px; }
#adminCreditsPane .ut-bar #acQ { flex: 1 1 260px; max-width: 420px; }
#adminCreditsPane .ut-bar #acCount { margin-left: auto; }
.ac-table td { white-space: nowrap; }
.ac-table td:nth-child(4) { white-space: normal; min-width: 180px; }
.ac-who { display: block; font-weight: 600; color: var(--text); }
.ac-when { color: var(--text-muted); }
.ac-amt { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; }
.ac-amt.neg { color: var(--danger); }
.ac-amt.pos { color: var(--ok); }
/* Every small form dialog (create team, invite, top up, grant credits, close team…) sits in the
   shared .modal-card, which has NO padding of its own — so the dialog body pads itself, and the
   title leaves room for the card's round × in the top-right (owner, 2026-10-15: the title, field
   and buttons ran into the card's edge and the × sat on the input). */
.ac-grant { display: grid; gap: 14px; min-width: min(420px, 86vw); padding: 24px 24px 22px; }
.ac-grant h3 { margin: 0; padding-right: 44px; font-size: 1.1rem; line-height: 1.35; }
.ac-grant .confirm-acts { margin-top: 4px; }
.ac-grant label { display: grid; gap: 6px; font-size: .8rem; font-weight: 600; color: var(--text-muted); }
.ac-grant p { margin: 0; }
.ac-lbl, .ac-dws { display: none; }
/* On a phone the seven columns cannot fit, and a sideways-scrolling table showed only Date and
   User. Each transaction becomes a card instead: who and how much on top, then type, date and
   the balance it left, then what it was for. */
@media (max-width: 640px) {
  #adminCreditsPane .ut-bar #acQ { flex: 1 1 100%; max-width: none; }
  #adminCreditsPane .ut-bar #acCount { order: 3; margin-left: 0; }
  #adminCreditsPane .ut-bar #acGrant { margin-left: auto; padding: 8px 14px; }
  .ac-table thead { display: none; }
  .ac-table, .ac-table tbody { display: block; width: 100%; min-width: 0; }
  .ac-table tr { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 6px 10px; padding: 12px 14px;
    grid-template-areas: "user user amt" "type when bal" "desc desc desc"; border-bottom: 1px solid var(--border); }
  .ac-table td { display: block; padding: 0; height: auto; border: 0; white-space: normal; min-width: 0; }
  .ac-table .ac-user { grid-area: user; min-width: 0; }
  .ac-table .ac-user .small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ac-table .ac-amt { grid-area: amt; align-self: start; font-size: 1rem; }
  .ac-table .ac-type { grid-area: type; align-self: center; }
  .ac-table .ac-when { grid-area: when; font-size: .78rem; align-self: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ac-table .ac-bal { grid-area: bal; font-size: .78rem; color: var(--text-muted); align-self: center; }
  .ac-table .ac-lbl { display: inline; }
  .ac-table .ac-desc { grid-area: desc; font-size: .82rem; color: var(--text-muted); min-width: 0; }
  .ac-table .ac-ws { display: none; }
  .ac-table .ac-dws { display: inline; }
  .ac-table td:nth-child(4) { min-width: 0; }
}


/* ======================= TOP BAR + SPACES (TEAMS P3, 2026-10-14) =======================
   Desktop: no sidebar. Row 1 is "Muse / Space ▾ … credits · bell · account", row 2 the
   destinations as tabs, Admin last as one dropdown (owner's choice: top bar C). Phones keep the
   drawer and the bottom tab bar; only the space switcher joins their header. */
.space-sep { color: var(--faint); font-size: 1.1rem; margin: 0 2px; }
.space-menu { position: relative; min-width: 0; }
.space-btn { display: flex; align-items: center; gap: 8px; padding: 5px 9px 5px 5px; border-radius: 10px;
  border: 1px solid transparent; background: none; color: var(--text); font: inherit; cursor: pointer; min-width: 0; }
.space-btn:hover, .space-btn[aria-expanded="true"] { background: var(--surface); border-color: var(--border); }
.space-sq { flex: none; width: 22px; height: 22px; border-radius: 7px; display: grid; place-items: center;
  font-size: .68rem; font-weight: 700; background: hsl(var(--h, 225) 45% 26%); color: hsl(var(--h, 225) 80% 86%); }
.space-sq.round { border-radius: 50%; }
.space-name { font-weight: 600; font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; }
.space-role { font-size: .62rem; font-weight: 700; letter-spacing: .06em; padding: 2px 6px; border-radius: 6px;
  background: var(--accent-weak); color: var(--accent); }
.space-role.member { background: var(--ok-weak); color: var(--ok); }
.space-caret { width: 12px; height: 12px; color: var(--muted); flex: none; }
.space-drop { position: absolute; top: calc(100% + 6px); left: 0; z-index: 80; width: 280px; padding: 6px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 18px 44px rgba(0,0,0,.5); display: flex; flex-direction: column; gap: 2px; }
.space-drop-h { padding: 8px 10px 3px; font-size: .64rem; letter-spacing: .14em; color: var(--faint); text-transform: uppercase; font-weight: 700; }
.space-opt { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 9px; border: 0;
  background: none; color: var(--text); font: inherit; font-size: .88rem; text-align: left; cursor: pointer; width: 100%; }
.space-opt:hover, .space-opt.on { background: var(--surface); }
.space-opt .r { margin-left: auto; color: var(--muted); font-size: .76rem; white-space: nowrap; }
.space-opt.add { color: var(--accent); }
.space-sep-line { height: 1px; background: var(--border); margin: 4px 2px; }
.top-credits { display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text); font: inherit; font-size: .82rem; cursor: pointer; }
.top-credits-k { color: var(--muted); }
.top-credits b { font-variant-numeric: tabular-nums; }
.top-credits.low b { color: var(--warn); }
.toptabs { display: none; }
.admin-drop { display: none; }

@media (min-width: 761px) {
  :root { --sidebar-w: 0px; --sidebar-w-collapsed: 0px; }
  .sidebar, .nav-scrim { display: none !important; }
  /* ONE ROW (owner, 2026-10-14 — the "Team page inside the top-bar layout" board): Muse / space ▾ │
     the destinations │ Admin ▾ · balance · bell · account. Narrow desktops scroll the tabs sideways
     rather than wrap, so the bar keeps one height and nothing below it has to move. */
  .topbar, .app.collapsed .topbar { left: 0; height: 60px; padding: 0 24px; flex-wrap: nowrap;
    justify-content: flex-start; gap: 0 8px; }
  .topbar > .brand { display: flex; width: auto; padding: 0 4px 0 0; height: 60px; align-items: center; gap: 9px; flex: none; }
  .topbar > .brand .brand-glyph { width: 28px; }
  .topbar > .brand .brand-name { color: var(--text); font-size: 1.05rem; }
  .topbar > .space-sep, .topbar > .space-menu { align-self: center; height: 60px; display: flex; align-items: center; flex: none; }
  .topbar-right { height: 60px; order: 2; flex: none; }
  .toptabs { order: 1; display: flex; flex: 1 1 auto; min-width: 0; align-items: stretch; gap: 4px;
    align-self: center; margin-left: 18px; height: 36px;
    overflow-x: auto; scrollbar-width: none; }
  .toptabs::-webkit-scrollbar { display: none; }
  /* Selected = a soft grey rounded box with white text, exactly Higgsfield's top bar; hover = the
     same box fainter. The box sits inside the row, so nothing shifts when it moves. */
  .toptab { display: inline-flex; align-items: center; gap: 6px; padding: 0 12px; border: 0; border-radius: 10px;
    background: none; white-space: nowrap; color: var(--muted); font: inherit; font-size: .9rem; cursor: pointer;
    transition: background .15s, color .15s; }
  .toptab:hover { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); }
  .toptab.active { color: var(--text); background: color-mix(in srgb, var(--text) 11%, transparent); font-weight: 500; }
  .toptab svg { width: 12px; height: 12px; }
  .admin-menu { margin-left: auto; position: relative; display: flex; }
  .admin-menu.hidden { display: none; }
  .toptab-admin.active { color: var(--text); }
  .admin-drop { display: grid; position: fixed; right: 24px; top: 60px; z-index: 80; width: min(820px, calc(100vw - 48px));
    grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px 20px; padding: 18px 20px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: 18px; box-shadow: 0 30px 80px rgba(0,0,0,.55); }
  .admin-drop.hidden { display: none; }
  .admin-col { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .admin-col-h { font-size: .74rem; color: var(--faint); padding: 0 8px 6px; }
  .admin-dd { display: flex; gap: 12px; align-items: flex-start; padding: 8px; border-radius: 12px; border: 0;
    background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; }
  .admin-dd:hover, .admin-dd.active { background: var(--surface); }
  .admin-dd > span:last-child { display: flex; flex-direction: column; min-width: 0; }
  .admin-dd b { font-size: .88rem; font-weight: 600; }
  .admin-dd small { font-size: .74rem; color: var(--muted); line-height: 1.35; }
  .admin-dd-ic { flex: none; width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center;
    background: var(--surface); border: 1px solid var(--border); color: var(--text-muted); }
  .admin-dd-ic svg { width: 16px; height: 16px; }
  .main { padding-top: 84px; }
  .wizard-top, .home-steps-row { top: 60px; }
  .wizard-top-right, .home-steps-row > .wiz-close { top: 74px; }
  .angle-drawer { top: 72px; }
  .prompt-preview { top: 72px; }
  .sty-bar { top: 60px; }
  .ws-head-title, .ws-head { scroll-margin-top: 84px; }
}
/* Laptop widths: the one-row bar tightens before anything is cut — the role badge, the word
   "Pool" and the wordmark go first, the tabs close up. Below ~960px the tabs scroll, and the
   fade on their right edge says so. */
@media (min-width: 761px) and (max-width: 1180px) {
  .space-role, .top-credits-k { display: none; }
  .topbar > .brand .brand-name { display: none; }
  .topbar, .app.collapsed .topbar { padding: 0 14px; }
  .toptabs { margin-left: 8px; }
  .toptab { padding: 0 9px; font-size: .86rem; }
  .topbar-right { gap: 6px; }
}
@media (min-width: 761px) and (max-width: 960px) {
  .toptabs { -webkit-mask-image: linear-gradient(90deg, #000 85%, transparent);
             mask-image: linear-gradient(90deg, #000 85%, transparent); }
}
@media (max-width: 760px) {
  .space-sep { display: none; }
  .space-btn { padding: 4px 6px 4px 4px; gap: 6px; }
  .space-name { max-width: 96px; font-size: .82rem; }
  .space-role { display: none; }
  .space-drop { position: fixed; top: 56px; left: 10px; right: 10px; width: auto; }
  .top-credits { display: none; }
  .topbar .brand-name { display: none; }
}

/* ---------------------------------- Team page ---------------------------------- */
.tm-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.tm-head h1 { margin: 4px 0 2px; font-family: var(--font-display); font-size: 2rem; letter-spacing: -.02em; }
.tm-eyebrow { font: 600 .72rem/1 ui-monospace, Menlo, monospace; letter-spacing: .2em; color: var(--accent); text-transform: uppercase; }
.tm-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.tm-tiles { margin-bottom: 16px; }
.tm-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin-bottom: 16px; overflow-x: auto; }
.tm-tab { padding: 9px 14px; border: 0; background: none; color: var(--muted); font: inherit; cursor: pointer; white-space: nowrap;
  box-shadow: inset 0 -2px 0 transparent; }
.tm-tab.on { color: var(--text); box-shadow: inset 0 -2px 0 var(--accent); }
.tm-announce { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border-radius: 14px; margin-bottom: 16px;
  background: var(--accent-weak); border: 1px solid var(--accent-border); }
.tm-announce b { display: block; font-size: .78rem; color: var(--accent); margin-bottom: 2px; }
.tm-who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.tm-who .small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tm-low { color: var(--warn); font-weight: 600; }
.tm-ra { display: flex; justify-content: flex-end; gap: 6px; position: relative; }
.tm-ib { width: 32px; height: 32px; border-radius: 9px; border: 1px solid var(--border); background: none; color: var(--text-muted);
  display: inline-grid; place-items: center; cursor: pointer; padding: 0; }
.tm-ib:hover { color: var(--text); border-color: var(--border-hi); }
.tm-ib svg { width: 16px; height: 16px; }
.tm-ib.ghost { visibility: hidden; }
.tm-menu { position: absolute; right: 0; top: 38px; z-index: 30; width: 200px; padding: 6px; border-radius: 12px;
  background: var(--surface-2); border: 1px solid var(--border); box-shadow: 0 16px 40px rgba(0,0,0,.5); display: flex; flex-direction: column; }
.tm-menu button { border: 0; background: none; color: var(--text); font: inherit; font-size: .84rem; text-align: left; padding: 8px 10px; border-radius: 8px; cursor: pointer; }
.tm-menu button:hover { background: var(--surface); }
.tm-menu .danger { color: var(--danger); }
.tm-menu hr { border: 0; height: 1px; background: var(--border); margin: 4px 2px; }
.tm-grid2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 16px; align-items: start; }
.tm-ring { width: 128px; height: 128px; border-radius: 50%; display: grid; place-items: center; flex: none; }
.tm-ring > div { width: 98px; height: 98px; border-radius: 50%; background: var(--surface); display: grid; place-items: center; text-align: center; }
.tm-ring b { font-family: var(--font-display); font-size: 1.6rem; }
.tm-allow { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.tm-allow-lines { display: flex; flex-direction: column; gap: 6px; color: var(--text-muted); font-size: .86rem; }
.tm-amt { font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; }
.tm-amt.pos { color: var(--ok); } .tm-amt.neg { color: var(--danger); }
.tm-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; }
.tm-card { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 14px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.tm-card:hover { border-color: var(--border-hi); }
.tm-card .space-sq { width: 36px; height: 36px; border-radius: 11px; font-size: .9rem; }
.tm-empty { padding: 28px; border: 1px dashed var(--border-hi); border-radius: 14px; color: var(--muted); text-align: center; }
.tm-banner { display: flex; align-items: center; gap: 14px; padding: 12px 16px; border-radius: 14px; margin: 0 0 16px;
  background: color-mix(in srgb, var(--warn) 12%, var(--surface)); border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent); }
.tm-banner.out { background: color-mix(in srgb, var(--danger) 12%, var(--surface)); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.tm-banner > div { flex: 1; min-width: 0; }
.tm-banner small { display: block; color: var(--text-muted); }
.ws-by { display: inline-block; margin-left: 6px; font-size: .7rem; padding: 1px 7px; border-radius: 999px; background: var(--surface-2); color: var(--text-muted); }
@media (max-width: 760px) {
  .tm-grid2 { grid-template-columns: 1fr; }
  .tm-head h1 { font-size: 1.6rem; }
}

/* ------------------- Allocate dialog (visual 1: the team as one bar) ------------------- */
.al { display: flex; flex-direction: column; gap: 16px; min-width: min(520px, 84vw); padding: 24px 24px 22px; }
.al-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding-right: 44px; flex-wrap: wrap; }
.al-top h3 { margin: 0; font-family: var(--font-display); }
.al-bar { display: flex; height: 30px; border-radius: 10px; overflow: hidden; gap: 2px; background: var(--surface-2); }
.al-bar i { display: block; height: 100%; min-width: 2px; transition: width .15s; }
.al-bar .al-new { background-image: repeating-linear-gradient(45deg, rgba(255,255,255,.25) 0 6px, transparent 6px 12px); }
.al-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: .78rem; color: var(--text-muted); }
.al-legend span::before { content: ""; display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 6px; background: var(--c); vertical-align: -1px; }
.al-slide { display: flex; align-items: center; gap: 14px; }
.al-slide input[type=range] { flex: 1; accent-color: var(--accent); }
.al-num { width: 110px; text-align: right; font-family: var(--font-display); font-size: 1.5rem; font-weight: 700;
  border: 1px solid var(--border); border-radius: 10px; background: var(--bg-2, var(--surface)); color: var(--text); padding: 4px 10px; }
.al-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.al-chip { padding: 6px 12px; border-radius: 999px; border: 1px solid var(--border); background: none; color: var(--text-muted); font: inherit; font-size: .8rem; cursor: pointer; }
.al-chip.on { border-color: var(--accent); color: var(--text); background: var(--accent-weak); }
.al-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; padding-top: 12px; border-top: 1px solid var(--border); }
.al-foot .r { display: flex; gap: 8px; }
.al-note { width: 100%; }
.inv-card { max-width: 440px; margin: 40px auto; padding: 28px; border-radius: 20px; border: 1px solid var(--border); background: var(--surface); text-align: center; }
.inv-card h2 { margin: 10px 0 6px; font-family: var(--font-display); }
.inv-card .tm-acts { justify-content: center; margin-top: 18px; }
.auth-invite { margin: -4px 0 14px; padding: 10px 12px; border-radius: 12px; background: var(--accent-weak); border: 1px solid var(--accent-border); font-size: .86rem; }
/* ------------------------------ comments (TEAMS P6) ------------------------------ */
.cm { display: flex; flex-direction: column; gap: 10px; }
.cm-list { display: flex; flex-direction: column; gap: 8px; max-height: 320px; overflow-y: auto; }
.cm-row { padding: 9px 12px; border-radius: 12px; background: var(--surface-2); max-width: 92%; }
.cm-row.mine { align-self: flex-end; background: var(--accent-weak); }
.cm-meta { display: flex; gap: 8px; align-items: baseline; font-size: .74rem; color: var(--muted); }
.cm-meta b { color: var(--text); font-size: .8rem; }
.cm-del { margin-left: auto; font-size: .72rem; }
.cm-body { font-size: .88rem; white-space: pre-wrap; word-break: break-word; margin-top: 2px; }
.cm-new { display: flex; gap: 8px; align-items: flex-end; }
.cm-new textarea { flex: 1; min-height: 42px; resize: vertical; }
.notif-inv-acts { display: flex; gap: 6px; margin-top: 6px; }
.al-top { padding-right: 40px; }                         /* the modal's own × sits in that corner */
.al-slide input[type=range] { flex: 1 1 auto; min-width: 0; width: auto; }
.al .al-num { flex: 0 0 120px; width: 120px; max-width: 120px; }
.tm-you { color: var(--muted); font-size: .78rem; font-weight: 400; }
.ao-pill.warn { background: var(--warn-weak); color: var(--warn); }

/* ---- THE TOP BAR, QUIETER (owner, 2026-10-14: "the premium feel is gone" next to Higgsfield) ----
   What made Higgsfield's bar read as premium was what it leaves OUT: no boxes, no borders, no
   badges on the account, one flat colour with the page, and a selected tab marked by its text
   colour alone. Ours had a box on every control (balance, bell, account), a frosted bar with a
   rule under it, the wordmark, a slash and an OWNER badge. Desktop only — phones keep their bar. */
@media (min-width: 761px) {
  .topbar, .app.collapsed .topbar { height: 64px; background: var(--bg); backdrop-filter: none;
    border-bottom: 0; padding: 0 28px; }
  .topbar > .brand { height: 64px; padding-right: 2px; }
  .topbar > .brand .brand-glyph { width: 32px; }
  .topbar > .brand .brand-name, .topbar > .space-sep, .space-role { display: none; }
  .topbar > .space-sep + .space-menu, .topbar > .space-menu { height: 64px; margin-left: 6px; }
  .space-btn { gap: 7px; padding: 6px 8px; border: 0; background: none; color: var(--muted); }
  .space-btn:hover, .space-btn[aria-expanded="true"] { background: none; color: var(--text); }
  .space-sq { width: 20px; height: 20px; border-radius: 6px; font-size: .62rem; }
  .space-name { font-weight: 500; font-size: .95rem; }
  .space-caret { width: 12px; height: 12px; opacity: .7; }

  /* Tabs: plain words, grey, selected = the accent colour. A hair of a divider before the first. */
  .toptabs { margin-left: 14px; padding-left: 20px; gap: 26px; height: 28px; position: relative; }
  .toptabs::before { content: ""; position: absolute; left: 0; top: 50%; width: 1px; height: 18px;
    transform: translateY(-50%); background: var(--border); }
  .toptab { padding: 0; border-radius: 0; background: none !important; font-size: 1rem; font-weight: 500;
    color: color-mix(in srgb, var(--text) 52%, transparent); letter-spacing: -.005em; }
  .toptab:hover { color: var(--text); }
  .toptab.active { color: var(--accent); font-weight: 500; }
  .toptab-admin.active { color: var(--warn); }
  .admin-menu { padding-left: 22px; position: relative; }
  .admin-menu::before { content: ""; position: absolute; left: 0; top: 50%; width: 1px; height: 18px;
    transform: translateY(-50%); background: var(--border); }
  .tab-new { margin-left: 7px; padding: 2px 6px; border-radius: 6px; font-size: .68rem; font-weight: 700;
    background: var(--accent-weak); color: var(--accent); }
  .admin-drop { top: 64px; }

  /* Right side: the balance is the one filled element, like Higgsfield's Pricing; the bell and
     the account are bare. */
  .topbar-right { height: 64px; gap: 6px; }
  .top-credits { border: 0; background: var(--surface); padding: 7px 13px; border-radius: 10px; font-size: .9rem; }
  .top-credits:hover { background: var(--surface-2); }
  .notif-btn { background: none; width: 38px; height: 38px; color: color-mix(in srgb, var(--text) 70%, transparent); }
  .notif-btn:hover { background: none; color: var(--text); }
  .acct-btn { background: none; padding: 4px; }
  .acct-btn:hover { background: none; }
  .acct-btn .acct-name, .acct-btn .acct-caret { display: none; }
  .acct-btn .acct-avatar { width: 32px; height: 32px; font-size: .8rem; }
  .notif-drop, .acct-drop { top: 50px; }
  .main { padding-top: 88px; }
  .wizard-top, .home-steps-row, .sty-bar { top: 64px; }
}
@media (min-width: 761px) and (max-width: 1180px) {
  .toptabs { gap: 16px; padding-left: 14px; margin-left: 8px; }
  .toptab { font-size: .92rem; }
  .tab-new { display: none; }
}

/* ---- ACCENT TONES ON TRIAL (owner, 2026-10-14). ?tone=a | ?tone=b on any page (remembered), ?tone=
   to go back. Both after Higgsfield's lime: a LIGHT accent with DARK text, a pressed edge instead of
   a glow, and neutral greys — the purple-tinted navy swallowed the old blue. ----------------------- */
html[data-tone="a"], html[data-tone="b"] {
  --bg:#0C0C0E; --surface:#151517; --surface-2:#1B1B1E; --sidebar:#08080A; --sidebar-raised:#222226;
  --border:#242428; --border-strong:#2E2E33; --text-muted:#A3A3AB; --text-faint:#7C7C85; --on-ink:#8E8E96;
  --header-bg:rgba(12,12,14,.86);
  --shadow-accent:none;
}
/* A · ICE BLUE — the light blue at the left of the logo. */
html[data-tone="a"] {
  --accent:#8FD0FF; --accent-deep:#4FA6E6; --accent-weak:rgba(143,208,255,.12);
  --accent-border:rgba(143,208,255,.32); --on-accent:#06121C;
}
/* B · IRIDESCENT — the logo's blue → violet → pink on the primary button only; violet for text. */
html[data-tone="b"] {
  --accent:#B39BFF; --accent-deep:#7E62E8; --accent-weak:rgba(179,155,255,.13);
  --accent-border:rgba(179,155,255,.32); --on-accent:#0B0A14;
}
html[data-tone="a"] .btn-neon, html[data-tone="b"] .btn-neon { color: var(--on-accent); box-shadow: inset 0 -3px 0 var(--accent-deep); }
html[data-tone="a"] .btn-neon:hover, html[data-tone="b"] .btn-neon:hover { filter: brightness(1.05); box-shadow: inset 0 -3px 0 var(--accent-deep); }
html[data-tone="a"] .btn-neon:active, html[data-tone="b"] .btn-neon:active { box-shadow: inset 0 -1px 0 var(--accent-deep); transform: translateY(2px); }
html[data-tone="b"] .btn-neon:not(.danger) { background: linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%);
  box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); }
html[data-tone="b"] .btn-neon:not(.danger):hover { box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); }
/* The other primary buttons — each had its own hard-coded blue (#6d7cff → #4453e8, or the phone
   tab bar's violet→blue), so the tone did not reach them: "New workspace", the empty card's "+",
   "Top up" and the phone's centre Create. Same fill and pressed edge as .btn-neon. */
html[data-tone="a"] :is(.ws-head-new, .wsp-new-plus, .cr-topup, .tab-fab) {
  background: var(--accent); color: var(--on-accent); box-shadow: inset 0 -3px 0 var(--accent-deep); }
html[data-tone="b"] :is(.ws-head-new, .wsp-new-plus, .cr-topup, .tab-fab) {
  background: linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%); color: var(--on-accent);
  box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); }
html[data-tone] :is(.ws-head-new, .wsp-new-plus, .cr-topup, .tab-fab) svg { color: inherit; }

/* ---- ONE ACCENT (colour audit, 2026-10-14, under the trial tones only) --------------------------
   Higgsfield reads as premium because one colour does all the pointing and everything else is
   grey. Ours had a hue per workspace, per team and per user, gold stars, a violet "brain" colour
   and violet focus rings beside the accent — five or six colours on the Home page alone.
   KEEP: the accent (primary buttons, the selected tab, New badges, progress), and the status
   colours ok / warn / danger where they mean a real state. GREY: identity avatars and stars.
   QUIETER: per-workspace tags keep a trace of their hue (they help tell clips apart) at low
   saturation. ACCENT: the stray violet rings and glows. */
html[data-tone] { --brain: var(--accent); --brain-weak: var(--accent-weak); }

/* identity squares and avatars: grey letters on grey, not a rainbow */
html[data-tone] :is(.space-sq, .ut-av, .wsp-avatar) {
  background: var(--surface-2); color: var(--text); border-color: var(--border); }
html[data-tone] .acct-avatar { background: var(--sidebar-raised); color: var(--text); }

/* Stars are gold again (owner, 2026-10-15): a starred workspace is a status the eye should find,
   and gold is the colour everyone reads as "starred". The one-accent rule is for decoration. */
html[data-tone] :is(.wsp-star.on, .wsp-star:hover, .ws-filter-b[data-f="starred"].is-on, .ws-opt-star) { color: #F5C451; }
html[data-tone] .wsp-star.on svg { fill: #F5C451; }
html[data-tone] .wsp-card:has(.wsp-star.on) { border-color: var(--border-strong); }

/* per-workspace tags: the hue survives, quietly */
html[data-tone] :is(.ref-shot, .ref-ws-pill) { color: hsl(var(--ws-hue, 190) 22% 72%); }
html[data-tone] .ref-ws-pill { border-bottom-color: hsl(var(--ws-hue, 190) 18% 50% / .45); }
html[data-tone] .lib-ws { background: linear-gradient(hsl(var(--ws-hue, 190) 18% 50% / .2), hsl(var(--ws-hue, 190) 18% 50% / .2)), rgba(7, 8, 13, .82);
  border-color: hsl(var(--ws-hue, 190) 18% 55% / .4); color: hsl(var(--ws-hue, 190) 25% 84%); }
html[data-tone] .ref-thumb-wrap::before { background: hsl(var(--ws-hue, 190) 22% 55%); }
html[data-tone] :is(.cr-wsdot, .cr-wsbar i) { background: hsl(var(--h, 258) 22% 60%); }

/* stray violet rings and glows → the accent, no glow */
html[data-tone] .seg-opt input:focus-visible + .seg-face { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent); }
html[data-tone] .pager-n.on { box-shadow: none; }

/* ---- TONE B, A STEP FURTHER: TYPE AND SURFACES (2026-10-14) ------------------------------------
   The colour was right and it still read as a template next to Higgsfield, for two reasons that
   are not colour. (1) Its headlines are a heavy CONDENSED grotesk in capitals; ours were a
   sentence-case display face under a tracked mono eyebrow. (2) It separates things by FILL —
   panels a shade lighter than the page, no outlines — where ours drew a hairline round the reel,
   every card, the search box and the filter group. Owner tried condensed capitals (Archivo,
   then Saira Condensed) and kept the original Bricolage headline, 2026-10-14. Tone B only, so the default is untouched. */
html[data-tone="b"] .home-hello {
  font-family: var(--font-sans); font-size: 14px; letter-spacing: 0; text-transform: none;
  color: var(--text-muted); margin-bottom: 10px; }

/* surfaces, not hairlines — the reel and the desktop workspace cards only. The search box and
   filter keep their outline, the "Create new workspace" card keeps its dashed edge, and the phone
   keeps its divided list (owner's call, 2026-10-14). */
html[data-tone="b"] .home-reel { border: 0; background: var(--surface); }
@media (min-width: 761px) {
  html[data-tone="b"] .wsp-card:not(.new) { border: 0; background: var(--surface); box-shadow: none; border-radius: 16px; }
  html[data-tone="b"] .wsp-card:not(.new):hover { background: var(--surface-2); box-shadow: none; transform: translateY(-2px); }
  html[data-tone="b"] .wsp-card:not(.new):has(.wsp-star.on) { border: 0; }
}

/* ---- TONE B: MESSAGES, NOTICES, SEGMENTED CONTROLS (owner picked B / B / B, 2026-10-14) ----------
   One rule for all three, applied everywhere they occur: colour lives in a small mark, never in a
   frame. Radii: 10px for controls and toasts, 16px for notices.
   · Toast — solid dark box, a filled ✓ / ✕ disc (core.js toast(), ICON.okc / errc), a springy rise.
   · Notice — the neutral raised surface, a coloured mark, the point first in bold, then the why.
     Applies to every warning/error box: clip references, composer @image gaps, team allowance,
     workspace fail banner, account status, admin incident rows and error boxes, low-credit card.
   · Segmented control — the selected option is a raised block that slides (core.js placeSegs,
     the Styles page's .sty-seg-ind generalised). Page-level tabs (Account, Admin, workspace view,
     Team) keep their underline: they navigate between screens, these switch a panel. */

/* outside tone B the new marks stay out of the way */
.toast-ic, .nb-ic { display: none; }
.ref-frozen strong { display: block; color: var(--text); font-weight: 600; }
.fb-ic svg { width: 20px; height: 20px; }

/* toast */
html[data-tone="b"] .toast {
  display: flex; align-items: center; gap: 10px; border: 0; border-radius: 10px;
  padding: 10px 16px 10px 12px; background: #232327; color: #F2F2F4; font-size: .86rem; font-weight: 500;
  box-shadow: 0 12px 32px rgba(0,0,0,.45), 0 0 0 1px rgba(255,255,255,.05);
  transform: translateX(-50%) translateY(18px) scale(.96);
  transition: opacity .2s ease, transform .5s cubic-bezier(.2,1.3,.4,1); }
html[data-tone="b"] .toast.show { transform: translateX(-50%) translateY(0) scale(1); }
html[data-tone="b"] .toast-ic { display: grid; flex: none; width: 18px; height: 18px; }
html[data-tone="b"] .toast-ic svg { width: 18px; height: 18px; }
html[data-tone="b"] .toast.ok .toast-ic { color: var(--ok); }
html[data-tone="b"] .toast.err .toast-ic { color: var(--err); }
html[data-tone="b"] .toast-act { border: 0; border-radius: 8px; background: rgba(255,255,255,.1); color: #F2F2F4; }
html[data-tone="b"] .toast-act:hover { background: #F2F2F4; color: #0C0C0E; }

/* notices: the neutral surface, colour only in the mark */
html[data-tone="b"] :is(.ref-frozen, .mc-missing, .tm-banner, .tm-banner.out, .fail-banner, .fail-banner.bad,
    .fail-banner.warn, .acct-status, .acct-status.warn, .log-inc-row, .ao-errbox) {
  border: 0; border-radius: 16px; background: var(--surface-2); }
html[data-tone="b"] :is(.ref-frozen, .mc-missing) {
  display: flex; gap: 10px; align-items: flex-start; padding: 13px 16px; color: var(--text-muted);
  font-size: .8rem; line-height: 1.55; }
html[data-tone="b"] .nb-ic { display: grid; flex: none; width: 17px; height: 17px; margin-top: 1px; color: var(--warn); }
html[data-tone="b"] .nb-ic svg { width: 17px; height: 17px; }
html[data-tone="b"] .ref-frozen.gone .nb-ic { color: var(--text-faint); }
/* boxes whose markup has no mark of their own get one drawn: a disc with "!" */
html[data-tone="b"] :is(.mc-missing, .tm-banner)::before {
  content: "!"; flex: none; display: grid; place-items: center; width: 17px; height: 17px; border-radius: 50%;
  background: var(--warn); color: #0C0C0E; font: 800 11px/1 var(--font-sans); margin-top: 1px; }
html[data-tone="b"] .run-edit-note { background: var(--surface-2); color: var(--text-muted); }
html[data-tone="b"] .tm-banner { align-items: flex-start; }
html[data-tone="b"] .tm-banner::before { margin-top: 2px; }
html[data-tone="b"] .tm-banner.out::before { background: var(--danger); }
html[data-tone="b"] .tm-banner > button { align-self: center; }
html[data-tone="b"] .fb-ic, html[data-tone="b"] .fail-banner:is(.bad, .warn) .fb-ic {
  width: 22px; height: 22px; background: none; border-radius: 0; margin-top: 1px; }
html[data-tone="b"] .fb-ic svg { width: 22px; height: 22px; }
html[data-tone="b"] .acct-status-ico { border: 0; background: color-mix(in srgb, var(--ok) 16%, transparent); }
html[data-tone="b"] .acct-status.warn .acct-status-ico { background: color-mix(in srgb, var(--warn) 16%, transparent); }
html[data-tone="b"] .ao-errbox { color: var(--text-muted); }
html[data-tone="b"] .ao-errbox::first-line { color: var(--danger); }
html[data-tone="b"] .credit-box.low { border-color: transparent; background: var(--surface); }

/* segmented controls: a raised block that slides */
html[data-tone="b"] :is(.ref-tabs, .lib-tabs, .clip-tabs, .pe-tabs, .sty-wchips, .pf-mode-toggle, .ws-filter) { position: relative; }
html[data-tone="b"] :is(.ref-tabs, .ref-tabs.has-ind) { position: sticky; }
html[data-tone="b"] :is(.ref-tab, .lib-tab, .clip-tab, .pe-tab, .sty-wtab, .pf-mode-btn, .ws-filter-b) { position: relative; z-index: 1; }
html[data-tone="b"] :is(.ref-tab.on, .lib-tab.on, .clip-tab.on, .pe-tab.on, .sty-wtab.on, .pf-mode-btn.on, .ws-filter-b.is-on),
html[data-tone="b"] .seg-ind {
  background: #26262B; border-color: transparent; color: var(--text);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 4px 12px rgba(0,0,0,.35); }
html[data-tone="b"] .has-ind > :is(.ref-tab.on, .lib-tab.on, .clip-tab.on, .pe-tab.on, .sty-wtab.on, .pf-mode-btn.on, .ws-filter-b.is-on) {
  background: transparent; box-shadow: none; }
html[data-tone="b"] .seg-ind {
  position: absolute; top: 0; left: 0; z-index: 0; border-radius: 9px; pointer-events: none;
  transition: transform .35s cubic-bezier(.2,1.2,.4,1), width .35s cubic-bezier(.2,1.2,.4,1), opacity .15s; }
html[data-tone="b"] .pf-mode-btn.on { color: var(--accent); }

/* ---- TONE B: THE WHOLE SYSTEM, NOT JUST WHAT WAS POINTED AT (2026-10-14) ------------------------
   The owner found a confirm dialog still drawn the old way (outlined card, outlined Cancel, a red
   button with the purple underline meant for the primary gradient) after the notices and tabs had
   moved on. These rules cover every component kind at once, so no screen keeps the old look:
   · Hairlines fade (tokens): frames recede to near-invisible; things are told apart by fill.
     Exceptions the owner asked to keep: the workspace search box and filter, the phone list's
     dividers — pinned to the old hairline below.
   · Hover/focus is a soft accent ring (--glow-cyan) or a lighter fill, never a glow.
   · Secondary buttons are fills; danger is a flat red (no gradient underline).
   · Dialogs, sheets, menus, popovers, tooltips: raised surface + deep shadow + a faint ring.
   · Selected choice (chip, tile, pill, provider row): raised fill with an accent ring, not a
     gradient block — the gradient is kept for the one primary action on a screen. */
html[data-tone="b"] {
  --border: rgba(255,255,255,.06); --border-strong: rgba(255,255,255,.1); --border-hi: rgba(255,255,255,.1);
  --glow-cyan: 0 0 0 1.5px var(--accent-border);
  --raised: #26262B; --float: #1C1C20;
  --float-shadow: 0 18px 48px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,.06);
}
html[data-tone="b"] :is(.ws-search, .ws-filter) { border-color: #242428; }
@media (max-width: 760px) { html[data-tone="b"] .wsp-card { border-bottom-color: #242428; } }

/* buttons */
html[data-tone="b"] .btn-ghost {
  border-color: transparent; background: rgba(255,255,255,.06); color: var(--text); }
html[data-tone="b"] .btn-ghost:hover { border-color: transparent; background: rgba(255,255,255,.1); box-shadow: none; }
html[data-tone="b"] :is(.btn-ghost.danger, .btn-ghost.mini.danger) {
  border-color: transparent; background: color-mix(in srgb, var(--err) 12%, transparent); color: var(--err); }
html[data-tone="b"] .btn-ghost.danger:hover { background: color-mix(in srgb, var(--err) 18%, transparent); box-shadow: none; }
html[data-tone="b"] .btn-neon.danger, html[data-tone="b"] .btn-neon.danger:hover,
html[data-tone="b"] .btn-neon.danger:active { background: #F0566B; color: #fff; box-shadow: none; }
html[data-tone="b"] .btn-neon.danger:hover { background: #F86B7E; }
html[data-tone="b"] :is(.icon-btn, .lib-act, .wiz-close, .modal-close) {
  border-color: transparent; background: rgba(255,255,255,.06); }
html[data-tone="b"] :is(.icon-btn, .lib-act, .wiz-close, .modal-close):hover {
  border-color: transparent; background: rgba(255,255,255,.12); box-shadow: none; color: var(--text); }

/* inputs: a sunken fill, an accent ring on focus */
html[data-tone="b"] :is(textarea, .select, input[type="text"], input[type="number"], input[type="password"],
    input[type="email"], input[type="search"]) { border-color: transparent; background-color: rgba(255,255,255,.05); }
html[data-tone="b"] :is(textarea, .select, input, .auth-card input):focus {
  border-color: var(--accent-border); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }

/* dialogs and sheets */
html[data-tone="b"] :is(.modal-card, .sty-sheet, .ws-sheet, .trim-sheet, .auth-card) {
  border: 0; border-radius: 16px; background: var(--float); box-shadow: var(--float-shadow); }
html[data-tone="b"] .modal-overlay { background: rgba(5,5,7,.7); }

/* menus, popovers, tooltips */
html[data-tone="b"] :is(.notif-drop, .acct-drop, .ws-drop, .space-drop, .split-menu, .bb-pop, .ap-more-menu,
    .acct-rowmenu, .acct-multi-menu, .mc-pop, .mp-pop, .tm-menu, .sday-pop, .cr-tip, .schart-tip, .admin-drop) {
  border: 0; border-radius: 12px; background: var(--float); box-shadow: var(--float-shadow); }

/* a selected choice: raised fill + accent ring (the gradient stays for primary actions) */
html[data-tone="b"] :is(.chip, .aspect-tile, .target-pill, .provider-row) { border-color: transparent; background: var(--surface-2); }
html[data-tone="b"] :is(.chip.on, .aspect-tile.on, .target-pill.on, .target-pill.dev.on, .provider-row.on, .anchor-ai.on,
    .pe-seg.on, .sday-chip.on, .al-chip.on) {
  color: var(--text); background: var(--raised); border-color: transparent;
  box-shadow: 0 0 0 1.5px var(--accent), 0 4px 12px rgba(0,0,0,.3); }
html[data-tone="b"] .dropzone.dragover { border-color: var(--accent); background: var(--accent-weak); box-shadow: none; }
html[data-tone="b"] :is(.feed-more, .feed-thumb):hover { box-shadow: 0 0 0 1.5px var(--accent-border); }

/* ---- TONE B: EVERY FRAME, FOUND BY SCAN (2026-10-14) ----------------------------------------------
   The block below comes from scanning every rule above that draws a full 1px frame (dashed edges are
   kept: they mean "add here" or "drop here"). Filled things lose the frame; outline-only things get a
   quiet fill; accent outlines become accent fills; a selected thing keeps an inner accent ring. */
/* GENERATED by scratchpad framegen.py from a scan of every full-frame rule — do not hand-edit. */
/* filled containers and controls: the fill already separates them; drop the frame */
html[data-tone="b"] .status-pill,
html[data-tone="b"] .collapse-btn,
html[data-tone="b"] .log-pre,
html[data-tone="b"] .log-ref-view,
html[data-tone="b"] .notif-drop,
html[data-tone="b"] .lib-cap-edit,
html[data-tone="b"] .lib-cap-pencil,
html[data-tone="b"] .acct-drop,
html[data-tone="b"] .card,
html[data-tone="b"] .pe-full-body,
html[data-tone="b"] .pe-vcount,
html[data-tone="b"] .pe-ver.current,
html[data-tone="b"] .help-q::after,
html[data-tone="b"] .pf-mode-toggle,
html[data-tone="b"] .ref-item,
html[data-tone="b"] .ref-part,
html[data-tone="b"] .ref-list-col,
html[data-tone="b"] .ref-count,
html[data-tone="b"] .ref-clip-model,
html[data-tone="b"] .ref-refs,
html[data-tone="b"] .ref-tab.on,
html[data-tone="b"] .ref-sec-n,
html[data-tone="b"] .ref-chain-tag,
html[data-tone="b"] .ref-img,
html[data-tone="b"] .head-dd-btn,
html[data-tone="b"] .chip,
html[data-tone="b"] .wsp-card,
html[data-tone="b"] .ws-drop,
html[data-tone="b"] .setup-card,
html[data-tone="b"] .ref-panel,
html[data-tone="b"] .bb-pop,
html[data-tone="b"] .split-menu,
html[data-tone="b"] .ask-thumb-clear,
html[data-tone="b"] .anchor-thumb-x,
html[data-tone="b"] .anchor-ai,
html[data-tone="b"] .step-box,
html[data-tone="b"] .ap-details,
html[data-tone="b"] .wiz-close,
html[data-tone="b"] .provider-row,
html[data-tone="b"] .aspect-tile,
html[data-tone="b"] .target-pill,
html[data-tone="b"] .ico-btn,
html[data-tone="b"] .ico-btn:hover,
html[data-tone="b"] .stats-row,
html[data-tone="b"] .credit-box,
html[data-tone="b"] .ap-card.clickable:hover,
html[data-tone="b"] .ap-rename-btn:hover,
html[data-tone="b"] .target-acct,
html[data-tone="b"] .acct-multi-trigger,
html[data-tone="b"] .ta-chip,
html[data-tone="b"] .acct-multi-menu,
html[data-tone="b"] .feed-item,
html[data-tone="b"] .feed-act,
html[data-tone="b"] .lib-card,
html[data-tone="b"] .lib-act,
html[data-tone="b"] .lib-tabs,
html[data-tone="b"] .post-acct,
html[data-tone="b"] .driver-popover.ap-tour,
html[data-tone="b"] .redirect-uri,
html[data-tone="b"] .auth-card,
html[data-tone="b"] .icon-btn,
html[data-tone="b"] .logout-btn,
html[data-tone="b"] .toast,
html[data-tone="b"] .modal-card,
html[data-tone="b"] .modal-close,
html[data-tone="b"] .clip-count-pill,
html[data-tone="b"] #adminUsers .admin-table tr,
html[data-tone="b"] #adminModels .admin-table tr,
html[data-tone="b"] #adminPricing .admin-table tr,
html[data-tone="b"] .side-panel,
html[data-tone="b"] .preview-frame,
html[data-tone="b"] .sched-time,
html[data-tone="b"] .opt-card,
html[data-tone="b"] .dest-opt,
html[data-tone="b"] .dest-opt.goto-accounts:hover,
html[data-tone="b"] .lock-panel,
html[data-tone="b"] .acct-tile,
html[data-tone="b"] .acct-row,
html[data-tone="b"] .acct-lock-card,
html[data-tone="b"] .acct-cta,
html[data-tone="b"] .acct-rowmenu,
html[data-tone="b"] .acct-pick-btn,
html[data-tone="b"] .day-preset,
html[data-tone="b"] .day-circle,
html[data-tone="b"] .sday-track,
html[data-tone="b"] .sday-ghost b,
html[data-tone="b"] .sday-pop,
html[data-tone="b"] .sday-chip:hover,
html[data-tone="b"] .sday-clear:hover,
html[data-tone="b"] .sday-sum,
html[data-tone="b"] .wsp-act,
html[data-tone="b"] .ws-back,
html[data-tone="b"] .btn-back,
html[data-tone="b"] .btn-back:hover,
html[data-tone="b"] .lbl-btn,
html[data-tone="b"] .lbl-btn:hover,
html[data-tone="b"] .ap-more-menu,
html[data-tone="b"] .hero-chip.idle,
html[data-tone="b"] .anchor-mode,
html[data-tone="b"] .ref-refresh,
html[data-tone="b"] .clip-act,
html[data-tone="b"] .slot-chip,
html[data-tone="b"] .ref-actions,
html[data-tone="b"] .ref-frozen,
html[data-tone="b"] .ref-act-solo,
html[data-tone="b"] .cr-hero,
html[data-tone="b"] .cr-card,
html[data-tone="b"] .cr-tip,
html[data-tone="b"] .set-iconbtn:hover,
html[data-tone="b"] .admin-sections,
html[data-tone="b"] .schart-tip,
html[data-tone="b"] .inter-picker,
html[data-tone="b"] .angle-tab,
html[data-tone="b"] .ad-row,
html[data-tone="b"] .ad-caret,
html[data-tone="b"] .ad-caret:hover,
html[data-tone="b"] .seg-pill,
html[data-tone="b"] .seg-pill::before,
html[data-tone="b"] .vary-opt,
html[data-tone="b"] .combo-list,
html[data-tone="b"] .wsp-actions,
html[data-tone="b"] .ref-drop,
html[data-tone="b"] .tab-fab,
html[data-tone="b"] .sty-seg,
html[data-tone="b"] .sty-seg-ind,
html[data-tone="b"] .sty-search,
html[data-tone="b"] .sty-arrange,
html[data-tone="b"] .sty-tag,
html[data-tone="b"] .sty-card,
html[data-tone="b"] .sty-pick,
html[data-tone="b"] .sty-sheet,
html[data-tone="b"] .sty-edit-btn,
html[data-tone="b"] .ws-sheet,
html[data-tone="b"] .ws-sheet-style,
html[data-tone="b"] .home-reel,
html[data-tone="b"] .reel-nav,
html[data-tone="b"] .reel-mute,
html[data-tone="b"] .hstat,
html[data-tone="b"] .trim-sheet,
html[data-tone="b"] .ws-style-card,
html[data-tone="b"] .watch-row,
html[data-tone="b"] .ws-prev-stage,
html[data-tone="b"] .bs-stage,
html[data-tone="b"] .sty-summary,
html[data-tone="b"] .sty-gcard,
html[data-tone="b"] .wsv-hero,
html[data-tone="b"] .wsv-fact,
html[data-tone="b"] .wsv-shape,
html[data-tone="b"] .wsv-screen,
html[data-tone="b"] .wsv-shot,
html[data-tone="b"] .wsv-tile,
html[data-tone="b"] .wsv-track,
html[data-tone="b"] .wsv-chip,
html[data-tone="b"] .mc,
html[data-tone="b"] .mc-att-x,
html[data-tone="b"] .mc-att-cat,
html[data-tone="b"] .mc-pill,
html[data-tone="b"] .mc-u-chip,
html[data-tone="b"] .mc-pop,
html[data-tone="b"] .sty-wchips,
html[data-tone="b"] .sty-ed,
html[data-tone="b"] .wsv-ep,
html[data-tone="b"] .wsv-eps-more > summary,
html[data-tone="b"] .wsv-ep[data-ep]:hover,
html[data-tone="b"] .wsv-epv-end,
html[data-tone="b"] .wsv-take,
html[data-tone="b"] .view-credits .cr-hero,
html[data-tone="b"] .tp-card,
html[data-tone="b"] .tp-covers,
html[data-tone="b"] .tp-buy,
html[data-tone="b"] .tp-method,
html[data-tone="b"] .tp-bar,
html[data-tone="b"] .cr-use,
html[data-tone="b"] .mp-trigger,
html[data-tone="b"] .mp-pop,
html[data-tone="b"] .ooc-meter,
html[data-tone="b"] .ooc-chip,
html[data-tone="b"] .ao-tile,
html[data-tone="b"] .ao-panel,
html[data-tone="b"] .ao-seg,
html[data-tone="b"] .ao-card,
html[data-tone="b"] .ao-worker,
html[data-tone="b"] .ao-brief,
html[data-tone="b"] .fail-banner.bad,
html[data-tone="b"] .fail-banner.warn,
html[data-tone="b"] .ut-wrap,
html[data-tone="b"] .space-btn:hover,
html[data-tone="b"] .space-btn[aria-expanded="true"],
html[data-tone="b"] .space-drop,
html[data-tone="b"] .top-credits,
html[data-tone="b"] .admin-drop,
html[data-tone="b"] .admin-dd-ic,
html[data-tone="b"] .tm-menu,
html[data-tone="b"] .tm-card,
html[data-tone="b"] .al-num,
html[data-tone="b"] .inv-card,
html[data-tone="b"] .pe-row:hover,
html[data-tone="b"] .pe-drawer-x:hover,
html[data-tone="b"] .help-q:hover,
html[data-tone="b"] .btn-ghost:hover,
html[data-tone="b"] .wsp-card:hover,
html[data-tone="b"] .wsp-dormant:hover,
html[data-tone="b"] .ask-photo-preview img,
html[data-tone="b"] .anchor-ai:hover:not(:disabled),
html[data-tone="b"] .wiz-close:hover,
html[data-tone="b"] .provider-row:hover,
html[data-tone="b"] .ico-btn.start:hover,
html[data-tone="b"] .lib-act:hover,
html[data-tone="b"] .driver-popover.ap-tour .driver-popover-prev-btn:hover,
html[data-tone="b"] .icon-btn:hover,
html[data-tone="b"] .modal-close:hover,
html[data-tone="b"] .opt-card:hover,
html[data-tone="b"] .day-preset:hover,
html[data-tone="b"] .day-circle:hover,
html[data-tone="b"] .anchor-mode:hover,
html[data-tone="b"] .ref-refresh:hover,
html[data-tone="b"] .preset-pick-new:hover,
html[data-tone="b"] .ad-x:hover,
html[data-tone="b"] .vary-opt:hover,
html[data-tone="b"] .sty-arrange:hover,
html[data-tone="b"] .sty-card:hover,
html[data-tone="b"] .hstat:hover,
html[data-tone="b"] .gen-sheet img,
html[data-tone="b"] .gen-shot img,
html[data-tone="b"] .wsv-ref img,
html[data-tone="b"] .wsv-days .sday-chip:hover,
html[data-tone="b"] .wsv-eps-more > summary:hover,
html[data-tone="b"] .ao-refs img,
html[data-tone="b"] .tm-ib:hover,
html[data-tone="b"] .tm-card:hover,
html[data-tone="b"] .log-ref-view:hover,
html[data-tone="b"] .lib-cap-pencil:hover,
html[data-tone="b"] .pe-ver-btn:hover,
html[data-tone="b"] .pe-ver-ico:hover,
html[data-tone="b"] .ref-img:hover,
html[data-tone="b"] .head-dd-btn:hover,
html[data-tone="b"] .ws-empty.is-new:hover,
html[data-tone="b"] .anchor-add:hover,
html[data-tone="b"] .lib-act.lib-share:hover,
html[data-tone="b"] .lib-restore:hover,
html[data-tone="b"] .lib-post:hover,
html[data-tone="b"] .ask-cards .ask-other-card:hover,
html[data-tone="b"] .dest-opt.goto-accounts:hover .dest-tag,
html[data-tone="b"] .acct-add:hover,
html[data-tone="b"] .acct-pick-btn:hover,
html[data-tone="b"] .wsp-act:hover:not(:disabled),
html[data-tone="b"] .ws-back:hover,
html[data-tone="b"] #apRunNow:hover:not(:disabled),
html[data-tone="b"] .clip-act.share:hover,
html[data-tone="b"] .angle-tab:hover,
html[data-tone="b"] .home-browse:hover,
html[data-tone="b"] .reel-nav:hover,
html[data-tone="b"] .ws-style-card:hover,
html[data-tone="b"] .ws-style-skip:hover,
html[data-tone="b"] .sty-summary:hover,
html[data-tone="b"] .sty-gcard:hover,
html[data-tone="b"] .mc-drop:hover,
html[data-tone="b"] .mc-att-cat:hover,
html[data-tone="b"] .mc-att-add:hover,
html[data-tone="b"] .mc-pill:hover,
html[data-tone="b"] .mc-u-chip:hover,
html[data-tone="b"] .tp-method:hover,
html[data-tone="b"] .mp-trigger:hover:not(:disabled),
html[data-tone="b"] .ao-dl:hover,
html[data-tone="b"] .ao-card:hover,
html[data-tone="b"] .lib-approve.saving,
html[data-tone="b"] .ad-row.on .ad-tick,
html[data-tone="b"] .ad-row.on .ad-caret,
html[data-tone="b"] .pager-n.on {
  border-color: transparent; }
/* outline-only controls and boxes: become a quiet fill */
html[data-tone="b"] .log-badge,
html[data-tone="b"] .log-thumb,
html[data-tone="b"] .kind-badge,
html[data-tone="b"] .log-scroll,
html[data-tone="b"] .notif-clear,
html[data-tone="b"] .pe-drawer-x,
html[data-tone="b"] .pe-ver-btn,
html[data-tone="b"] .pe-ver-ico,
html[data-tone="b"] .help-q,
html[data-tone="b"] .btn-ghost,
html[data-tone="b"] .anchor-thumb-item,
html[data-tone="b"] .anchor-drop.ai-on,
html[data-tone="b"] .provider-avail,
html[data-tone="b"] .ap-chip,
html[data-tone="b"] .lib-restore,
html[data-tone="b"] .lib-badge,
html[data-tone="b"] .conn-badge,
html[data-tone="b"] .driver-popover.ap-tour .driver-popover-prev-btn,
html[data-tone="b"] .stat,
html[data-tone="b"] .sched-time.first,
html[data-tone="b"] .ask-cards .ask-other-card,
html[data-tone="b"] .dest-opt.goto-accounts .dest-tag,
html[data-tone="b"] .plan-badge,
html[data-tone="b"] .sday-chip,
html[data-tone="b"] .sday-clear,
html[data-tone="b"] .ref-strip-i,
html[data-tone="b"] .ad-x,
html[data-tone="b"] .ad-tick,
html[data-tone="b"] .ad-del,
html[data-tone="b"] .reel-card,
html[data-tone="b"] .qrow-key,
html[data-tone="b"] .wsv-ro,
html[data-tone="b"] .mc-tok.gone,
html[data-tone="b"] .tp-card.on,
html[data-tone="b"] .ao-dl,
html[data-tone="b"] .ao-worker.down,
html[data-tone="b"] .btn-ghost.danger,
html[data-tone="b"] .fail-banner,
html[data-tone="b"] .tm-ib,
html[data-tone="b"] .al-chip {
  border-color: transparent; background-color: rgba(255,255,255,.05); }
/* accent-outlined badges, buttons and panels: accent fill instead of an accent frame */
html[data-tone="b"] .kind-badge.t2v,
html[data-tone="b"] .update-bar,
html[data-tone="b"] .btn-ghost.apply,
html[data-tone="b"] .ref-nrefs,
html[data-tone="b"] .ref-used-tag,
html[data-tone="b"] .lib-post,
html[data-tone="b"] .ask-cards .ask-other-cell:has(input:not(:placeholder-shown)),
html[data-tone="b"] .dest-opt .dest-tag,
html[data-tone="b"] .acct-tile.accent,
html[data-tone="b"] .acct-pill,
html[data-tone="b"] .acct-hero,
html[data-tone="b"] .acct-av,
html[data-tone="b"] .lbl-btn.primary,
html[data-tone="b"] .ws-style-tag,
html[data-tone="b"] .hero-chip,
html[data-tone="b"] .hstat.live,
html[data-tone="b"] .ws-style-chosen,
html[data-tone="b"] .cfg-season,
html[data-tone="b"] .ao-worker.busy,
html[data-tone="b"] .tm-announce,
html[data-tone="b"] .auth-invite {
  border-color: transparent; background-color: var(--accent-weak); }
/* a selected thing: the ring is the mark, drawn inside so nothing shifts */
html[data-tone="b"] .lib-cap-edit.editing,
html[data-tone="b"] .pe-row.on,
html[data-tone="b"] .ref-item.on,
html[data-tone="b"] .anchor-drop.dragover,
html[data-tone="b"] .anchor-drop.filled,
html[data-tone="b"] .anchor-ai.on,
html[data-tone="b"] .dropzone.dragover,
html[data-tone="b"] .provider-row.on,
html[data-tone="b"] .target-acct:has(input:checked),
html[data-tone="b"] .post-acct:has(input:checked),
html[data-tone="b"] .lib-card.playing,
html[data-tone="b"] .opt-card.on,
html[data-tone="b"] .dest-opt.active,
html[data-tone="b"] .acct-row.current,
html[data-tone="b"] .sday-chip.on,
html[data-tone="b"] .feed-item.playing,
html[data-tone="b"] .slot-chip.next,
html[data-tone="b"] .ad-row.on,
html[data-tone="b"] .vary-opt.on,
html[data-tone="b"] #styArrange.on,
html[data-tone="b"] .ws-style-card.on,
html[data-tone="b"] .sty-summary[aria-expanded="true"],
html[data-tone="b"] .sty-gcard.on,
html[data-tone="b"] .wsv-days .sday-chip.on:hover,
html[data-tone="b"] .mc.dragover,
html[data-tone="b"] .lib-card.lib-focus,
html[data-tone="b"] .tp-card.tone-best,
html[data-tone="b"] .mp-trigger[aria-expanded="true"],
html[data-tone="b"] .ao-tile.hi,
html[data-tone="b"] .al-chip.on {
  border-color: transparent; box-shadow: 0 0 0 1.5px var(--accent); }
/* END GENERATED */

/* What the scan cannot see: */
/* a search box's own <input> must not draw a second box inside the wrapper */
html[data-tone="b"] :is(.ws-search, .lib-search, .sty-search, .ref-search) input { background: transparent; border: 0; box-shadow: none; }
/* the Admin tab when on an admin page: the one accent, like every other tab */
html[data-tone="b"] .toptab-admin.active { color: var(--accent); }
/* the admin menu's icon squares */
html[data-tone="b"] .admin-dd-ic { border-color: transparent; background: var(--surface); }
html[data-tone="b"] .admin-drop { background: var(--float); box-shadow: var(--float-shadow); }
/* primary actions that were a flat accent: the same gradient as every primary button */
html[data-tone="b"] :is(.sty-use-btn, .lbl-btn.primary, .wsv-epv-watch, .tp-pay.brand) {
  background: linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%); color: var(--on-accent);
  border-color: transparent; box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); }
/* little round icon buttons over media (carousel mute, arrows): fill, no ring */
html[data-tone="b"] :is(.reel-nav, .reel-mute, .home-mute, .sty-sheet-sound) { border-color: transparent; }
/* left after the scan (found by a computed-style sweep of every page): tag pills and status badges
   that drew a tinted ring, and the workspace avatar's hairline */
html[data-tone="b"] .lib-ws { border-color: transparent; }
html[data-tone="b"] .status-badge { border-color: transparent; }
html[data-tone="b"] .wsp-avatar { border-color: transparent; }
/* the setup page's style preview: its frame is gone, but the stage's own gradient showed through the
   now-clear 1px edge around the picture — clip the fill inside the edge */
html[data-tone="b"] .bs-stage { background-clip: padding-box; border-width: 0; }
/* credits page: the boxed italic mono kicker becomes a plain small label; the balance card's
   gradient no longer shows through its cleared edge */
html[data-tone="b"] .view-credits .cr-kicker { background: none; padding: 0; transform: none; font-weight: 500; font-style: normal; font-family: var(--font-sans);
  font-size: 12px; letter-spacing: .02em; text-transform: none; color: var(--text-muted); border: 0; }
html[data-tone="b"] .cr-hero { background-clip: padding-box; border-width: 0; }
/* the style sheet's Edit: a secondary button is a fill */
html[data-tone="b"] .sty-edit-btn { border-color: transparent; background: rgba(255,255,255,.06); color: var(--text); }
html[data-tone="b"] .sty-edit-btn:hover { background: rgba(255,255,255,.1); }

/* ============================== ADD REFERENCES DIALOG (refpicker.js) ==============================
   THE WHOLE LOOK OF THE DIALOG IS THIS ONE SECTION, and only these class names are used by its
   markup (refpicker.js shellHtml / tileHtml), so the look can change without touching behaviour.
   Also here: the "Fresh every run" card the composer strip shows for an AI description, and the
   admin Assets thumbnail.
   LOOK B, THE SIDE DRAWER (owner, 2026-10-14): a panel from the right edge with the page still in
   view under a light dim; underlined tabs with the logo gradient under the open one; the New image
   box one line until clicked; three columns of 3:4 tiles; the footer fades over them. Fills, not
   frames — nothing here draws a border except the dashed Upload tile. */
.rp-overlay { position: fixed; inset: 0; z-index: 260; background: rgba(3,4,8,0); transition: background .25s ease; }
.rp-overlay.in { background: rgba(3,4,8,.42); }
.rp { position: absolute; top: 0; right: 0; bottom: 0; width: min(520px, 100%); display: flex; flex-direction: column;
  background: var(--surface); box-shadow: -24px 0 64px rgba(0,0,0,.55);
  transform: translateX(100%); transition: transform .32s cubic-bezier(.16,1,.3,1); }
.rp-overlay.in .rp { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .rp-overlay, .rp { transition: none; }
}
.rp-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 20px 20px 12px; }
.rp-head h3 { margin: 0; font: 700 18px/1.2 var(--font-display); letter-spacing: -.01em; }
.rp-close { width: 32px; height: 32px; flex: none; display: grid; place-items: center; border: 0; border-radius: 50%;
  background: rgba(255,255,255,.06); color: var(--text-muted); cursor: pointer; }
.rp-close:hover { color: var(--text); background: rgba(255,255,255,.1); }
.rp-close svg { width: 14px; height: 14px; }
.rp-tabs { display: flex; gap: 22px; padding: 0 20px; border-bottom: 1px solid rgba(255,255,255,.06); }
.rp-tab { position: relative; display: inline-flex; align-items: center; gap: 6px; padding: 10px 0 12px; border: 0;
  background: none; color: var(--text-muted); font: 600 13.5px var(--font-sans); cursor: pointer; }
.rp-tab:hover { color: var(--text); }
.rp-tab.on { color: var(--text); }
.rp-tab.on::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; border-radius: 2px;
  background: linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%); }
.rp-tab em { font-style: normal; font-size: 11px; font-weight: 600; color: var(--text-faint); }
.rp-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 20px 0; }
.rp-chip { border: 0; border-radius: var(--r-pill); padding: 4px 12px; font: 600 12px var(--font-sans);
  background: rgba(255,255,255,.06); color: var(--text-muted); cursor: pointer; }
.rp-chip.on { background: var(--accent-weak); color: var(--text); }
.rp-create { padding: 16px 20px 4px; }
.rp-collapsed { width: 100%; display: flex; align-items: center; gap: 10px; padding: 12px 14px; border: 0; border-radius: 12px;
  background: rgba(255,255,255,.05); color: var(--text-faint); font: 14px var(--font-sans); text-align: left; cursor: text; }
.rp-collapsed:hover { background: rgba(255,255,255,.07); }
.rp-spark { display: grid; color: var(--accent); }
.rp-spark svg { width: 16px; height: 16px; }
.rp-open { display: none; }
.rp-create.is-open .rp-collapsed { display: none; }
.rp-create.is-open .rp-open { display: block; }
.rp-desc { display: block; width: 100%; resize: none; padding: 12px 14px; border: 0; border-radius: 12px;
  background: rgba(255,255,255,.05); color: var(--text); font: 14px/1.55 var(--font-sans); }
.rp-desc::placeholder { color: var(--text-faint); }
.rp-desc:focus { outline: none; box-shadow: 0 0 0 3px var(--accent-weak); }
.rp-row { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.rp-sp { flex: 1; }
.rp-keep { display: inline-flex; align-items: center; gap: 10px; min-width: 0; font-size: 12.5px; color: var(--text-muted); }
.rp-switch { position: relative; flex: none; width: 36px; height: 20px; border: 0; border-radius: var(--r-pill);
  background: rgba(255,255,255,.12); cursor: pointer; }
.rp-switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; transition: transform .2s cubic-bezier(.16,1,.3,1); }
.rp-switch.on { background: var(--accent); }
.rp-switch.on::after { transform: translateX(16px); }
.rp-cost { font-size: 12.5px; color: var(--text-muted); white-space: nowrap; }
.rp-cost b { color: var(--text); font-weight: 600; }
.rp-go { white-space: nowrap; }
/* grid-auto-rows: max-content — a grid that is itself a fixed-height scroll box squeezes its rows
   to fit when there are many (272 uploads collapsed every row to 8px and the tiles piled up), because
   an aspect-ratio tile with overflow:hidden has no minimum height. max-content keeps each row its
   tile's real height and lets the box scroll. */
.rp-grid { flex: 1; min-height: 0; overflow: auto; padding: 14px 20px 24px; display: grid; align-content: start;
  grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: max-content; gap: 8px; }
.rp-lh { grid-column: 1 / -1; margin: 0 2px 2px; font-size: 12.5px; color: var(--text-faint); }
.rp-tile, .rp-upl { position: relative; aspect-ratio: 3 / 4; border-radius: 12px; overflow: hidden; cursor: pointer; }
.rp-tile { padding: 0; border: 0; text-align: left; color: var(--text); background: var(--surface-2);
  transition: transform .2s cubic-bezier(.16,1,.3,1); }
.rp-tile:hover:not(:disabled) { transform: translateY(-2px); }
.rp-im { position: absolute; inset: 0; }
.rp-im img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rp-im-desc { display: flex; align-items: center; padding: 34px 12px 30px; font-size: 12px; line-height: 1.45; color: var(--text-muted);
  background: linear-gradient(160deg, var(--accent-weak), transparent 70%); }
.rp-im-desc span { display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; }
.rp-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 22px 9px 8px; font-size: 11px; line-height: 1.35;
  color: rgba(255,255,255,.88); background: linear-gradient(transparent, rgba(0,0,0,.72));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-tag { position: absolute; top: 8px; left: 8px; max-width: calc(100% - 40px); font-size: 10.5px; font-weight: 600;
  padding: 2px 8px; border-radius: var(--r-pill); background: rgba(12,12,14,.72); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-tile.sel { box-shadow: inset 0 0 0 2px var(--accent); }
.rp-tile.sel::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 2px var(--accent); }
.rp-ck { position: absolute; top: 8px; right: 8px; z-index: 2; width: 22px; height: 22px; border-radius: 50%; display: none;
  place-items: center; background: var(--accent); color: var(--on-accent); }
.rp-ck svg { width: 12px; height: 12px; }
.rp-tile.sel .rp-ck { display: grid; }
.rp-tile.drawing { cursor: progress; }
.rp-tile.drawing .rp-cap { background: none; color: var(--text-muted); }
.rp-upl { display: grid; place-items: center; padding: 8px; text-align: center; font: 12.5px/1.4 var(--font-sans);
  color: var(--text-muted); background: none; border: 1.5px dashed var(--border-strong); }
.rp-upl b { display: block; color: var(--text); font-size: 13.5px; font-weight: 600; }
.rp-upl:hover { border-color: var(--accent); }
.rp-empty { grid-column: 1 / -1; padding: 48px 12px; text-align: center; color: var(--text-muted); font-size: 13px; }
/* The footer sits over the end of the grid, so the last row scrolls under a fade, not a hard edge. */
.rp-foot { position: relative; z-index: 1; display: flex; align-items: center; gap: 12px; margin-top: -24px; padding: 24px 20px 20px;
  background: linear-gradient(transparent, var(--surface) 30%); }
.rp-hint { flex: 1; min-width: 0; display: grid; gap: 1px; font-size: 12.5px; color: var(--text-faint); }
/* The ticks are the workspace's references, so the footer says how many it has — not a pending
   count of things that might still be lost. */
.rp-count { color: var(--text); font-weight: 600; }
.rp-hint-k { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Taking out an image the brief names: said where it happened, and still done. */
.rp-warn { position: relative; z-index: 2; margin: 0 20px -8px; padding: 8px 12px; border-radius: 10px;
  font-size: 12.5px; color: var(--text); background: var(--warn-weak); }
.rp-team { display: inline-flex; gap: 6px; align-items: center; }
.rp-team-sel { max-width: 140px; padding: 8px 10px; border-radius: 10px; border: 0; background: rgba(255,255,255,.06); color: var(--text); }
html[data-tone="b"] .rp { background: #1C1C20; }
html[data-tone="b"] .rp-foot { background: linear-gradient(transparent, #1C1C20 30%); }
@media (max-width: 720px) {
  .rp { width: 100vw; }
  /* The switch takes its own line; the cost and the button share the next, at the right. */
  .rp-row { flex-wrap: wrap; row-gap: 10px; }
  .rp-keep { flex: 1 0 100%; }
  .rp-desc { font-size: 16px; }    /* 16px: iOS zooms into anything smaller */
}
/* The composer strip's card for an AI image drawn every run, and the Edit references row's tile. */
.mc-att-desc { display: flex; align-items: center; padding: 6px; font-size: 10px; line-height: 1.3; color: var(--text-muted);
  background: linear-gradient(160deg, var(--accent-weak), var(--surface-2) 75%); cursor: default; }
.mc-att-desc span { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.mc-att-every { font-size: 10px; font-weight: 600; color: var(--accent); white-space: nowrap; }
.anchor-ai-tile.is-desc { color: var(--accent); }
.aa-thumb { width: 44px; height: 44px; object-fit: cover; border-radius: 8px; display: block; }
/* "EVERY RUN" / "EVERY STORY": the References page's corner ribbon (.ref-mark .rm-used), on a
   description that is drawn afresh each time — in the drawer and in the composer's strip. The
   words are longer than "USED", so the corner is bigger and the type smaller. */
/* A BAND, NOT A TRIANGLE: "EVERY STORY" is three times "USED", and a triangle big enough to hold
   it covered half a strip thumbnail. Same fill, same type; the band crosses the corner instead. */
.ref-mark.rp-ribbon { width: 76px; height: 76px; z-index: 2; border-top-right-radius: 12px; overflow: hidden; }
.ref-mark.rp-ribbon i { inset: auto; top: 16px; right: -30px; width: 110px; height: 17px; clip-path: none;
  transform: rotate(45deg); display: grid; place-items: center; box-shadow: 0 2px 6px rgba(0,0,0,.35); }
.ref-mark.rp-ribbon i b { position: static; transform: none; font-size: .5rem; letter-spacing: .05em; }
.mc-att .ref-mark.rp-ribbon { width: 62px; height: 62px; border-top-right-radius: 10px; }
.mc-att .ref-mark.rp-ribbon i { top: 11px; right: -32px; width: 104px; height: 14px; }
.mc-att .ref-mark.rp-ribbon i b { font-size: .4rem; }
/* The strip's description card: the words start below the band, so it never covers them. */
.mc-att-ai .mc-att-desc { align-items: flex-end; padding: 24px 6px 6px; }
.mc-att-ai .mc-att-desc span { -webkit-line-clamp: 3; }
/* Its line under the card wraps inside the card's width: one line of it ran under the next card. */
.mc-att-ai .mc-att-every { white-space: normal; line-height: 1.25; max-width: 100%; }
/* The workspace page's strip and the workspace view: a description card in the same spot. */
.ref-strip-i.is-desc { display: flex; align-items: flex-end; padding: 22px 5px 5px; background: var(--accent-weak); }
.ref-strip-desc, .wsv-ref-desc { font-size: 9.5px; line-height: 1.3; color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.ref-strip-i .ref-mark.rp-ribbon, .wsv-ref .ref-mark.rp-ribbon { width: 58px; height: 58px; border-top-right-radius: 9px; }
.ref-strip-i .ref-mark.rp-ribbon i, .wsv-ref .ref-mark.rp-ribbon i { top: 10px; right: -32px; width: 100px; height: 13px; }
.ref-strip-i .ref-mark.rp-ribbon i b, .wsv-ref .ref-mark.rp-ribbon i b { font-size: .38rem; }
.wsv-ref.is-desc .wsv-ref-desc { box-sizing: border-box; width: 68px; height: 68px; padding: 22px 5px 5px; border-radius: 10px;
  display: -webkit-box; background: var(--accent-weak); }
.wsv-ref .ref-mark.rp-ribbon { left: calc(50% - 34px + 68px - 58px); right: auto; }
/* References page: an image a run drew from a per-run description. */
.ref-cell.is-per-run .ref-img { border: 0; }
.ref-run-tag { position: absolute; left: 6px; bottom: 6px; z-index: 2; padding: 2px 7px; border-radius: var(--r-pill);
  font-size: 10px; font-weight: 600; color: var(--text); background: rgba(12,12,14,.72); }
.ref-cell.is-per-run > .zoom-btn { top: 6px; left: 6px; }
/* THUMBNAILS TOO SMALL FOR A BAND (Edit references' 42px tiles, Admin's 32px ones): the same
   words and fill, as a strip across the foot of the picture. */
:is(.anchor-ai-tile, .ao-ref) .ref-mark.rp-ribbon { inset: auto 0 0 0; width: auto; height: 11px; border-radius: 0 0 8px 8px; }
:is(.anchor-ai-tile, .ao-ref) .ref-mark.rp-ribbon i { inset: 0; top: 0; right: 0; width: auto; height: 11px; transform: none; box-shadow: none; }
:is(.anchor-ai-tile, .ao-ref) .ref-mark.rp-ribbon i b { font-size: 6.5px; letter-spacing: .02em; }
.ao-ref { position: relative; }
.ao-refs.sm .ao-ref .ref-mark.rp-ribbon { border-radius: 0 0 6px 6px; }
/* The ribbon has the corner, so a description card's check moves to the other one. */
.rp-tile:has(.rp-ribbon) .rp-ck { right: auto; left: 8px; }
.rp-im-desc { flex-direction: column; align-items: flex-start; justify-content: center; gap: 8px; }
.rp-im-desc small { font-size: 11px; font-weight: 600; color: var(--accent); }
.rp-fresh-note { margin: 8px 2px 0; font-size: 12px; color: var(--text-faint); }
/* A draw that failed: said on the tile, refunded, removable. */
.rp-fail-im { display: grid; place-items: center; padding: 10px; text-align: center; font-size: 11px; line-height: 1.35;
  color: var(--danger); background: var(--danger-weak); }
.rp-tile.failed { cursor: default; }
/* The composer strip's placeholder while an image draws, the same size as a photo. */
.mc-att-draw .mc-att-img { position: relative; display: grid; place-items: center; font-size: 11px; color: var(--text-muted); cursor: progress; }
.mc-att-draw .mc-att-img.is-drawing { place-items: end center; }
.mc-att-draw .is-drawing .mc-draw-cap { position: relative; z-index: 1; padding-bottom: 6px; font-size: 10px; }
/* Edit references: a draw in progress takes its place in the row. */
.anchor-thumb-item.is-drawing { position: relative; overflow: hidden; }
.mc-att-draw.failed .mc-att-img { cursor: default; font-size: 10px; padding: 6px; }
.mc-att-draw .mc-att-n { cursor: default; }
/* The last setup step, while a reference image is still drawing: a note, never a wait. */
.rp-draw-note { margin: 0 0 12px; padding: 9px 12px; border-radius: 10px; font-size: 12.5px; color: var(--text-muted);
  background: var(--accent-weak); }

/* ---- Something is being made (core.js drawAnim; owner 2026-10-15, option C) ----------------------
   The Muse mark as a mask, faint at rest; the brand gradient fills it from the bottom like ink over
   2.8 s, fades, and starts again, while flowing sideways. It replaces the grey shimmer on every
   tile where an AI image is drawing, and the empty poster wherever a clip is being made. Only
   clip-path, opacity and background-position move. */
.draw-anim { position: absolute; inset: 0; display: block; background: #141418; overflow: hidden; pointer-events: none; }
.draw-logo { position: absolute; left: 50%; top: 44%; transform: translate(-50%, -50%);
  width: 46%; min-width: 30px; max-width: 132px; aspect-ratio: 240 / 167; background: rgba(255,255,255,.08);
  -webkit-mask: url(/logo-mark.png?v=4) center / contain no-repeat; mask: url(/logo-mark.png?v=4) center / contain no-repeat; }
.draw-logo::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%, #7FC4FF 150%); background-size: 200% 100%;
  clip-path: inset(100% 0 0 0);
  animation: drawFill 2.8s cubic-bezier(.45, 0, .2, 1) infinite, drawFlow 3s linear infinite; }
@keyframes drawFill { 0% { clip-path: inset(100% 0 0 0); opacity: 1; } 70% { clip-path: inset(0 0 0 0); opacity: 1; }
  100% { clip-path: inset(0 0 0 0); opacity: 0; } }
@keyframes drawFlow { to { background-position: -200% 0; } }
html.tab-hidden .draw-logo::after { animation-play-state: paused; }
/* Still, half filled: it says "being made" without moving. */
@media (prefers-reduced-motion: reduce) {
  .draw-logo::after { animation: none; clip-path: inset(50% 0 0 0); opacity: 1; }
}
/* Wide video placeholders (a 16:9 run, a table row) keep the mark the same size as a tall one. */
.draw-anim.is-wide .draw-logo { width: 26%; top: 50%; }
.draw-anim.is-tiny .draw-logo { width: 62%; min-width: 0; top: 50%; }
/* Where it stands in for a clip being made: the Home card's picture, the workspace page's hero
   (at the workspace's shape, set inline), and Admin → Videos' thumbnail. */
.wsp-avatar.is-making { position: relative; overflow: hidden; }
/* The hero's left column folds away with a hidden orb (above); while something is being made it
   holds the animation instead, so it stays. */
.card.hero .hero-left:has(> .hero-making) { display: block; }
.hero-making { position: relative; display: block; width: 64px; max-height: 120px; border-radius: 12px; overflow: hidden;
  aspect-ratio: 9 / 16; }
.ao-noth.is-making, .ao-th .ao-noth.is-making { position: relative; overflow: hidden; }
.ao-th .ao-noth.is-making { position: absolute; inset: 0; width: auto; height: auto; }

/* ---- See the whole image (core.js zoomButton, owner 2026-10-15) ------------------------------
   One small round magnifier on every reference thumbnail, top-left — clear of the selection
   check, the USED / EVERY RUN ribbon and the remove × (all top-right). Shown on hover or focus
   where there is a pointer; always where there is not. The lightbox shows the whole picture at
   its own shape (.img-zoom). */
.zoom-btn { position: absolute; top: 6px; left: 6px; z-index: 3; width: 24px; height: 24px; padding: 0; display: grid;
  place-items: center; border: 0; border-radius: 50%; background: rgba(12,12,14,.66); color: #fff; cursor: zoom-in;
  opacity: 0; transition: opacity .15s, background .15s; backdrop-filter: blur(4px); }
.zoom-btn svg { width: 13px; height: 13px; }
.zoom-btn:hover { background: rgba(12,12,14,.86); }
:is(.rp-tile, .mc-att, .anchor-thumb-item, .ref-cell, .ref-chain-step, .gen-sheet, .gen-shot, .ref-strip-i, .wsv-ref, .ao-ref):is(:hover, :focus-within) > .zoom-btn,
.zoom-btn:focus-visible { opacity: 1; }
@media (hover: none) { .zoom-btn { opacity: 1; } }
:is(.ref-chain-step, .gen-sheet, .gen-shot, .wsv-ref, .ao-ref) { position: relative; }
.ao-ref { display: inline-block; }
/* In the drawer the top-left holds a tile's tag; the magnifier sits bottom-right, over the caption. */
.rp-tile > .zoom-btn { top: auto; left: auto; right: 7px; bottom: 7px; }
.rp-tile:has(> .zoom-btn) .rp-cap { padding-right: 36px; }
/* Thumbnails too small for a 24px button get a smaller one. */
:is(.anchor-thumb-item, .ao-ref, .ref-strip-i) > .zoom-btn { top: 2px; left: 2px; width: 18px; height: 18px; }
:is(.anchor-thumb-item, .ao-ref, .ref-strip-i) > .zoom-btn svg { width: 10px; height: 10px; }
.wsv-ref > .zoom-btn { left: calc(50% - 30px); top: 4px; }
.img-zoom img { object-fit: contain; }


/* ---- Setup: the style card (owner, 2026-10-15, option B) ------------------------------------
   The style was on screen three times: the panel, a caption under it, and a STYLE pill in the
   box's footer. Now the card beside the box is the only place, and the two are the SAME HEIGHT:
   the grid stretches both, the box grows to a tall film, the card grows to a long brief. No
   fixed heights anywhere; the film is laid over its stage, so it never sets the height itself. */
/* A CEILING ON THE ROW (owner, 2026-10-15): a 1,500-character brief made the row ~700px and the
   card a tall strip. Both columns are capped at what fits between the title and the Next bar
   (on a 900px screen, 900 - 240 = 660), never under 460; the brief scrolls inside its own box
   (at most ~14 lines, 420px) instead of growing the page. max-height on the two grid items also
   caps their contribution to the row, so the stretch still makes them equal. */
@media (min-width: 901px) {
  .view-ask .home-grid:has(#briefRail:not(.hidden)) {
    grid-template-columns: minmax(0, 340px) minmax(0, 1fr); align-items: stretch;
    --setup-row-max: max(460px, calc(100vh - 240px)); }
  #briefRail { align-self: stretch; }
  .view-ask .home-grid:has(#briefRail:not(.hidden)) > #briefRail,
  .view-ask .home-grid:has(#briefRail:not(.hidden)) > .brief-col { max-height: var(--setup-row-max); }
}
/* The right column hands its height to the box, and the box to its editor, which is the one part
   that gives way (min-height:0 down the chain) when the row is at its ceiling. */
.view-ask .brief-col { display: flex; flex-direction: column; gap: 20px; min-height: 0; }
.view-ask #briefCard { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.view-ask #briefCard > .mc { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.view-ask #briefCard > .mc > .mc-edit { flex: 1 1 auto; min-height: 96px; max-height: 420px; overflow-y: auto; }
.view-ask #briefCard > .mc > .mc-foot { margin-top: auto; }

#briefRail.brief-side { display: flex; flex-direction: column; gap: 12px; padding: 14px; min-width: 0; }
#briefRail .bs-eyebrow { font: 500 12.5px/1.4 var(--font-sans); letter-spacing: 0; text-transform: none;
  color: var(--text-muted); }
#briefRail .bs-eyebrow:empty, #briefRail.is-brief .bs-eyebrow { display: none; }
#briefRail .bs-stagebox { position: relative; flex: 1 1 auto; display: flex; flex-direction: column; min-height: 220px; }
#briefRail .bs-stage { position: relative; flex: 1 1 auto; min-height: 220px; aspect-ratio: auto;
  display: flex; flex-direction: column; }
#briefRail .bs-stage > .ws-prev-none { position: absolute; inset: 0; width: 100%; height: 100%; }
/* THE FILM AT ITS OWN RATIO (home.js paintFilm sets --ar from the file). The stage is a size
   container, so the film is the largest box of that ratio that fits it: contain, done in layout
   rather than with object-fit, so the element IS the picture and nothing is stretched. The spare
   room is the same poster, blurred and dimmed. */
#briefRail .bs-stage.has-film { container-type: size; align-items: center; justify-content: center;
  overflow: hidden; background: #08080A; }
#briefRail .bs-stage .bs-bg { position: absolute; inset: -32px; width: calc(100% + 64px); height: calc(100% + 64px);
  max-width: none; object-fit: cover; filter: blur(26px) brightness(.42) saturate(1.15); pointer-events: none; }
#briefRail .bs-stage .bs-film { position: relative; z-index: 1; display: block; flex: none;
  width: min(100cqw, calc(100cqh * var(--ar, .5625))); height: min(100cqh, calc(100cqw / var(--ar, .5625)));
  object-fit: cover; border-radius: 8px; box-shadow: 0 10px 30px rgba(0, 0, 0, .45); }
/* Several styles ticked: their films take turns, each at its own shape over the same dark stage. */
#briefRail .bs-stage.auto-reel .ar-layer { object-fit: contain; background: #08080A; }

/* The card is one big button (role=button). No button inside it (the Style pill says the same):
   the cue is a slight lift and a brighter fill on hover / focus, and a "Change style" label that
   fades in over the bottom of the picture. On touch there is no hover, so a small "Tap to change"
   sits in the corner instead. */
#briefRail { cursor: pointer; transition: border-color .15s, background-color .15s, box-shadow .2s, transform .2s; }
#briefRail:hover, #briefRail:focus-visible { transform: translateY(-2px); border-color: var(--accent-border);
  box-shadow: 0 12px 28px -14px rgba(0, 0, 0, .7); }
#briefRail:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
html[data-tone="b"] #briefRail:hover, html[data-tone="b"] #briefRail:focus-visible { background-color: rgba(255, 255, 255, .03); }
#briefRail .bs-cue { position: absolute; z-index: 3; left: 50%; bottom: 12px; pointer-events: none;
  padding: 6px 13px; border-radius: var(--r-pill, 999px); background: rgba(12, 12, 14, .74);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); color: #F2F2F4;
  font: 600 12.5px/1.2 var(--font-sans); white-space: nowrap;
  opacity: 0; transform: translate(-50%, 4px); transition: opacity .18s ease, transform .18s ease; }
#briefRail:hover .bs-cue, #briefRail:focus-visible .bs-cue { opacity: 1; transform: translate(-50%, 0); }
#briefRail .bs-cue .cue-touch { display: none; }
#briefRail .bs-cue-row { display: none; }
@media (hover: none) {
  #briefRail .bs-cue { left: auto; right: 10px; bottom: 10px; transform: none; opacity: 1;
    padding: 4px 9px; font-size: 11.5px; font-weight: 500; color: rgba(242, 242, 244, .82); }
  #briefRail .bs-cue .cue-hover { display: none; }
  #briefRail .bs-cue .cue-touch { display: inline; }
  #briefRail:hover, #briefRail:focus-visible { transform: none; }
}
@media (prefers-reduced-motion: reduce) { #briefRail, #briefRail .bs-cue { transition: none; } #briefRail:hover { transform: none; } }
#briefRail .bs-pick { border-top: 0; padding-top: 0; }
#briefRail .bs-thumb { display: none; }
#briefRail .bs-txt > span { font-size: 12.5px; }
/* Follow my brief: the stage is the whole card (no name row under it, the card says it). */
#briefRail.is-brief .bs-pick { display: none; }
/* Follow my brief: laid out to fill the card, not a short block over empty space. The name and
   what it means, then its three promises, centred in the card. */
#briefRail .bs-brief-led { flex: 1 1 auto; height: auto; justify-content: center; gap: 14px; padding: 26px 22px; }
#briefRail .bs-brief-led b { font-size: 1.5rem; line-height: 1.15; }
.bs-bl-ico { width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center;
  background: var(--accent-weak); color: var(--accent); }
.bs-bl-ico svg { width: 22px; height: 22px; }
#briefRail .bs-brief-led .bs-bl-sub { font-size: 14px; line-height: 1.5; color: var(--text-muted); }
.bs-bl-list { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 10px; }
.bs-bl-list li { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--text); }
.bs-bl-list li::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.bs-thumb-ico { width: 100%; height: 100%; display: grid; place-items: center;
  background: var(--accent-weak); color: var(--accent); }
.bs-thumb-ico svg { width: 22px; height: 22px; }

/* Phone: the card is one row ABOVE the box (thumb, name, one line, the button). The film and the
   Follow my brief card are desktop's; a 390px screen keeps its height for the brief. */
@media (max-width: 900px) {
  #briefRail { order: 0; }
  #briefRail.brief-side { flex-direction: row; padding: 10px 12px; }
  #briefRail .bs-eyebrow, #briefRail .bs-stagebox { display: none; }
  #briefRail .bs-pick, #briefRail.is-brief .bs-pick { display: flex; flex: 1 1 auto; min-width: 0; }
  /* The cue sits at the row's end here, not over a picture. */
  #briefRail .bs-cue.bs-cue-row { display: block; position: static; transform: none; flex: none; margin-left: auto;
    align-self: center; background: none; padding: 0; color: var(--text-muted); font-weight: 500; }
  #briefRail:hover .bs-cue.bs-cue-row, #briefRail:focus-visible .bs-cue.bs-cue-row { transform: none; }
  #briefRail .bs-thumb { display: block; width: 46px; }
  #briefRail .bs-thumb:empty { display: none; }
  #briefRail .bs-txt, #briefRail.is-brief .bs-txt { display: grid; flex: 1 1 auto; }
  #briefRail .bs-txt > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* CHOOSE A STYLE, as a sheet (index.html #styleSheet, home.js openStyleSheet). Centred on desktop,
   from the bottom on a phone; above the Next bar (z 40) because both sit in the same view. */
.stp-sheet { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; }
.stp-sheet-scrim { position: absolute; inset: 0; background: rgba(6, 6, 10, .64); animation: stpSheetFade .18s ease; }
.stp-sheet-panel { position: relative; display: flex; flex-direction: column; width: min(880px, 100%);
  max-height: min(86vh, 880px); overflow: hidden; border-radius: 16px; background: var(--surface);
  border: 1px solid var(--border-strong); box-shadow: 0 30px 80px rgba(0, 0, 0, .6);
  animation: stpSheetPop .26s cubic-bezier(.16, 1, .3, 1); }
.stp-sheet-head { display: flex; align-items: center; gap: 12px; padding: 16px 18px 10px; }
.stp-sheet-head h3 { flex: 1; margin: 0; font-family: var(--font-display); font-size: 20px; font-weight: 650; }
.stp-sheet-x { width: 34px; height: 34px; padding: 0; border: 0; border-radius: 50%; background: var(--surface-2);
  color: var(--text-muted); font-size: 20px; line-height: 1; cursor: pointer; }
.stp-sheet-x:hover { color: var(--text); }
.stp-sheet-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 2px 18px 18px; }
.stp-sheet-foot { display: flex; align-items: center; gap: 12px; padding: 12px 18px; border-top: 1px solid var(--border); }
.stp-sheet-note { flex: 1 1 auto; min-width: 0; font-size: 12.5px; color: var(--text-muted); }
.stp-sheet-foot .btn-neon { flex: none; }
/* In the sheet the wall is the whole point: its own open/close row would be a second title. */
#styleSheet .sty-summary { display: none; }
#styleSheet .sty-wchips { margin-top: 0; }
#styleSheet .sty-gasks { font-family: var(--font-sans); font-size: 11.5px; letter-spacing: 0; }
html.sheet-open, html.sheet-open body { overflow: hidden; }
@keyframes stpSheetFade { from { opacity: 0; } }
@keyframes stpSheetPop { from { opacity: 0; transform: translateY(10px) scale(.985); } }
@keyframes stpSheetUp { from { transform: translateY(40px); opacity: 0; } }
@media (max-width: 900px) {
  .stp-sheet { place-items: end stretch; padding: 0; }
  .stp-sheet-panel { width: 100%; max-height: 88vh; max-height: 88dvh; border-radius: 16px 16px 0 0; border-bottom: 0;
    padding-bottom: env(safe-area-inset-bottom); animation-name: stpSheetUp; }
  .stp-sheet-head { padding: 14px 16px 8px; }
  .stp-sheet-body { padding: 2px 16px 16px; }
  .stp-sheet-foot { padding: 10px 16px; }
  #styleSheet .sty-gwall { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) { .stp-sheet-scrim, .stp-sheet-panel { animation: none; } }
html[data-tone="b"] .stp-sheet-panel { background: #18181B; border-color: transparent; }
html[data-tone="b"] .stp-sheet-foot { border-top-color: rgba(255, 255, 255, .05); }

/* THE STYLE PILL, dressed exactly as the Model one beside it (.mp-trigger): same height, border,
   type and caret; a 20px mark in front (the style's poster, or the sparkle for Follow my brief). */
.mc-pill.mc-style { height: 32px; padding: 0 12px 0 8px; gap: 8px; max-width: 320px;
  font: 600 12.5px var(--font-sans); }
.mc-pill.mc-style:hover { border-color: var(--accent-border); }
/* A <label>, so it took the form-label 6px bottom margin and sat 3px above the Style pill. */
.mc-foot > #mcModelPill { margin: 0; }
.mc-style-ico { flex: none; width: 20px; height: 20px; border-radius: 50%; overflow: hidden; display: grid;
  place-items: center; color: var(--accent); }
.mc-style-ico img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mc-style-ico svg { width: 16px; height: 16px; }
@media (max-width: 760px) { .mc-pill.mc-style { max-width: 220px; } }

/* Readable labels in the box's footer and menus, not 9.5px mono capitals. */
.mc-keys { font-family: var(--font-sans); font-size: 12.5px; color: var(--text-faint); }
.mc-keys kbd { font: inherit; color: var(--text-muted); background: var(--surface-2); border-radius: 6px; padding: 0 5px; }
.mc-pill-k, .mp-k, .mc-u-k, .mc-pop-h { font-family: var(--font-sans); font-size: 12.5px; font-weight: 400;
  letter-spacing: 0; text-transform: none; color: var(--text-faint); }
/* One accent: the provider's brand mark in the closed picker reads in grey (its colours stay in the list). */
.mp-trigger .mp-ico { filter: grayscale(1); opacity: .85; }

/* The estimate on Setup: no number exists before Format, so there is no estimate to show. */
.setup-foot .est-inline.is-blank { display: none; }
.setup-foot .step-go { margin-left: auto; }
/* …and the phone bar stays one row: the estimate (when there is one) shrinks, Next keeps its size. */
@media (max-width: 900px) {
  .setup-foot .bar-inner { flex-wrap: nowrap; }
  .setup-foot .est-inline { flex: 1 1 auto; min-width: 0; }
}

/* ======================= AUTH SPLIT PAGE (owner, 2026-10-15) =======================
   Sign in, sign up (and invite sign-up), forgot password, set a new password and the
   "check your inbox" note — one split page after Theater's login. Left ("D1"): a TikTok-like and
   a Reels-like phone playing official style demos (#authStage, authphones.js, media from
   /api/public/auth-posters) with likes floating up, and the logo;
   right: the form on dark. Always the tone-B palette, whatever tone the app is on: this is the
   brand's front door. Everything is scoped to #authGate. The old centred .auth-card rules
   above are no longer drawn by any markup and can be retired. */
#authGate.auth-split {
  --af-bg:#0C0C0E; --af-surface:#151517; --af-fill:rgba(255,255,255,.05); --af-fill-hi:rgba(255,255,255,.075);
  --af-text:#F1EFF5; --af-muted:#A3A3AB; --af-faint:#7C7C85; --af-line:rgba(255,255,255,.06);
  --af-accent:#B39BFF; --af-accent-weak:rgba(179,155,255,.13); --af-accent-border:rgba(179,155,255,.42);
  --af-danger:#FF7A84; --af-ok:#5FDBA5;
  --af-grad:linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%);
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch; justify-content: stretch;
  background: var(--af-bg); color: var(--af-text); font-family: var(--font-sans);
  overflow-x: hidden; overflow-y: auto; -webkit-overflow-scrolling: touch;
}
#authGate.auth-split.hidden { display: none !important; }

/* ---- left: two phones (authphones.js). Sizes are em of the rig, which scales with the panel. ---- */
#authGate .af-media { position: sticky; top: 0; height: 100vh; height: 100dvh; padding: 0; min-width: 0; overflow: hidden;
  background: radial-gradient(40% 32% at 52% 50%, rgba(156,123,255,.30), transparent 70%),
    radial-gradient(28% 24% at 34% 62%, rgba(127,196,255,.16), transparent 70%),
    radial-gradient(28% 24% at 70% 36%, rgba(217,138,224,.18), transparent 70%), var(--af-bg); }
#authGate .af-stage { position: absolute; inset: 0; }
#authGate .aph-rig { position: absolute; left: 50%; top: 50%; width: 72em; height: 90em; transform: translate(-50%, -50%);
  font-size: min(calc(100vh / 90), calc(50vw / 72)); font-size: min(calc(100dvh / 90), calc(50vw / 72)); }
#authGate .aph-slot { position: absolute; }
#authGate .aph-slot-a { left: 7em; top: 15em; z-index: 1; font-size: .92em; }
#authGate .aph-slot-a .aph { transform: rotate(-6deg); }
#authGate .aph-slot-b { left: 33em; top: 9.6em; z-index: 2; font-size: 1.04em; }
#authGate .aph-slot-b .aph { transform: rotate(4deg); }
#authGate .aph-bob { animation: aphBob 6.5s ease-in-out infinite alternate; will-change: transform; }
#authGate .aph-slot-a .aph-bob { animation-delay: -3.2s; }
@keyframes aphBob { from { transform: translateY(-.6em); } to { transform: translateY(.6em); } }
#authGate .aph { position: relative; width: 30em; aspect-ratio: 9 / 19.5; padding: .9em; border-radius: 4.2em; background: #18181B;
  box-shadow: 0 0 0 .1em rgba(255,255,255,.09), 0 3em 8em rgba(8,4,24,.75); color: #fff; font-family: var(--font-sans); }
#authGate .aph svg { width: 1em; height: 1em; display: block; }
#authGate .aph-scr { position: relative; width: 100%; height: 100%; border-radius: 3.4em; overflow: hidden; isolation: isolate;
  background: linear-gradient(170deg, #1d1a2c 0%, #121116 60%, #0d0c10 100%); }
#authGate .aph-scr::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,.35), transparent 18%, transparent 55%, rgba(0,0,0,.6)); }
#authGate .aph-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; z-index: 0; }
#authGate .aph-vid { opacity: 0; transition: opacity .6s ease; }
#authGate .aph.is-playing .aph-vid { opacity: 1; }
#authGate .aph-notch { position: absolute; top: .9em; left: 50%; transform: translateX(-50%); width: 9em; height: 2.4em; border-radius: 999px; background: #0A0A0B; z-index: 9; }
#authGate .aph-top { position: absolute; top: 4.4em; left: 0; right: 0; z-index: 3; display: flex; justify-content: center; align-items: center; gap: 1.6em;
  font-size: 1.45em; font-weight: 600; text-shadow: 0 .1em .5em rgba(0,0,0,.5); }
#authGate .aph-dim { opacity: .6; }
#authGate .aph-on { position: relative; }
#authGate .aph-on::after { content: ""; position: absolute; left: 30%; right: 30%; bottom: -.4em; height: .16em; border-radius: 9px; background: #fff; }
#authGate .aph-ig .aph-top { justify-content: space-between; padding: 0 1.1em; font-size: 1.7em; font-weight: 700; }
#authGate .aph-rail { position: absolute; right: .9em; bottom: 9.5em; z-index: 4; display: flex; flex-direction: column; align-items: center; gap: 1.5em; }
#authGate .aph-act { display: flex; flex-direction: column; align-items: center; gap: .25em; font: 600 1.15em/1 var(--font-sans); text-shadow: 0 .1em .4em rgba(0,0,0,.5); }
#authGate .aph-act svg { font-size: 2.55em; filter: drop-shadow(0 .05em .2em rgba(0,0,0,.4)); transition: color .2s; }
#authGate .aph-like.is-liked svg { color: #FF3B5C; }
#authGate .aph-like.is-pop svg { animation: aphPop .45s cubic-bezier(.3,1.6,.5,1); }
@keyframes aphPop { 40% { transform: scale(1.35); } }
#authGate .aph-ava-img { display: block; background: #2a2833 center / cover no-repeat; border-radius: 50%; }
#authGate .aph-ava { position: relative; padding-bottom: .4em; }
#authGate .aph-ava .aph-ava-img { width: 4.2em; height: 4.2em; border: .18em solid #fff; }
#authGate .aph-plus { position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); width: 1.9em; height: 1.9em; border-radius: 50%;
  background: #FF3B5C; display: grid; place-items: center; font-size: 1.05em; }
#authGate .aph-thumb .aph-ava-img { width: 3.2em; height: 3.2em; border-radius: .7em; border: .18em solid #fff; }
#authGate .aph-disc { position: absolute; right: 1.1em; bottom: 2.4em; z-index: 4; width: 4.4em; height: 4.4em; border-radius: 50%; padding: .9em;
  background: radial-gradient(circle, #2a2a2e 0 45%, #111 46% 100%); box-shadow: 0 0 0 .1em rgba(255,255,255,.08); animation: aphSpin 5s linear infinite; }
#authGate .aph-disc .aph-ava-img { width: 100%; height: 100%; }
@keyframes aphSpin { to { transform: rotate(360deg); } }
#authGate .aph-cap { position: absolute; left: 1.4em; right: 6.6em; bottom: 2.2em; z-index: 4; display: flex; flex-direction: column; gap: .55em;
  text-shadow: 0 .1em .4em rgba(0,0,0,.55); }
#authGate .aph-handle { font-weight: 700; font-size: 1.45em; display: flex; align-items: center; gap: .5em; }
#authGate .aph-handle .aph-ava-img { width: 1.9em; height: 1.9em; flex: none; }
#authGate .aph-follow { border: .08em solid rgba(255,255,255,.85); border-radius: .5em; padding: .15em .6em; font-size: .82em; font-weight: 600; }
#authGate .aph-text { font-size: 1.3em; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#authGate .aph-music { display: flex; align-items: center; gap: .5em; font-size: 1.2em; min-width: 0; }
#authGate .aph-music svg { flex: none; }
#authGate .aph-ticker { overflow: hidden; white-space: nowrap; min-width: 0; flex: 1;
  -webkit-mask-image: linear-gradient(90deg, #000 80%, transparent); mask-image: linear-gradient(90deg, #000 80%, transparent); }
#authGate .aph-ticker span { display: inline-block; padding-right: 3em; animation: aphTick 9s linear infinite; }
@keyframes aphTick { to { transform: translateX(-100%); } }
#authGate .aph-prog { position: absolute; left: 0; right: 0; bottom: 0; height: .3em; z-index: 5; background: rgba(255,255,255,.22); }
#authGate .aph-prog i { display: block; height: 100%; background: #fff; transform-origin: 0 50%; transform: scaleX(0); transition: transform .3s linear; }
/* likes: transform + opacity only, at most 24 alive per phone (authphones.js) */
#authGate .aph-hearts { position: absolute; inset: 0; z-index: 6; pointer-events: none; overflow: hidden; }
#authGate .aph-heart { position: absolute; right: 1.2em; bottom: 14em; color: var(--c, #FF3B5C);
  animation: aphRise var(--dur, 3s) cubic-bezier(.22,.61,.36,1) both; will-change: transform, opacity; }
#authGate .aph-heart > span { display: block; font-size: var(--sz, 2.2em); animation: aphWob var(--wd, 1.1s) ease-in-out infinite alternate; }
@keyframes aphRise { 0% { transform: translate(0, 0) scale(.3); opacity: 0; } 12% { transform: translate(0, -.8em) scale(1); opacity: 1; }
  70% { opacity: .9; } 100% { transform: translate(var(--dx, -1em), var(--up, -9em)) scale(.85); opacity: 0; } }
@keyframes aphWob { from { transform: translateX(calc(var(--wob, .2em) * -1)) rotate(-9deg); } to { transform: translateX(var(--wob, .2em)) rotate(9deg); } }
#authGate .aph-big { position: absolute; left: 50%; top: 44%; z-index: 7; font-size: 9em; margin: -.5em 0 0 -.5em; color: #FF3B5C; pointer-events: none;
  animation: aphDbl 1.1s cubic-bezier(.2,.9,.3,1.2) both; }
@keyframes aphDbl { 0% { transform: scale(0) rotate(-14deg); opacity: 0; } 18% { transform: scale(1.18) rotate(-6deg); opacity: 1; }
  32% { transform: scale(.95) rotate(-8deg); } 70% { transform: scale(1) rotate(-8deg); opacity: 1; } 100% { transform: scale(1.05) rotate(-8deg) translateY(-.6em); opacity: 0; } }
/* Muse's push banner inside the front phone (iOS-style): under the notch, above the top bar,
   clear of the action rail and the hearts. Slides on transform only. */
#authGate .aph-banner { position: absolute; left: 1em; right: 1em; top: 3.9em; z-index: 8; display: flex; align-items: center; gap: .9em;
  padding: .9em 1.1em; border-radius: 1.8em; color: #fff; background: rgba(30,30,34,.66);
  -webkit-backdrop-filter: blur(18px) saturate(160%); backdrop-filter: blur(18px) saturate(160%);
  box-shadow: inset 0 0 0 .08em rgba(255,255,255,.10), 0 .8em 2.4em rgba(0,0,0,.35);
  transform: translateY(-160%); opacity: 0; transition: transform .55s cubic-bezier(.16,1,.3,1), opacity .35s ease; }
#authGate .aph-banner.is-in { transform: translateY(0); opacity: 1; }
#authGate .aph-banner img { flex: none; width: 3.4em; height: 3.4em; border-radius: 50%; padding: .45em; background: #0C0C0E; object-fit: contain; }
#authGate .aph-banner-t { display: flex; flex-direction: column; gap: .2em; min-width: 0; flex: 1; font-size: 1.3em; line-height: 1.2; }
#authGate .aph-banner-t b { font-weight: 700; }
#authGate .aph-banner-t span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: .92; }
#authGate .aph-banner time { align-self: flex-start; font-size: 1.05em; opacity: .6; }
@media (prefers-reduced-transparency: reduce) { #authGate .aph-banner { background: #1E1E22; -webkit-backdrop-filter: none; backdrop-filter: none; } }
/* reduced motion: posters only, nothing moves */
#authGate .af-stage.is-still :is(.aph-bob, .aph-disc, .aph-ticker span) { animation: none; }
#authGate .af-stage.is-still :is(.aph-hearts, .aph-big, .aph-banner) { display: none; }
#authGate .af-media-brand {
  position: absolute; left: 32px; top: 28px; z-index: 2; display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-weight: 800; font-size: 24px; letter-spacing: -0.02em; color: #fff;
  filter: drop-shadow(0 1px 8px rgba(0,0,0,.6));
}
#authGate .af-media-brand img { width: 34px; height: 34px; object-fit: contain; }

/* ---- right: the form ---- */
#authGate .af-panel { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; min-width: 0;
  background: var(--af-bg); animation: pageIn .5s cubic-bezier(.22,.61,.36,1) both; }
#authGate .af-center { flex: 1; display: flex; align-items: center; justify-content: center; padding: 48px 28px; }
#authGate .af-box { width: 100%; max-width: 384px; min-width: 0; }
#authGate .af-head { display: flex; flex-direction: column; align-items: center; gap: 6px; margin: 0; text-align: center;
  font-family: var(--font-display); font-weight: 600; font-size: 28px; letter-spacing: -0.02em; line-height: 1.15; color: var(--af-text); }
#authGate .af-kicker { font-weight: 600; }
#authGate .af-wordmark { display: inline-flex; align-items: center; gap: 12px; }
#authGate .af-wordmark img { width: 48px; height: 48px; object-fit: contain; }
#authGate .af-wordmark span { font-size: 48px; font-weight: 800; letter-spacing: -0.035em; line-height: 1;
  background: var(--af-grad); -webkit-background-clip: text; background-clip: text; color: transparent; padding-bottom: 4px; }
#authGate .af-title { font-weight: 700; }
#authGate .af-sub { margin: 10px 0 30px; text-align: center; font-size: 14px; line-height: 1.5; color: var(--af-muted); }
#authGate .af-sub:empty { margin-bottom: 18px; }
#authGate .af-form { display: flex; flex-direction: column; gap: 18px; margin: 0; }
#authGate .af-field { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
#authGate .af-label { font-size: 13px; font-weight: 500; color: var(--af-text); }
/* a fill, not a frame; an accent ring on focus (beats the app-wide tone rules on inputs) */
#authGate .af-field input.af-input {
  width: 100%; box-sizing: border-box; height: 46px; padding: 0 14px; margin: 0;
  border: 1px solid transparent; border-radius: 12px; background: var(--af-fill); color: var(--af-text);
  font: 400 15px/1.2 var(--font-sans); outline: none; box-shadow: none;
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
#authGate .af-field input.af-input:hover { background: var(--af-fill-hi); }
#authGate .af-field input.af-input:focus { background: var(--af-fill-hi); border-color: var(--af-accent-border);
  box-shadow: 0 0 0 3px rgba(179,155,255,.18); }
#authGate .af-field.has-err input.af-input { border-color: rgba(255,122,132,.55); }
#authGate .af-field.has-err input.af-input:focus { box-shadow: 0 0 0 3px rgba(255,122,132,.16); }
#authGate .af-err { margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--af-danger); overflow-wrap: anywhere; }
#authGate .af-err:empty { display: none; }
#authGate .af-pw { position: relative; }
#authGate .af-pw input.af-input { padding-right: 48px; }
#authGate .af-eye {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%); width: 36px; height: 36px;
  display: grid; place-items: center; padding: 0; border: 0; border-radius: 9px; background: transparent;
  color: var(--af-faint); cursor: pointer;
}
#authGate .af-eye:hover { color: var(--af-text); background: rgba(255,255,255,.06); }
#authGate .af-eye:focus-visible { outline: 2px solid var(--af-accent); outline-offset: 0; }
#authGate .af-eye svg { width: 18px; height: 18px; }
#authGate .af-eye .af-eye-off, #authGate .af-eye.on .af-eye-on { display: none; }
#authGate .af-eye.on .af-eye-off { display: block; }
#authGate .af-forgot-row { display: flex; justify-content: flex-end; margin-top: -2px; }
#authGate .af-link { background: none; border: 0; padding: 0; margin: 0; cursor: pointer; font: 500 13px/1.4 var(--font-sans);
  color: var(--af-accent); text-shadow: none; opacity: 1; }
#authGate .af-link:hover { text-decoration: underline; text-underline-offset: 3px; }
#authGate .af-link:focus-visible { outline: 2px solid var(--af-accent); outline-offset: 2px; border-radius: 4px; }
#authGate .af-link:disabled { color: var(--af-muted); cursor: default; text-decoration: none; }
#authGate .af-link-strong { font-size: 14px; font-weight: 600; }
/* the primary button: the logo's gradient and a pressed edge, in every tone */
#authGate .af-primary {
  width: 100%; height: 48px; margin: 2px 0 0; padding: 0 18px; border: 0; border-radius: 12px; cursor: pointer;
  background: var(--af-grad); color: #0B0A14; font: 600 15px/1 var(--font-sans); letter-spacing: 0;
  box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); transition: filter .15s ease, transform .1s ease;
}
#authGate .af-primary:hover { filter: brightness(1.06); box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); }
#authGate .af-primary:active { transform: translateY(1px); box-shadow: inset 0 -1px 0 rgba(40,20,90,.38); }
#authGate .af-primary:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
#authGate .af-primary:disabled { opacity: .7; cursor: progress; filter: none; }
/* the form's own line: rate limits, a disabled account, "password updated" — hidden when empty */
#authGate .auth-msg { margin: 0; padding: 10px 12px; border-radius: 10px; min-height: 0; font-size: 13.5px; line-height: 1.5;
  background: rgba(255,255,255,.04); color: var(--af-muted); overflow-wrap: anywhere; text-align: left; }
#authGate .auth-msg:empty { display: none; }
#authGate .auth-msg.err { background: rgba(255,122,132,.10); color: var(--af-danger); }
#authGate .auth-msg.ok { background: rgba(95,219,165,.10); color: var(--af-ok); }
#authGate .auth-msg .af-link { margin-left: 4px; font-size: 13.5px; }
#authGate .auth-invite { margin: 0 0 22px; padding: 11px 13px; border: 0; border-radius: 12px; background: var(--af-accent-weak);
  color: var(--af-text); font-size: 13.5px; line-height: 1.5; overflow-wrap: anywhere; }
#authGate:not([data-mode="signin"]):not([data-mode="signup"]) .auth-invite { display: none; }
#authGate .af-switch { margin: 26px 0 0; text-align: center; font-size: 14px; color: var(--af-muted); }
#authGate .af-switch .af-link { margin-left: 4px; }
/* "check your inbox" */
#authGate .af-done { display: flex; flex-direction: column; align-items: center; gap: 16px; text-align: center; }
#authGate .af-done.hidden { display: none; }
#authGate .af-done-ico { width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center;
  background: var(--af-accent-weak); color: var(--af-accent); }
#authGate .af-done-ico svg { width: 26px; height: 26px; }
#authGate .af-done-text { margin: 0; font-size: 15px; line-height: 1.6; color: var(--af-muted); overflow-wrap: anywhere; }
#authGate .af-done-extra:empty { display: none; }
#authGate .af-foot { padding: 16px 24px calc(16px + env(safe-area-inset-bottom)); border-top: 1px solid var(--af-line);
  text-align: center; font-size: 12px; color: var(--af-faint); }

/* ---- phone: the collage becomes one short strip at the top, the form full width below ---- */
@media (max-width: 900px) {
  #authGate.auth-split { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; }
  /* one row on top: the welcome block on the left, one small tilted phone on the right; no second
     logo (the wordmark is in the welcome block); the form starts right under the row */
  /* --aph-w: the phone's width. A 4° tilt widens its box by ~15% (9% a side) and adds ~4% in
     height; the strip, the slot and the welcome column are all sized from it, so nothing is cut. */
  #authGate.auth-split { --aph-w: clamp(140px, 40vw, 165px); }
  #authGate .af-media { position: relative; height: calc(var(--aph-w) * 2.26); }
  #authGate .af-media-brand { display: none; }
  #authGate .af-stage.is-compact .aph-rig { left: 0; top: 0; width: 100%; height: 100%; transform: none; font-size: 10px; }
  #authGate .aph-slot-solo { left: auto; right: calc(20px + var(--aph-w) * .09); top: calc(var(--aph-w) * .05);
    font-size: calc(var(--aph-w) / 30); }
  #authGate .aph-slot-solo .aph { transform: rotate(4deg); }
  /* a larger banner on the small phone, wrapping to two lines rather than cutting the text */
  #authGate .aph-slot-solo .aph-banner { font-size: 1.3em; left: .55em; right: .55em; top: 3.1em; padding: .7em .8em; gap: .6em; border-radius: 1.4em; }
  #authGate .aph-slot-solo .aph-banner img { width: 2.8em; height: 2.8em; }
  #authGate .aph-slot-solo .aph-banner time { display: none; }
  #authGate .aph-slot-solo .aph-banner-t span { white-space: normal; }
  #authGate .af-intro { position: absolute; left: 20px; top: 0; height: calc(var(--aph-w) * 2.26);
    width: calc(100% - 40px - var(--aph-w) * 1.18 - 12px);
    display: flex; flex-direction: column; justify-content: center; align-items: flex-start; z-index: 3; text-align: left; }
  #authGate .af-intro .af-head { align-items: flex-start; text-align: left; font-size: 19px; gap: 4px; }
  #authGate .af-intro .af-title { font-size: 23px; line-height: 1.15; }
  #authGate .af-intro .af-wordmark { gap: 8px; }
  #authGate .af-intro .af-wordmark img { width: 32px; height: 32px; }
  #authGate .af-intro .af-wordmark span { font-size: 36px; }
  #authGate .af-intro .af-sub { text-align: left; margin: 8px 0 0; font-size: 13.5px; line-height: 1.45; }
  #authGate .af-intro .af-sub:empty { display: none; }
  #authGate .af-panel { min-height: 0; }
  #authGate .af-center { align-items: flex-start; padding: 6px 20px 28px; }
  #authGate .af-form { gap: 12px; }
  #authGate .af-field { gap: 6px; }
}
/* The closed side drawers wait just off the right edge, and their shadow bled a dark band over
   the form's right edge. Nothing slides in while the gate is up. */
body:has(#authGate.auth-split:not(.hidden)) :is(.guide-dock:not(.open), .clip-drawer:not(.open)) { box-shadow: none; }
@media (prefers-reduced-motion: reduce) {
  #authGate .af-panel { animation: none; }
  #authGate :is(.aph-bob, .aph-disc, .aph-ticker span) { animation: none; }
  #authGate :is(.aph-hearts, .aph-big, .aph-banner) { display: none; }
  #authGate .aph-vid { transition: none; }
}
/* ===================== /AUTH SPLIT PAGE ===================== */

/* ---- THE SPLIT FINISH BUTTON IS ONE BUTTON (owner, 2026-10-15: "不好看") --------------------
   Each half drew its own gradient, so the colour restarted at the caret, and a pale 1px seam
   plus pill ends made it read as two stuck-together pills. The wrapper now carries one fill and
   one bottom edge; the halves are transparent; the divider is a faint dark hairline; corners are
   the 12px every other primary button uses. */
html[data-tone] .split-go { border-radius: 12px; overflow: hidden; background: var(--accent);
  box-shadow: inset 0 -3px 0 var(--accent-deep); }
html[data-tone="b"] .split-go { background: linear-gradient(100deg, #7FC4FF 0%, #9C7BFF 52%, #D98AE0 100%);
  box-shadow: inset 0 -3px 0 rgba(40,20,90,.38); }
html[data-tone] .split-go > .split-main, html[data-tone] .split-go > .split-caret,
html[data-tone] .split-go > .split-main:hover, html[data-tone] .split-go > .split-caret:hover {
  background: transparent; box-shadow: none; border-radius: 0; }
html[data-tone] .split-go > .split-caret { border-left: 1px solid rgba(11,10,20,.16); padding: 11px 14px; }
html[data-tone] .split-go > :is(.split-main, .split-caret):hover { background: rgba(255,255,255,.12); }
html[data-tone] .split-go > :is(.split-main, .split-caret):active { background: rgba(11,10,20,.08); transform: none; }
html[data-tone] .split-go.hidden { display: none; }

/* =====================================================================================
   ADMIN → OVERVIEW and ADMIN → CREDITS (2026-10-15). adminops.js loadOverview / loadCredits.
   Tone B: fills, not frames; small grey labels; Bricolage numbers; one date-range control
   (.rg) shared by both pages. Everything new for these two pages lives in this section.
   ===================================================================================== */
/* -- date range: presets + custom from–to -- */
.rg { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
.rg-seg { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--r-pill); background: var(--surface-2); }
.rg-seg button { border: 0; background: none; color: var(--text-muted); font: inherit; font-size: .8rem;
  padding: 5px 12px; border-radius: var(--r-pill); cursor: pointer; }
.rg-seg button:hover { color: var(--text); }
.rg-seg button.on { background: var(--surface); color: var(--text); font-weight: 600; }
.rg-dates { display: inline-flex; align-items: center; gap: 6px; opacity: .6; }
.rg-dates.on { opacity: 1; }
.rg-dates input { background: var(--surface-2); border: 0; border-radius: var(--r-sm); color: var(--text);
  font: inherit; font-size: .8rem; padding: 6px 8px; color-scheme: dark; min-width: 0; }
.rg-to { font-size: .76rem; color: var(--text-faint); }

/* -- Overview -- */
.ov-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 16px; }
.ov-kpis, .acr-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; margin-bottom: 16px; }
:is(.ov-kpis, .acr-kpis) .ao-tile { background: var(--surface-2); border: 0; border-radius: var(--r-md); padding: 14px 16px; }
:is(.ov-kpis, .acr-kpis) .ao-tile b { font-size: 1.6rem; }
:is(.ov-kpis, .acr-kpis) .ao-k { font-size: .74rem; color: var(--text-muted); }
:is(.ov-kpis, .acr-kpis) .ao-sub { font-size: .74rem; color: var(--text-faint); line-height: 1.4; }
.ov-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; margin-bottom: 16px; }
.ovc { margin: 0; padding: 14px 16px 10px; background: var(--surface-2); border-radius: var(--r-md); min-width: 0; }
.ovc figcaption { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin-bottom: 10px; }
.ovc-t { font-size: .76rem; color: var(--text-muted); }
.ovc figcaption b { font-family: var(--font-display); font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.ovc-lg { margin-left: auto; font-size: .72rem; color: var(--text-muted); display: inline-flex; gap: 10px; align-items: center; }
.ovc-lg i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 4px; }
.ovc-plot { position: relative; height: 96px; }
.ovc-bars { display: flex; align-items: flex-end; gap: 2px; height: 100%; border-bottom: 1px solid var(--border); }
.ovc-col { flex: 1 1 0; min-width: 1px; height: 100%; display: flex; flex-direction: column-reverse; gap: 1px; cursor: default; }
.ovc-col i { display: block; width: 100%; border-radius: 3px 3px 0 0; min-height: 0; }
.ovc-col i + i { border-radius: 3px 3px 0 0; }
.ovc .k-done, .ovc .k-credits, .ovc .k-signups, .ovc .k-creators { background: var(--accent); }
.ovc .k-failed { background: var(--danger); }
.ovc-col.on i { filter: brightness(1.3); }
.ovc-max { position: absolute; top: -2px; right: 0; font-size: .66rem; color: var(--text-faint); }
.ovc-tip { position: absolute; bottom: calc(100% + 6px); z-index: 5; display: none; min-width: 140px; padding: 8px 10px;
  border-radius: var(--r-sm); background: var(--surface); box-shadow: 0 10px 30px rgba(0,0,0,.45); font-size: .76rem; pointer-events: none; }
.ovc.on .ovc-tip { display: block; }
.ovc-tw { color: var(--text-muted); margin-bottom: 4px; }
.ovc-tr { display: flex; justify-content: space-between; gap: 14px; }
.ovc-tr b { font-variant-numeric: tabular-nums; }
.ovc-x { display: flex; justify-content: space-between; margin-top: 6px; font-size: .68rem; color: var(--text-faint); }
.ov-lists { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px; margin-bottom: 12px; }
.ov-card { background: var(--surface-2); border-radius: var(--r-md); padding: 14px 16px; min-width: 0; }
.ov-card.ov-wide { grid-column: 1 / -1; }
.ov-card > header { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px; margin-bottom: 10px; }
.ov-card h3 { margin: 0; font-family: var(--font-display); font-size: 1rem; }
.ov-chk { margin-left: auto; font-size: .76rem; color: var(--text-muted); display: inline-flex; gap: 6px; align-items: center; }
.ov-wn { margin: 0 0 10px; font-size: .8rem; color: var(--text-muted); }
.ov-dl, .acr-dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px 14px; margin: 0 0 10px; }
.ov-dl dt, .acr-dl dt { font-size: .72rem; color: var(--text-faint); }
.ov-dl dd, .acr-dl dd { margin: 2px 0 0; font-size: .86rem; color: var(--text); overflow-wrap: anywhere; }
.ov-dl dd { font-family: var(--font-display); font-size: 1.1rem; font-variant-numeric: tabular-nums; }
.ov-dl dd.bad, .ov-t td.bad { color: var(--danger); }
.ov-t { width: 100%; border-collapse: collapse; font-size: .82rem; }
.ov-t th { text-align: left; font-weight: 500; font-size: .72rem; color: var(--text-faint); padding: 0 10px 8px 0; white-space: nowrap; }
.ov-t td { padding: 8px 10px 8px 0; border-top: 1px solid var(--border); vertical-align: top; }
.ov-t td b { display: block; font-weight: 600; }
.ov-t .n { text-align: right; font-variant-numeric: tabular-nums; }
.ov-fail tr[data-job] { cursor: pointer; }
.ov-fail tr[data-job]:hover td { background: color-mix(in srgb, var(--text) 4%, transparent); }
.ov-err { color: var(--text-muted); }
.ov-hb { display: grid; grid-template-columns: minmax(90px, 40%) 1fr auto; gap: 10px; align-items: center; font-size: .82rem; padding: 4px 0; }
.ov-hb i { height: 8px; border-radius: 4px; background: linear-gradient(90deg, var(--accent) var(--w), var(--surface) var(--w)); }
.ov-hb b { font-variant-numeric: tabular-nums; }
.ov-more > summary { cursor: pointer; padding: 10px 0; font-weight: 600; list-style: none; display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.ov-more > summary::before { content: "▸"; color: var(--text-faint); }
.ov-more[open] > summary::before { content: "▾"; }
.ov-more .ov-lists { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* -- Credits -- */
.acr-pn { display: inline-block; min-width: 18px; padding: 1px 6px; border-radius: var(--r-pill); background: var(--warn-weak); color: var(--warn); font-size: .7rem; font-weight: 700; text-align: center; }
.cr-wrap { background: var(--surface-2); border-radius: var(--r-md); }
.acr-when { white-space: nowrap; color: var(--text-muted); }
.acr-user b { display: block; font-weight: 600; }
.acr-user .small { display: block; max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acr-what { min-width: 220px; }
.acr-w1 { display: block; }
.acr-w2 { display: block; font-size: .74rem; color: var(--text-faint); margin-top: 2px; }
.acr-w2.ok { color: var(--ok); }
.acr-flag { display: inline-block; margin-top: 4px; padding: 1px 7px; border-radius: var(--r-pill); background: var(--warn-weak); color: var(--warn); font-size: .7rem; font-weight: 600; }
.acr-amt .neg { color: var(--text); }
.acr-amt .pos { color: var(--ok); }
.acr-wal, .acr-ws { white-space: nowrap; }
.acr-chip { display: inline-block; padding: 2px 8px; border-radius: var(--r-pill); font-size: .7rem; font-weight: 600; white-space: nowrap;
  background: var(--surface); color: var(--text-muted); }
.acr-chip.k-video { background: var(--accent-weak); color: var(--accent); }
.acr-chip.k-image { background: color-mix(in srgb, var(--brain) 16%, transparent); color: var(--brain); }
.acr-chip.k-frame { background: color-mix(in srgb, var(--brain) 10%, transparent); color: var(--text); }
.acr-chip.k-refund, .acr-chip.k-topup { background: var(--ok-weak); color: var(--ok); }
.acr-chip.k-grant { background: var(--accent-weak); color: var(--text); }
.acr-chip.k-unlabelled { background: var(--warn-weak); color: var(--warn); }
.acr-scrim { position: fixed; inset: 0; z-index: 90; background: rgba(0,0,0,.35); opacity: 0; pointer-events: none; transition: opacity .15s; }
.acr-scrim.on { opacity: 1; pointer-events: auto; }
.acr-side { position: fixed; top: 0; right: 0; bottom: 0; z-index: 91; width: min(460px, 100vw); background: var(--surface);
  box-shadow: -20px 0 60px rgba(0,0,0,.45); transform: translateX(100%); transition: transform .18s ease; overflow-y: auto; }
.acr-side.on { transform: none; }
.acr-sb { padding: 20px 20px 40px; }
.acr-sh { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
.acr-sh h3 { margin: 8px 0 4px; font-family: var(--font-display); font-size: 1.15rem; line-height: 1.25; }
.acr-big { font-family: var(--font-display); font-size: 2rem; font-weight: 700; margin: 14px 0; font-variant-numeric: tabular-nums; }
.acr-big.pos { color: var(--ok); }
.acr-big span { font-size: .9rem; font-weight: 500; color: var(--text-muted); }
.acr-sec { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.acr-sec h4 { margin: 0 0 10px; font-size: .78rem; font-weight: 600; color: var(--text-muted); }
.acr-sec p { margin: 4px 0; font-size: .84rem; }
.acr-img { position: relative; width: 140px; margin-bottom: 10px; }
.acr-img img { width: 140px; border-radius: var(--r-sm); display: block; }
.acr-mini { width: 100%; margin-top: 10px; font-size: .76rem; border-collapse: collapse; }
.acr-mini td { padding: 5px 6px 5px 0; border-top: 1px solid var(--border); }
.acr-mini .n { text-align: right; font-variant-numeric: tabular-nums; }
.acr-raw { margin-top: 16px; font-size: .78rem; }
.acr-raw summary { cursor: pointer; color: var(--text-muted); }
.acr-raw pre { white-space: pre-wrap; word-break: break-all; background: var(--surface-2); padding: 10px; border-radius: var(--r-sm); font-size: .72rem; }

@media (max-width: 760px) {
  .ov-lists { grid-template-columns: minmax(0, 1fr); }
  .ov-kpis, .acr-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  :is(.ov-kpis, .acr-kpis) .ao-tile b { font-size: 1.3rem; }
  .ov-charts { grid-template-columns: minmax(0, 1fr); }
  .rg { width: 100%; }
  .rg-seg { flex-wrap: wrap; }
}

/* ==================== LIBRARY TOOLBAR (2026-10-15) ====================================================
   The owner: "the filter tabs arrangement is not that good". The bar was four different kinds of
   control at four heights: a framed tab group with a coloured dot per tab, a search box floating in
   the middle, a date picker whose focus ring stayed on so it looked selected, a sort picker pinned to
   the far edge, and the workspace as an accent pill beside the title. Now:
   · left: the status tabs, the raised sliding segmented control (core.js placeSegs, tone B); no dots,
     the counts small and muted
   · right: one group, every control one height (--lt-h), one fill, one radius, no frame —
     Clear (only while something is filtered, with a count), search, workspace, date, sort
   · the workspace picker moved into the group: it filters the grid exactly as the date does, and
     by the title it read as part of the heading
   · search is an icon until it is needed when space is short (it opens on focus, stays open while it
     holds a query); with room to spare (1440) it is open from the start
   · accent only on keyboard focus (:focus-visible) and on the count badge
   · phone: the tabs scroll sideways on their own row; search + a "Filters" button on the second;
     workspace, date, sort and Clear open as a bottom sheet (the same elements, not copies)
   Everything is scoped to .view-library, so no other page's controls move. */
:root .view-library {
  --lt-h: 38px; --lt-r: 10px;
  --lt-fill: var(--surface-2); --lt-fill-hi: #24232B; --lt-on: #2D2C35;
  --lt-chev: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23A29DAC' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
}
:root[data-tone] .view-library {
  --lt-fill: rgba(255,255,255,.05); --lt-fill-hi: rgba(255,255,255,.085); --lt-on: #26262B;
  --lt-chev: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23A3A3AB' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
}
:root .view-library .lib-title { margin-bottom: 18px; }
:root .view-library .lib-bar {
  container: libbar / inline-size;
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: 10px 16px; margin-bottom: 20px;
}

/* -- status tabs -- */
:root .view-library .lib-tabs {
  flex: none; display: flex; align-items: stretch; gap: 2px; flex-wrap: nowrap;
  height: var(--lt-h); box-sizing: border-box; padding: 3px;
  border: 0; border-radius: var(--lt-r); background: var(--lt-fill); box-shadow: none;
}
:root .view-library .lib-tab {
  flex: none; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 100%; box-sizing: border-box; padding: 0 12px; border: 0; border-radius: calc(var(--lt-r) - 3px);
  background: none; color: var(--text-muted); font: inherit; font-size: .84rem; font-weight: 600; line-height: 1;
  white-space: nowrap; cursor: pointer; transition: color .15s ease, background .15s ease;
}
:root .view-library .lib-tab:hover { color: var(--text); }
:root .view-library .lib-tab.on { color: var(--text); background: var(--lt-on);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05), 0 2px 8px rgba(0,0,0,.3); }
:root .view-library .lib-tabs.has-ind > .lib-tab.on { background: transparent; box-shadow: none; }
:root .view-library .lib-tabs > .seg-ind { border-radius: calc(var(--lt-r) - 3px); }
:root .view-library .lib-tab-l { display: block; line-height: 18px; }
:root .view-library .lib-tab-n { display: block; line-height: 18px; font-family: var(--font-sans);
  font-size: .74rem; font-weight: 500; font-variant-numeric: tabular-nums; color: var(--text-faint); }
:root .view-library .lib-tab.on .lib-tab-n { color: var(--text-muted); }

/* -- the right-hand group -- */
:root .view-library .lib-tools {
  flex: 1 1 0; min-width: min-content; display: flex; align-items: center; justify-content: flex-end; gap: 8px;
}
:root .view-library .lib-ctl {
  height: var(--lt-h); box-sizing: border-box; margin: 0;
  border: 0; border-radius: var(--lt-r); background-color: var(--lt-fill); box-shadow: none; outline: none;
  color: var(--text-muted); font: inherit; font-size: .84rem; font-weight: 500;
  transition: background-color .15s ease, color .15s ease, box-shadow .15s ease, width .22s ease;
}
:root .view-library .lib-ctl:hover { background-color: var(--lt-fill-hi); color: var(--text); }
:root .view-library .lib-ctl.is-set { color: var(--text); }
/* No ring for a click; the accent ring only for keyboard focus. */
:root .view-library .lib-bar :is(.lib-ctl, .lib-tab, .lib-search):focus { outline: none; box-shadow: none; border-color: transparent; }
:root .view-library .lib-bar :is(.lib-ctl, .lib-tab):focus-visible { box-shadow: 0 0 0 2px var(--accent); }

/* date + sort */
:root .view-library .lib-pick {
  flex: none; width: auto; min-width: 0; padding: 0 32px 0 12px;
  -webkit-appearance: none; appearance: none; cursor: pointer;
  background-image: var(--lt-chev); background-repeat: no-repeat; background-position: right 11px center;
}
:root .view-library .lib-pick:focus { background-image: var(--lt-chev); }

/* workspace */
:root .view-library .lib-ws-dd { position: relative; flex: 0 1 auto; min-width: 0; display: flex; }
:root .view-library .lib-ws-btn {
  display: inline-flex; align-items: center; width: 100%; min-width: 120px; max-width: 220px; padding: 0 32px 0 12px;
  cursor: pointer; text-align: left;
  background-image: var(--lt-chev); background-repeat: no-repeat; background-position: right 11px center;
}
:root .view-library .lib-ws-btn > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
:root .view-library .lib-ws-menu { top: calc(100% + 6px); left: auto; right: 0; max-width: min(360px, calc(100vw - 32px)); }

/* search: an icon that opens */
:root .view-library .lib-search-wrap { position: relative; flex: none; width: var(--lt-h); min-width: 0; overflow: hidden; cursor: text; }
:root .view-library .lib-search-ico { left: 11px; width: 16px; height: 16px; color: var(--text-muted); }
:root .view-library .lib-search {
  display: block; width: 100%; height: 100%; box-sizing: border-box; margin: 0; padding: 0 12px 0 36px;
  border: 0; border-radius: 0; background: transparent; color: var(--text); font: inherit; font-size: .84rem;
  cursor: pointer;
}
:root .view-library .lib-search::-webkit-search-cancel-button { cursor: pointer; }
:root .view-library .lib-search-wrap:not(:focus-within):not(.has-q) .lib-search::placeholder { color: transparent; }
:root .view-library .lib-search-wrap:is(:focus-within, .has-q) { flex: 0 1 auto; width: 240px; min-width: 140px; }
:root .view-library .lib-search-wrap:is(:focus-within, .has-q) .lib-search { cursor: text; }
:root .view-library .lib-search-wrap:focus-within { background-color: var(--lt-fill-hi); }
:root .view-library .lib-search::placeholder { color: var(--text-faint); }
@container libbar (min-width: 1300px) {
  :root .view-library .lib-search-wrap { flex: 0 1 auto; width: 240px; min-width: 140px; }
  :root .view-library .lib-search-wrap .lib-search { cursor: text; }
  :root .view-library .lib-search-wrap:not(:focus-within):not(.has-q) .lib-search::placeholder { color: var(--text-faint); }
}

/* Clear + count. Clear sits last in the markup (inside the pickers, so the phone's sheet has it)
   and is ordered to the front of the row here, so it appearing never moves the controls. */
:root .view-library .lib-clear {
  order: -1; flex: none; display: inline-flex; align-items: center; gap: 7px; padding: 0 10px 0 12px;
  background-color: transparent; color: var(--text-muted); font-weight: 600; cursor: pointer;
}
:root .view-library .lib-clear.hidden { display: none; }
:root .view-library .lib-clear-n {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box;
  border-radius: 9px; background: var(--accent-weak); color: var(--accent);
  font-size: .7rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1;
}
:root .view-library .lib-clear-n:empty { display: none; }
/* desktop: the pickers' wrapper is transparent to layout; the phone-only parts are hidden */
:root .view-library .lib-picks { display: contents; }
:root .view-library :is(.lib-filters-btn, .lib-sheet-head) { display: none; }

/* -- phone: tabs on their own row (scrolling sideways), then search + a Filters button; the
   workspace, date, sort and Clear open as a bottom sheet -- */
@media (max-width: 760px) {
  :root .view-library .lib-bar { display: flex; flex-direction: column; align-items: stretch; gap: 8px; margin-bottom: 14px; }
  :root .view-library .lib-tabs { max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  :root .view-library .lib-tabs::-webkit-scrollbar { display: none; }
  :root .view-library .lib-tab { flex: 1 0 auto; padding: 0 10px; gap: 5px; font-size: .8rem; }
  :root .view-library .lib-tab-n { font-size: .7rem; }
  :root .view-library .lib-tools { flex: none; min-width: 0; width: 100%; gap: 8px; justify-content: stretch; }
  :root .view-library .lib-search-wrap,
  :root .view-library .lib-search-wrap:is(:focus-within, .has-q) { flex: 1 1 auto; width: auto; min-width: 0; }
  :root .view-library .lib-search-wrap .lib-search { cursor: text; }
  :root .view-library .lib-search-wrap:not(:focus-within):not(.has-q) .lib-search::placeholder { color: var(--text-faint); }
  :root .view-library .lib-filters-btn {
    flex: none; display: inline-flex; align-items: center; gap: 7px; padding: 0 12px; cursor: pointer; }
  :root .view-library .lib-filters-btn svg { width: 16px; height: 16px; }

  /* the sheet */
  :root .view-library .lib-picks {
    display: grid; gap: 10px; position: fixed; left: 0; right: 0; bottom: 0; z-index: 210;
    padding: 6px 16px calc(18px + env(safe-area-inset-bottom));
    background: var(--surface); border-radius: 16px 16px 0 0; box-shadow: 0 -18px 48px rgba(0,0,0,.55);
    transform: translateY(105%); visibility: hidden;
    transition: transform .28s cubic-bezier(.2,.9,.3,1), visibility 0s linear .28s;
  }
  :root[data-tone] .view-library .lib-picks { background: var(--float, var(--surface)); }
  :root .view-library .lib-bar.sheet-open .lib-picks { transform: none; visibility: visible; transition: transform .28s cubic-bezier(.2,.9,.3,1); }
  :root .view-library .lib-bar::before {
    content: ""; position: fixed; inset: 0; z-index: 209; background: rgba(5,5,7,.6);
    opacity: 0; pointer-events: none; transition: opacity .2s ease; }
  :root .view-library .lib-bar.sheet-open::before { opacity: 1; pointer-events: auto; }
  :root .view-library .lib-sheet-head { display: flex; align-items: center; justify-content: space-between; min-height: 48px; }
  :root .view-library .lib-sheet-head b { font-size: 1rem; color: var(--text); }
  :root .view-library .lib-sheet-done { border: 0; background: none; color: var(--accent); font: inherit;
    font-weight: 600; font-size: .92rem; padding: 10px 0 10px 16px; cursor: pointer; }
  :root .view-library .lib-picks .lib-ctl { --lt-h: 46px; width: 100%; max-width: none; min-width: 0; font-size: .92rem; }
  :root .view-library .lib-picks .lib-ws-dd { position: relative; }
  :root .view-library .lib-ws-menu { top: auto; bottom: calc(100% + 6px); left: 0; right: 0; min-width: 0; max-width: none;
    max-height: 50vh; overflow-y: auto; }
  :root .view-library .lib-clear { order: 0; justify-content: center; background-color: var(--lt-fill); color: var(--text); }
  @media (prefers-reduced-motion: reduce) {
    :root .view-library :is(.lib-picks, .lib-bar::before) { transition: none; }
  }
}
/* ==================== END LIBRARY TOOLBAR ==================== */

/* =====================================================================================
   ADMIN LISTS (2026-10-15): the one table, toolbar and pager every admin list uses
   (web/js/adminlist.js): Videos, Schedule & alerts, Worker, User logs, Users, Teams, Assets,
   Models, Pricing, Style films, Credits. Tone B: fills, not frames; small grey labels.
   ===================================================================================== */
.adl { min-width: 0; }
.adl-bar { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.adl-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
.adl-row:empty { display: none; }
.adl-q { flex: 1 1 240px; min-width: 0; }
.adl-sel { width: auto; max-width: 100%; }
.adl-end { margin-left: auto; display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.adl-check { display: inline-flex; align-items: center; gap: 6px; font-size: .8rem; color: var(--text-muted); }
.adl-chips { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.adl-chip { border: 0; background: var(--surface-2); color: var(--text-muted); font: inherit; font-size: .76rem;
  padding: 5px 10px; border-radius: var(--r-pill); cursor: pointer; }
.adl-chip:hover { color: var(--text); }
.adl-chip.on { background: var(--accent-weak); color: var(--text); font-weight: 600; }
.adl-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 2px 0 8px; min-height: 18px; }
.adl-scroll { overflow-x: auto; background: var(--surface-2); border-radius: var(--r-md); }
.adl-table { width: 100%; border-collapse: collapse; font-size: .84rem; }
.adl-table th { text-align: left; font-weight: 500; font-size: .72rem; color: var(--text-faint); padding: 10px 12px; white-space: nowrap; }
.adl-table th.n, .adl-table td.n { text-align: right; }
.adl-sort button { border: 0; background: none; color: inherit; font: inherit; padding: 0; cursor: pointer; display: inline-flex; gap: 4px; }
.adl-sort.on button, .adl-sort button:hover { color: var(--text); }
.adl-sort i { font-style: normal; }
.adl-table td { padding: 10px 12px; border-top: 1px solid var(--border); vertical-align: middle; }
.adl-table td.n { font-variant-numeric: tabular-nums; white-space: nowrap; }
.adl-table tr.adl-click { cursor: pointer; }
.adl-table tr.adl-click:hover td, .adl-table tr.adl-click:focus-visible td { background: color-mix(in srgb, var(--text) 4%, transparent); }
.adl-table tr:focus-visible { outline: none; }
.adl-table tr.is-disabled td { opacity: .55; }
.adl-table td b { font-weight: 600; }
.adl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
.adl-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 36px 16px; text-align: center;
  background: var(--surface-2); border-radius: var(--r-md); color: var(--text-muted); }
.adl-empty b { color: var(--text); font-weight: 600; }
.adl-empty.err b { color: var(--danger); }
.adl-pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px; padding: 12px 0 4px; }
.adl-pager:empty { display: none; }
.adl-pgn { display: inline-flex; align-items: center; gap: 6px; font-size: .8rem; color: var(--text-muted); white-space: nowrap; }
.adl-pager .select { display: inline-block; width: auto; min-width: 0; height: 32px; padding: 4px 10px; font-size: .8rem; }
.adl-pager select.select { padding-right: 30px; }
.adl-jump { width: 64px; padding: 4px 6px; text-align: center; }
.adl-size { width: auto; }
.adl-badge:empty { display: none; }
.aa-tw { position: relative; display: inline-block; }
.adl .sd-thumb { width: 64px; }
.adl .sd-acts { display: inline-flex; gap: 6px; }
@media (max-width: 760px) {
  .adl-end { margin-left: 0; width: 100%; }
  .adl-sel { flex: 1 1 140px; }
  .adl-scroll { background: none; overflow: visible; }
  .adl-table thead { display: none; }
  .adl-table, .adl-table tbody { display: block; width: 100%; }
  .adl-table tr { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 12px 14px; margin-bottom: 8px;
    background: var(--surface-2); border-radius: var(--r-md); }
  .adl-table td { display: flex; justify-content: space-between; gap: 12px; padding: 0; border: 0; min-width: 0; overflow-wrap: anywhere; }
  .adl-table td::before { content: attr(data-label); flex: none; font-size: .72rem; color: var(--text-faint); }
  .adl-table td[data-label=""]::before { display: none; }
  .adl-table td.n { justify-content: space-between; }
  .adl-table .adl-hp { display: none; }
  .adl-table td:empty { display: none; }
}

/* ==== CREATE A TEAM: the guided flow (team.js createTeamDialog, 2026-10-15) =======================
   One modal, three steps (Name, Invite, Top up) and a summary. Pads itself like .ac-grant / .al
   (the shared .modal-card has no padding); on a phone it is a full-height sheet with the footer
   pinned to the bottom. Owns every .tcf* class; nothing else in the app uses them. */
.modal-card:has(.tcf) { max-width: 540px; overflow: hidden; display: flex; }
.modal-card:has(.tcf) > .modal-body { flex: 1 1 auto; min-width: 0; display: flex; }
.tcf { display: flex; flex-direction: column; width: 100%; min-width: min(480px, 86vw); max-height: 88vh; }
.tcf .sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.tcf-head { padding: 22px 24px 0; display: grid; gap: 8px; }
.tcf-head h3 { margin: 6px 0 0; padding-right: 44px; font-size: 1.15rem; line-height: 1.35; outline: none; overflow-wrap: anywhere; }
.tcf-sub { margin: 0; font-size: .86rem; line-height: 1.5; color: var(--text-muted); max-width: 60ch; }
/* the step indicator: 1 Name, 2 Invite, 3 Top up, joined by a hairline */
.tcf-steps { list-style: none; margin: 0; padding: 0 44px 0 0; display: flex; align-items: center; gap: 0; }
.tcf-steps li { display: inline-flex; align-items: center; gap: 8px; font-size: .78rem; font-weight: 600; color: var(--text-faint); white-space: nowrap; }
.tcf-steps li + li::before { content: ""; width: 28px; height: 1px; margin: 0 10px; background: var(--border-strong); }
.tcf-steps li.done + li::before { background: var(--accent-border); }
.tcf-steps li.on { color: var(--text); }
.tcf-steps li.done { color: var(--text-muted); }
.tcf-dot { width: 22px; height: 22px; border-radius: 50%; display: inline-grid; place-items: center; flex: none;
  font: 700 .72rem/1 var(--font-sans); background: var(--surface-2); color: var(--text-faint); }
.tcf-steps li.on .tcf-dot { background: var(--accent); color: var(--on-accent); }
.tcf-steps li.done .tcf-dot { background: var(--accent-weak); color: var(--accent); }
.tcf-dot svg { width: 13px; height: 13px; }
.tcf-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 18px 24px 4px; display: flex; flex-direction: column; gap: 8px; }
@media (prefers-reduced-motion: no-preference) { .tcf-body.enter { animation: tcfIn .2s cubic-bezier(.16, 1, .3, 1); } }
@keyframes tcfIn { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: none; } }
.tcf-field { font-size: .8rem; font-weight: 600; color: var(--text-muted); }
.tcf-body > .select, .tcf-pane > .select { width: 100%; }
.tcf-help { margin: 0; font-size: .8rem; line-height: 1.5; color: var(--text-muted); }
.tcf-err { margin: 0; font-size: .8rem; line-height: 1.45; color: var(--danger); }
.tcf-err:empty { display: none; }
.tcf [aria-invalid="true"] { border-color: var(--danger) !important; }
/* invite: the chip field. Wraps, then scrolls inside its own box (50 pasted addresses stay put). */
.tcf-chipbox { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-height: 48px; max-height: 212px; overflow-y: auto;
  padding: 8px; border: 1px solid var(--border-strong); border-radius: var(--r-md); background: var(--surface-2); cursor: text; }
.tcf-chipbox:focus-within { border-color: var(--accent-border); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }
html[data-tone="b"] .tcf-chipbox { border-color: transparent; background: rgba(255,255,255,.05); }
html[data-tone="b"] .tcf-chipbox:focus-within { border-color: var(--accent-border); }
.tcf-chips { display: contents; }
html .tcf .tcf-chipbox > input { flex: 1 1 160px; min-width: 120px; height: 30px; padding: 0 4px; border: 0; background: transparent;
  color: var(--text); font: inherit; font-size: .88rem; outline: none; box-shadow: none; }
html .tcf .tcf-chipbox > input:focus { border: 0; box-shadow: none; }
.tcf-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; height: 30px; padding: 0 4px 0 10px;
  border-radius: var(--r-pill); background: color-mix(in srgb, var(--text) 9%, transparent); border: 1px solid transparent; font-size: .8rem; color: var(--text); }
.tcf-chip-e { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
button.tcf-chip-e { background: none; border: 0; padding: 0; color: inherit; font: inherit; cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.tcf-chip-s { display: inline-flex; align-items: center; gap: 3px; flex: none; font-size: .72rem; font-weight: 600; color: var(--text-muted); padding-right: 6px; }
.tcf-chip-s svg { width: 12px; height: 12px; }
.tcf-chip-x { flex: none; width: 22px; height: 22px; display: inline-grid; place-items: center; padding: 0; border: 0; border-radius: 50%;
  background: transparent; color: var(--text-muted); cursor: pointer; }
.tcf-chip-x:hover { background: rgba(255,255,255,.08); color: var(--text); }
.tcf-chip-x svg { width: 14px; height: 14px; }
.tcf-chip.s-bad, .tcf-chip.s-failed { border-color: color-mix(in srgb, var(--danger) 55%, transparent); background: var(--danger-weak); }
.tcf-chip.s-bad .tcf-chip-s, .tcf-chip.s-failed .tcf-chip-s { color: var(--danger); }
.tcf-chip.s-sending { opacity: .65; }
.tcf-chip.s-sent { background: var(--ok-weak); }
.tcf-chip.s-sent .tcf-chip-s { color: var(--ok); }
.tcf-chip.s-sent, .tcf-chip.s-member, .tcf-chip.s-invited { padding-right: 4px; }
.tcf-chip.s-member, .tcf-chip.s-invited { color: var(--text-muted); }
.tcf-msg { display: grid; gap: 4px; }
.tcf-msg:empty { display: none; }
.tcf-note { margin: 0; font-size: .8rem; line-height: 1.45; color: var(--text-muted); overflow-wrap: anywhere; }
.tcf-note.err { color: var(--danger); }
.tcf-note.ok { color: var(--ok); }
.tcf-inl { padding: 0; font-size: inherit; text-decoration: underline; text-underline-offset: 3px; }
/* top up: two ways in, side by side; the chosen one opens below */
.tcf-opts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 8px; }
.tcf-opt { display: grid; gap: 3px; text-align: left; padding: 12px 14px; border-radius: var(--r-md); cursor: pointer; font: inherit;
  background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text-muted); transition: border-color .15s, background-color .15s; }
.tcf-opt b { color: var(--text); font-size: .88rem; font-weight: 600; }
.tcf-opt span { font-size: .78rem; }
.tcf-opt:hover { border-color: var(--accent-border); }
.tcf-opt.on { border-color: var(--accent); background: var(--accent-weak); }
html[data-tone="b"] .tcf-opt { border-color: transparent; background: rgba(255,255,255,.05); }
html[data-tone="b"] .tcf-opt.on { background: var(--raised); box-shadow: 0 0 0 1.5px var(--accent-border); }
.tcf-opt:active, .tcf-chip-x:active { transform: scale(.98); }
.tcf-pane { display: flex; flex-direction: column; gap: 8px; }
.tcf-pane .al-chips { margin-top: 2px; }
/* the footer: Back on the left, Skip and the step's action on the right; a close-confirm takes it over */
.tcf-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 16px 24px 22px; }
.tcf-foot .l, .tcf-foot .r { display: inline-flex; align-items: center; gap: 8px; }
.tcf-foot .r { margin-left: auto; }
.tcf-foot button { white-space: nowrap; }
.tcf-confirm { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; width: 100%; padding: 12px 14px;
  border-radius: var(--r-md); background: var(--warn-weak); font-size: .86rem; color: var(--text); }
.tcf-confirm > span:first-child { flex: 1 1 220px; }
.tcf-confirm.tcf-ask { background: var(--accent-weak); }   /* renamed with invites out: a question, not a warning */
.tcf-confirm .r { display: inline-flex; gap: 8px; margin-left: auto; }
@media (max-width: 640px) {
  .modal-overlay:has(.tcf) { padding: 0; align-items: stretch; }
  .modal-card:has(.tcf) { max-width: none; height: 100dvh; max-height: 100dvh; border-radius: 0; }
  html[data-tone="b"] .modal-card:has(.tcf) { border-radius: 0; }
  .tcf { min-width: 0; max-height: none; height: 100%; }
  .tcf-head { padding: 18px 16px 0; }
  .tcf-steps { padding-right: 40px; }
  .tcf-steps li + li::before { width: 14px; margin: 0 6px; }
  .tcf-body { padding: 16px 16px 8px; }
  .tcf-chipbox { max-height: 40dvh; }
  .tcf-opts { grid-template-columns: 1fr; }
  .tcf-foot { padding: 12px 16px calc(14px + env(safe-area-inset-bottom)); border-top: 1px solid var(--border); }
  .tcf-foot :is(.btn-neon, .btn-ghost) { padding: 10px 14px; font-size: .88rem; }
  .tcf-confirm .r { width: 100%; justify-content: flex-end; }
}
/* ONE EMPTY CARD (team.js emptyCard / spaceEmptyHtml): Home in a team, Library, References and the
   Team page's Credits and Activity tabs. The Accounts page's shape: icon, bold title, two lines, a
   primary and a secondary action, centred on a filled surface (no frame). */
.sp-empty { grid-column: 1 / -1; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px;
  padding: 44px 24px; margin: 4px 0 12px; border-radius: 16px; background: var(--surface); }
html[data-tone="b"] .sp-empty { background: rgba(255,255,255,.035); }
.sp-empty-ic { width: 52px; height: 52px; margin-bottom: 4px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-muted); }
.sp-empty-ic svg { width: 22px; height: 22px; }
.sp-empty h3 { margin: 0; font: 650 1.3rem/1.25 var(--font-display); color: var(--text); overflow-wrap: anywhere; }
.sp-empty p { margin: 0; max-width: 48ch; color: var(--text-muted); font-size: .9rem; line-height: 1.5; }
.sp-empty-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 8px; }
.sp-empty-acts button { white-space: nowrap; }
.sp-empty.is-filtered { padding: 32px 24px; }
.empty.sp-host { padding: 8px 0 0; }                                  /* Library's #libEmpty holds the card */
#refEmptyCard { margin-top: 18px; }
.tm-grid2 .sp-empty { margin: 0; }
.view-references.ref-is-empty .ref-split { display: none; }          /* one card, not three empty panes */
.view-references.ref-space-empty :is(.ref-actions, #refMaskToggle) { display: none !important; }
@media (max-width: 640px) {
  .sp-empty { padding: 32px 16px; }
  .sp-empty-acts { width: 100%; }
  .sp-empty-acts button { flex: 1 1 140px; }
}

/* THE TEAM PAGE STAT STRIP (team.js ownerTiles): one filled surface, four cells with hairlines
   between, the pool first and a size up. Replaces four framed tiles. 2 x 2 on a phone. */
.tm-stats { display: grid; grid-template-columns: 1.25fr 1fr 1fr 1fr; margin: 0 0 18px; border-radius: 16px; background: var(--surface); overflow: hidden; }
html[data-tone="b"] .tm-stats { background: rgba(255,255,255,.035); }
.tm-stat { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 18px 20px; }
.tm-stat + .tm-stat { box-shadow: inset 1px 0 0 var(--border); }
.tm-stat-k { font-size: .78rem; font-weight: 600; color: var(--text-muted); }
.tm-stat-v { display: flex; align-items: center; gap: 10px; font: 650 1.55rem/1.15 var(--font-display); color: var(--text); font-variant-numeric: tabular-nums; }
.tm-stat.lead .tm-stat-v { font-size: 2rem; }
.tm-stat-s { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; font-size: .8rem; color: var(--text-faint); }
.tm-stat-link { padding: 0; font-size: inherit; font-weight: 600; color: var(--accent); }
.tm-faces { display: inline-flex; }
.tm-faces .space-sq { width: 24px; height: 24px; font-size: .68rem; box-shadow: 0 0 0 2px var(--bg); }
.tm-faces .space-sq + .space-sq { margin-left: -7px; }
.tm-faces .tm-more { width: auto; min-width: 24px; padding: 0 6px; border-radius: 999px; background: var(--surface-2); color: var(--text-muted); }
/* Members tab with only the owner: a light prompt row under them */
.tm-alone { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 8px 0 0; padding: 10px 10px 10px 16px;
  border-radius: 12px; background: var(--accent-weak); font-size: .86rem; color: var(--text); }
@media (max-width: 640px) {
  .tm-stats { grid-template-columns: 1fr 1fr; }
  .tm-stat { padding: 14px 16px; }
  .tm-stat + .tm-stat { box-shadow: none; }
  .tm-stat:nth-child(even) { box-shadow: inset 1px 0 0 var(--border); }
  .tm-stat:nth-child(n+3) { box-shadow: inset 0 1px 0 var(--border); }
  .tm-stat:nth-child(4) { box-shadow: inset 1px 0 0 var(--border), inset 0 1px 0 var(--border); }
  .tm-stat-v { font-size: 1.3rem; }
  .tm-stat.lead .tm-stat-v { font-size: 1.6rem; }
}
/* THE ANNOUNCEMENT (team.js announceCard): pinned at the top of the Team page for everyone, on
   Home for members (dismissible), and in Settings as the owner's read view. */
.tm-ann { display: grid; gap: 10px; margin: 0 0 16px; padding: 16px 18px; border-radius: 16px; background: var(--surface);
  box-shadow: inset 3px 0 0 var(--accent); }
html[data-tone="b"] .tm-ann { background: rgba(255,255,255,.035); }
.tm-ann-h { display: flex; align-items: center; gap: 10px; min-width: 0; }
.tm-ann-h .space-sq { width: 30px; height: 30px; flex: none; }
.tm-ann-who { display: grid; min-width: 0; line-height: 1.3; }
.tm-ann-who b { font-size: .9rem; color: var(--text); }
.tm-ann-who span { font-size: .76rem; color: var(--text-faint); }
.tm-ann-x { margin-left: auto; flex: none; width: 28px; height: 28px; display: grid; place-items: center; padding: 0; border: 0;
  border-radius: 50%; background: transparent; color: var(--text-muted); cursor: pointer; }
.tm-ann-x:hover { background: rgba(255,255,255,.08); color: var(--text); }
.tm-ann-x svg { width: 15px; height: 15px; }
.tm-ann-t { margin: 0; font-size: .95rem; line-height: 1.55; color: var(--text); white-space: pre-wrap; overflow-wrap: anywhere; }
#tmHomeAnn .tm-ann { margin-bottom: 18px; }

/* SETTINGS (team.js settingsPanel): sections with a label column and the control beside it. */
.tm-set { display: grid; }
.tm-sec { display: grid; grid-template-columns: minmax(180px, 260px) minmax(0, 1fr); gap: 16px 40px; padding: 24px 0;
  border-top: 1px solid var(--border); }
.tm-sec:first-child { border-top: 0; padding-top: 8px; }
.tm-sec-l h3 { margin: 0 0 4px; font-size: .95rem; font-weight: 600; color: var(--text); }
.tm-sec-l p { margin: 0; font-size: .82rem; line-height: 1.5; color: var(--text-muted); }
.tm-sec-r { display: grid; gap: 8px; min-width: 0; max-width: 620px; align-content: start; }
.tm-inline { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.tm-inline > .select { flex: 1 1 240px; min-width: 0; }
.tm-inline-acts { display: inline-flex; gap: 8px; }
.tm-inline-acts.hidden { display: none; }
.tm-saved { display: inline-flex; align-items: center; gap: 5px; font-size: .8rem; font-weight: 600; color: var(--ok); }
.tm-saved svg { width: 14px; height: 14px; }
@media (prefers-reduced-motion: no-preference) { .tm-saved { animation: tmSaved 2.4s ease forwards; } }
@keyframes tmSaved { 0%, 70% { opacity: 1; } 100% { opacity: 0; } }
.tm-ann-ta { width: 100%; min-height: 104px; resize: vertical; line-height: 1.5; }
.tm-ann-foot, .tm-ann-meta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.tm-ann-meta { font-size: .8rem; color: var(--text-muted); }
.tm-sec-r .tm-ann { margin: 0; }
.tm-count { font-size: .78rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.tm-count.over { color: var(--danger); font-weight: 600; }
.tm-ann-none { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; padding: 14px 16px;
  border-radius: 12px; background: var(--surface-2); }
html[data-tone="b"] .tm-ann-none { background: rgba(255,255,255,.035); }
.tm-ann-none p, .tm-ann-none-t { margin: 0; font-size: .86rem; color: var(--text-muted); }
.tm-kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 10px 20px; margin: 0; align-items: center; }
.tm-kv dt { font-size: .8rem; color: var(--text-muted); }
.tm-kv dd { margin: 0; font-size: .9rem; color: var(--text); overflow-wrap: anywhere; }
.tm-kv .tm-who .space-sq { width: 24px; height: 24px; }
.tm-sec.danger .tm-sec-l h3 { color: var(--danger); }
.tm-danger-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px 24px; padding: 14px 16px;
  border-radius: 12px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--danger) 28%, transparent); }
.tm-danger-row b { font-size: .9rem; color: var(--text); }
.tm-danger-row p { margin: 4px 0 0; font-size: .82rem; line-height: 1.5; color: var(--text-muted); max-width: 60ch; }
/* the Accounts page's Remove: a text button that turns red, not a filled alarm */
.tm-danger-btn { flex: none; height: 34px; padding: 0 12px; border: 0; border-radius: 10px; background: transparent; cursor: pointer;
  font: inherit; font-size: .85rem; font-weight: 600; color: var(--danger); white-space: nowrap; }
.tm-danger-btn:hover { background: var(--danger-weak); }
.tm-danger-btn:focus-visible { outline: none; box-shadow: 0 0 0 1.5px var(--danger); }
.tm-confirm-name { color: var(--text); overflow-wrap: anywhere; }
@media (max-width: 640px) {
  .tm-sec { grid-template-columns: 1fr; gap: 12px; padding: 20px 0; }
  .tm-danger-row { flex-direction: column; }
  .tm-inline > .select { flex-basis: 100%; }
}
/* THE CREDITS PAGE IN A TEAM (team.js paintCreditsSpace): one compact row in place of the personal
   top-up. */
.tm-cred-note { display: flex; align-items: center; gap: 16px; margin: 16px 0 0; padding: 16px 18px; border-radius: 16px; background: var(--surface); }
html[data-tone="b"] .tm-cred-note { background: rgba(255,255,255,.035); }
.tm-cred-note-ic { flex: none; width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; background: var(--surface-2); color: var(--text-muted); }
.tm-cred-note-ic svg { width: 20px; height: 20px; }
.tm-cred-note-t { display: grid; gap: 3px; min-width: 0; flex: 1; }
.tm-cred-note-t b { font-size: .95rem; color: var(--text); }
.tm-cred-note-t span { font-size: .84rem; color: var(--text-muted); }
.tm-cred-note button { flex: none; white-space: nowrap; }
@media (max-width: 640px) { .tm-cred-note { flex-wrap: wrap; } .tm-cred-note button { width: 100%; } }

/* THE BELL, GROUPED BY SPACE (notify.js, T4): a header per space with its counts, the space on
   screen first. */
.notif-group-h { display: flex; align-items: center; gap: 8px; padding: 10px 16px 4px; font-size: .72rem; font-weight: 700;
  letter-spacing: .02em; color: var(--text-muted); }
.notif-group-h .space-sq { width: 18px; height: 18px; font-size: .62rem; }
.notif-group-h .n { margin-left: auto; font-weight: 600; color: var(--text-faint); }
.notif-group-h .n b { color: var(--accent); font-weight: 700; }
.notif-group-h.here::after { content: "Here"; order: 2; padding: 1px 6px; border-radius: 999px; background: var(--accent-weak); color: var(--accent); font-size: .66rem; }
.notif-group + .notif-group { border-top: 1px solid var(--border); margin-top: 4px; }
/* ==== end CREATE A TEAM ========================================================================= */

/* ==== ACCOUNTS PAGE, OPTION C (owner, 2026-10-15) =============================================
   Platform tabs over one list of rich rows (accounts.js proView). A row: who, which workspaces
   post here, the last post, the next one. Health shows only when something is wrong. A row opens
   in place. Fills, not frames; platform colours only as small icon tints; radius 16 for the list
   and banner, 12 for rows and tiles, 8 for thumbnails, pills for controls. All classes acx-. */
.acx-p-tiktok { color: #6FE3E6; } .acx-p-instagram { color: #F286B4; } .acx-p-email { color: var(--text-muted); }
.acx-tools { display: flex; align-items: center; gap: 12px; margin: 0 0 14px; }
.acx-tabs { height: 40px; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.acx-tabs::-webkit-scrollbar { display: none; }
.acx-tabs .ws-filter-b { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; padding: 0 14px; }
.acx-tabs .ws-filter-b svg { width: 14px; height: 14px; display: block; }
.acx-n { color: var(--text-faint); font-weight: 500; font-size: .76rem; }
.acx-list { display: flex; flex-direction: column; gap: 4px; }
.acx-row { background: var(--surface); border-radius: var(--r-md); overflow: hidden; }
.acx-row:first-child { border-top-left-radius: 16px; border-top-right-radius: 16px; }
.acx-row:last-child { border-bottom-left-radius: 16px; border-bottom-right-radius: 16px; }
.acx-main { display: grid; grid-template-columns: auto minmax(0, 1fr) minmax(0, 250px) 190px auto; align-items: center;
  gap: 18px; padding: 14px 16px; cursor: pointer; transition: background .15s; }
.acx-main:hover, .acx-row.open .acx-main { background: var(--surface-2); }
.acx-main:focus-visible { outline: none; box-shadow: inset 0 0 0 1.5px var(--accent-border); }
.acx-av { position: relative; flex: none; width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  background: var(--raised, #26262B); color: var(--text); font: 600 .95rem/1 var(--font-sans); }
.acx-av.is-email svg { width: 18px; height: 18px; color: var(--text-muted); }
.acx-badge { position: absolute; right: -3px; bottom: -3px; width: 19px; height: 19px; border-radius: 50%;
  display: grid; place-items: center; background: var(--bg); }
.acx-badge svg { width: 11px; height: 11px; }
.acx-who { min-width: 0; }
.acx-l1 { display: flex; align-items: center; gap: 8px; min-width: 0; }
.acx-name { font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.acx-status { flex: none; display: inline-flex; align-items: center; gap: 6px; font-size: .8rem; font-weight: 600; white-space: nowrap; }
.acx-status svg { width: 15px; height: 15px; }
.acx-status.is-expired { color: var(--warn); }
.acx-status.is-off { color: var(--text-muted); }
.acx-l2 { color: var(--text-faint); font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
.acx-l2 b { color: var(--text-muted); font-weight: 500; }
.acx-last { display: flex; align-items: center; gap: 10px; min-width: 0; font-size: .82rem; }
.acx-last-t { display: flex; flex-direction: column; min-width: 0; }
.acx-last-t > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acx-thumb { flex: none; width: 30px; aspect-ratio: 9 / 13; border-radius: 8px; object-fit: cover; background: var(--raised, #26262B); }
.acx-thumb.is-bad, .acx-post img.is-bad { filter: grayscale(1) brightness(.55); }
.acx-thumb.is-gone, .acx-post img.is-gone { visibility: hidden; }
.acx-next { display: flex; align-items: center; gap: 7px; font-size: .82rem; color: var(--text-muted); min-width: 0; }
.acx-next svg { width: 14px; height: 14px; flex: none; color: var(--text-faint); }
.acx-faint { color: var(--text-faint); }
.acx-bad { color: var(--warn); }
.acx-end { display: flex; align-items: center; gap: 4px; }
.acx-kebab { display: grid; place-items: center; width: 32px; height: 32px; padding: 0; border-radius: 50%; }
.acx-kebab svg { width: 16px; height: 16px; }
.acx-kebab-sp { width: 32px; }
.acx-chev { display: grid; color: var(--text-faint); transition: transform .25s cubic-bezier(.16,1,.3,1); }
.acx-chev svg { width: 16px; height: 16px; }
.acx-row.open .acx-chev { transform: rotate(180deg); }
/* the opened row: rows animate their height from 0fr to 1fr, so it unfolds rather than jumps */
.acx-xp { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s cubic-bezier(.16,1,.3,1); }
.acx-row.open .acx-xp { grid-template-rows: 1fr; }
.acx-xp-in { overflow: hidden; min-height: 0; }
.acx-xp-grid { display: grid; grid-template-columns: 1.1fr 1.2fr .8fr; gap: 28px; padding: 6px 16px 18px 74px; background: var(--surface-2); }
.acx-xp-grid h4 { margin: 10px 0 10px; font: 600 .78rem/1.3 var(--font-sans); color: var(--text-faint); }
.acx-ws { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--r-md); background: var(--surface); }
.acx-ws + .acx-ws { margin-top: 6px; }
.acx-ws-t { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.acx-ws-t b { font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acx-ws-t span { font-size: .78rem; color: var(--text-faint); }
.acx-ws .acx-faint svg { width: 16px; height: 16px; }
.acx-slots { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.acx-slot { font-size: .76rem; font-variant-numeric: tabular-nums; color: var(--text); background: var(--raised, #26262B);
  border-radius: var(--r-pill); padding: 2px 9px; }
.acx-posts { display: grid; grid-template-columns: repeat(4, minmax(0, 96px)); gap: 10px; }
.acx-post { margin: 0; min-width: 0; }
.acx-post img { width: 100%; aspect-ratio: 9 / 13; border-radius: 8px; object-fit: cover; background: var(--raised, #26262B); display: block; }
.acx-post figcaption { display: flex; flex-direction: column; margin-top: 6px; font-size: .78rem; line-height: 1.35; }
.acx-none { margin: 0; padding: 12px 14px; border-radius: var(--r-md); background: var(--surface); color: var(--text-faint); font-size: .84rem; }
.acx-kv { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 0; font-size: .86rem; }
.acx-kv + .acx-kv { box-shadow: inset 0 1px 0 var(--border); }
.acx-kv > span:first-child { color: var(--text-muted); }
.acx-acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.acx-acts .btn-ghost { display: inline-flex; align-items: center; gap: 6px; }
.acx-acts svg { width: 14px; height: 14px; }
.acx-alert { display: flex; align-items: flex-start; gap: 12px; padding: 12px 14px; margin-top: 10px; border-radius: var(--r-md);
  background: var(--warn-weak); }
.acx-alert > svg { flex: none; width: 18px; height: 18px; margin-top: 2px; color: var(--warn); }
.acx-alert.is-off { background: var(--surface); }
.acx-alert.is-off > svg { color: var(--text-muted); }
.acx-alert > div { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: .84rem; }
.acx-alert > div b { font-weight: 600; color: var(--text); }
.acx-alert > div span { color: var(--text-muted); }
.acx-banner { display: flex; align-items: center; gap: 14px; padding: 14px 16px; margin: 0 0 16px; border-radius: 16px; background: var(--warn-weak); }
.acx-banner > svg { flex: none; width: 20px; height: 20px; color: var(--warn); }
.acx-banner > div { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: .86rem; }
.acx-banner > div b { color: var(--text); font-weight: 600; }
.acx-banner > div span { color: var(--text-muted); }
:is(.acx-banner, .acx-alert) .btn-neon.sm { padding: 7px 14px; font-size: .82rem; white-space: nowrap; }
.acx-banner .btn-ghost.sm, .acx-alert .btn-ghost.sm { white-space: nowrap; }
.acx-add { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 8px; padding: 14px 4px 0; color: var(--text-muted); font-size: .86rem; }
.acx-add > span:first-child { margin-right: auto; }
.acx-add .btn-ghost { display: inline-flex; align-items: center; gap: 7px; }
.acx-add svg, .acx-empty-acts svg { width: 14px; height: 14px; }
.acx-note { text-align: center; margin-top: 12px; }
.acx-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: 44px 24px;
  margin: 0 0 12px; border-radius: 16px; background: var(--surface); }
.acx-empty-ics { display: flex; gap: 10px; margin-bottom: 4px; }
.acx-empty-ics > span { width: 52px; height: 52px; border-radius: 50%; display: grid; place-items: center; background: var(--surface-2); }
.acx-empty-ics svg { width: 22px; height: 22px; }
.acx-empty h3 { margin: 0; font: 650 1.3rem/1.2 var(--font-display); color: var(--text); }
.acx-empty p { margin: 0; max-width: 46ch; color: var(--text-muted); }
.acx-empty-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 8px; }
.acx-empty-acts button { display: inline-flex; align-items: center; gap: 8px; }
@media (max-width: 900px) {
  .acx-main { grid-template-columns: auto minmax(0, 1fr) minmax(0, 200px) auto; }
  .acx-next { display: none; }
  .acx-xp-grid { grid-template-columns: 1fr 1fr; padding-left: 16px; }
  .acx-xp-grid > div:first-child { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .acx-main { grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; padding: 12px; }
  .acx-last { display: none; }
  .acx-l1 { flex-wrap: wrap; row-gap: 2px; }
  .acx-xp-grid { grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 0 12px 14px; }
  .acx-posts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .acx-posts .acx-post:nth-child(4) { display: none; }
  .acx-banner { flex-wrap: wrap; align-items: flex-start; padding: 12px; }
  .acx-banner > div { flex-basis: calc(100% - 34px); }
  .acx-banner > button { margin-left: 34px; }
  .acx-tools { margin-bottom: 12px; }
  .acx-tabs { width: 100%; }
  .acx-tabs .ws-filter-b { flex: 1 0 auto; padding: 0 10px; }
  .acx-add { justify-content: flex-start; }
  .acx-add > span:first-child { flex-basis: 100%; }
  .acx-empty { padding: 30px 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .acx-xp, .acx-chev, }
/* many workspaces on one account (2026-10-15): one line + "+N more", a load line, a capped list */
.acx-l2 { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.acx-wsn { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acx-more { flex: none; color: var(--text-muted); font-weight: 500; }
.acx-more:empty { display: none; }
.acx-load { font-size: .82rem; color: var(--text-muted); margin: 0 0 8px; }
.acx-load-warn { display: flex; align-items: flex-start; gap: 7px; margin: -2px 0 10px; font-size: .8rem; color: var(--text-muted); }
.acx-load-warn svg { flex: none; width: 14px; height: 14px; margin-top: 2px; color: var(--warn); }
.acx-ws-open { display: block; max-width: 100%; padding: 0; border: 0; background: none; font: inherit; font-weight: 600;
  color: var(--text); text-align: left; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acx-ws-open:hover, .acx-ws-open:focus-visible { color: var(--accent); outline: none; text-decoration: underline; text-underline-offset: 3px; }
.acx-ws.is-paused { opacity: .55; }
.acx-paused-tag { flex: none; font-size: .72rem; font-weight: 600; color: var(--text-muted); background: var(--raised, #26262B);
  border-radius: var(--r-pill); padding: 2px 9px; }
.acx-slot.is-more { color: var(--text-muted); }
.acx-slots { flex-wrap: nowrap; }
.acx-wsall { margin-top: 8px; padding: 6px 12px; border: 0; border-radius: var(--r-pill); background: var(--surface);
  color: var(--text); font: inherit; font-size: .8rem; font-weight: 600; cursor: pointer; }
.acx-wsall:hover { background: var(--raised, #26262B); }
.acx-wssearch { display: flex; margin: 0 0 8px; }
.acx-wssearch input { width: 100%; height: 34px; padding: 0 12px; border: 0; border-radius: var(--r-pill);
  background: var(--surface); color: var(--text); font: inherit; font-size: .84rem; outline: none; }
.acx-wssearch input::placeholder { color: var(--text-faint); }
.acx-wssearch input:focus-visible { box-shadow: 0 0 0 1.5px var(--accent-border); }
.acx-wsscroll { max-height: 320px; overflow-y: auto; padding-right: 4px; scrollbar-width: thin; scrollbar-color: var(--raised, #26262B) transparent; }
.acx-wsscroll .acx-ws[hidden] { display: none; }
/* a post opens the Library's clip drawer: the thumbnail is a button with a play mark */
.acx-play { position: relative; display: block; width: 100%; padding: 0; border: 0; border-radius: 8px; background: none; cursor: pointer; }
.acx-play-sm { width: auto; flex: none; }
.acx-play:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-border); }
.acx-play-ic { position: absolute; inset: 0; display: grid; place-items: center; opacity: 0; transition: opacity .15s;
  border-radius: 8px; background: rgba(0,0,0,.28); pointer-events: none; }
.acx-play-ic svg { width: 22px; height: 22px; color: #F2F2F4; filter: drop-shadow(0 1px 4px rgba(0,0,0,.5)); }
.acx-play-sm .acx-play-ic svg { width: 13px; height: 13px; }
.acx-play:hover .acx-play-ic, .acx-play:focus-visible .acx-play-ic { opacity: 1; }
@media (hover: none) { .acx-play-ic { opacity: 1; background: rgba(0,0,0,.16); } }
.acx-post-gone { display: grid; place-items: center; aspect-ratio: 9 / 13; padding: 8px; border-radius: 8px; text-align: center;
  background: var(--surface); color: var(--text-faint); font-size: .72rem; line-height: 1.3; }
.acx-thumb.is-gone-tile { display: block; }
@media (max-width: 640px) {
  .acx-slots { flex-wrap: wrap; max-width: 45%; }
  .acx-wsscroll { max-height: 300px; }
}
/* the actions (owner, 2026-10-15): icon + label, one height; Remove is a quiet text link */
.acx-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 14px; }
.acx-act { display: inline-flex; align-items: center; justify-content: center; gap: 7px; height: 34px; padding: 0 14px;
  border: 0; border-radius: var(--r-pill); background: rgba(255,255,255,.06); color: var(--text);
  font: inherit; font-size: .82rem; font-weight: 600; cursor: pointer; white-space: nowrap; transition: background .15s; }
.acx-act:hover { background: rgba(255,255,255,.1); }
.acx-act:active { transform: translateY(1px); }
.acx-act:focus-visible, .acx-remove:focus-visible { outline: none; box-shadow: 0 0 0 1.5px var(--accent-border); }
.acx-act svg, .acx-remove svg { flex: none; width: 15px; height: 15px; }
.acx-act.acx-act-primary { height: 34px; padding: 0 14px; color: var(--on-accent); }
.acx-remove { display: inline-flex; align-items: center; gap: 6px; height: 34px; margin-left: auto; padding: 0 4px; border: 0;
  background: none; color: var(--text-faint); font: inherit; font-size: .82rem; font-weight: 500; cursor: pointer; border-radius: 6px; }
.acx-remove:hover { color: var(--danger); }
@media (max-width: 640px) {
  .acx-acts { display: grid; grid-template-columns: 1fr 1fr; }
  .acx-acts .acx-act { width: 100%; }
  .acx-remove { grid-column: 1 / -1; justify-self: center; margin: 2px 0 0; }
}
/* ==== end ACCOUNTS PAGE, OPTION C ============================================================== */

/* ==== AUDIT FIXES (2026-10-15 sweep) ============================================================
   Small, separate fixes from the full-app audit. Each line says what it fixes. */
/* Workspace page: a posting error with a long unbroken string (PostFast's raw JSON) ran past the
   activity card's right edge and gave the page a horizontal scroll. */
.res-why { overflow-wrap: anywhere; }
/* Phone: the setup flow's 2px progress line kept the desktop sidebar offset (220px), so it sat
   as a short purple stub under the bell instead of running from the left edge. */
@media (max-width: 760px) {
  .home-steps-row, .app.collapsed .home-steps-row, .wizard-top, .app.collapsed .wizard-top { left: 0; }
}
/* Posting schedule: the stems of the upper time pills were drawn over the labels of the lower
   ones ("3:55 P|M"). Labels sit above every stem. */
/* Each mark is its own stacking context (its translateX), so the lower lanes are raised above
   the higher ones whose stems run down through them. */
.sday-mark { z-index: calc(20 - var(--lane, 0)); }
/* Credits > Pricing on a phone: the table kept a 560px minimum inside a 340px card, so the
   Resolution and Cost columns (the prices) were off screen. Provider goes; the rest fits. */
@media (max-width: 760px) {
  #credPricing .admin-table { min-width: 0; }
  #credPricing .admin-table th:nth-child(2), #credPricing .admin-table td:nth-child(2) { display: none; }
  #credPricing .admin-table th, #credPricing .admin-table td { padding-left: 6px; padding-right: 6px; }
}
/* Admin lists: one control height per toolbar. Export CSV was 26px beside a 41px primary
   button, and the pager's Prev / Next 26px beside a 32px select. */
.adl-end > :is(.btn-ghost, .btn-neon, button) { height: 34px; display: inline-flex; align-items: center;
  padding-top: 0; padding-bottom: 0; }
.adl-pager > :is(button, .btn-ghost) { height: 32px; display: inline-flex; align-items: center; padding-top: 0; padding-bottom: 0; }
.ao-tools > .btn-neon { height: 34px; display: inline-flex; align-items: center; padding-top: 0; padding-bottom: 0; }
.ao-tools > .icon-btn { width: 34px; height: 34px; }
td.admin-actions > .btn-ghost.mini { height: 30px; display: inline-flex; align-items: center; padding-top: 0; padding-bottom: 0; }
#adminAssetsPane .ut-bar > :is(input:not([type=file]), select, button) { height: 40px; }
@media (max-width: 760px) {
  /* Admin > Style films on a phone: the cell is a flex row (label, name, blurb side by side), so
     the style's name got a 30px column and broke letter by letter ("Any Charact er"). */
  .adl-table td:has(> .sd-name) { display: block; }
  .adl-table td:has(> .sd-name)::before { display: block; margin-bottom: 2px; }
  /* Admin > Teams > a team: the member table kept its 560px minimum inside the dialog, so Role,
     Allowance and Used were cut off at the right. */
  .modal-body .ut-wrap .admin-table { min-width: 0; }
  .modal-body .ut-wrap .admin-table td { overflow-wrap: anywhere; }
}
/* Red is for danger only. Ordinary spending in Credits > History (-8, -180) and a model that
   is simply switched off (Admin > Models "disabled") read as errors in red. */
.cred-amt.neg { color: var(--text); }
.status-badge.disabled { color: var(--text-muted); background: var(--surface-2, rgba(255,255,255,.06)); border-color: transparent; }
/* ==== end AUDIT FIXES ========================================================================== */

/* =====================================================================================
   ADMIN ROUND 3 (2026-10-15): the Assets drop zone (U4), the Activation funnel on Overview,
   the Social accounts summary, the missing-poster tile (U7) and the colour audit (U3).
   ===================================================================================== */
/* -- U4: Admin → Assets, drop or pick images, one progress row per file -- */
.aa-up { display: grid; grid-template-columns: minmax(0, 1fr) minmax(220px, 320px); gap: 10px 12px; margin-bottom: 16px; }
.aa-drop { min-height: 104px; border-width: 1.5px; border-color: var(--border-hi); background: var(--surface-2); padding: 14px 18px; }
.aa-drop:hover, .aa-drop:focus-visible { border-color: var(--accent-border); outline: none; }
.aa-drop-t { display: flex; flex-direction: column; gap: 4px; align-items: center; color: var(--text-muted); font-size: .9rem; }
.aa-drop-t b { color: var(--text); font-weight: 600; }
.aa-pick { color: var(--accent); font-weight: 600; }
.aa-opts { display: flex; flex-direction: column; gap: 8px; justify-content: center; }
.aa-queue { grid-column: 1 / -1; list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.aa-queue:empty { display: none; }
.aa-q { display: grid; grid-template-columns: minmax(0, 1fr) 160px 140px; gap: 12px; align-items: center;
  padding: 8px 12px; border-radius: var(--r-md); background: var(--surface-2); font-size: .82rem; }
.aa-qn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aa-qbar { height: 6px; border-radius: 3px; background: var(--surface); overflow: hidden; }
.aa-qbar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width .15s; }
.aa-q.ok .aa-qs { color: var(--ok); }
.aa-q.bad .aa-qs { color: var(--danger); }
.aa-q.bad .aa-qbar i { background: var(--danger); }
@media (max-width: 760px) {
  .aa-up { grid-template-columns: minmax(0, 1fr); }
  .aa-q { grid-template-columns: minmax(0, 1fr) 80px; }
  .aa-q .aa-qs { grid-column: 1 / -1; }
}
/* -- Overview: the funnel beside the worker card; Schedule: the accounts summary line -- */
.ov-funnel .ov-hb { padding: 6px 0; }
.acc-sum { margin: 0 0 10px; }
/* -- U7: a clip whose poster is gone shows its first frame, or this neutral tile -- */
.poster-ph { display: block; background: linear-gradient(135deg, var(--surface-2), var(--surface)); }
.poster-ph::after { content: ""; display: block; width: 100%; height: 100%;
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--text) 10%, transparent) 0 14%, transparent 15%); }
img.poster-ph, video.poster-fallback { background: var(--surface-2); }
.ao-th .poster-ph, .ao-tt .poster-ph { width: 100%; height: 100%; }
/* -- U3: orange (--warn) only where something needs doing (expired, failed and not refunded,
      out of credits, stuck, disconnected). Informational states turn neutral or accent: -- */
html .ao-unseen, html[data-tone] .ao-unseen { color: var(--text-faint); }               /* "unseen" */
html .run-due, html[data-tone] .run-due { color: var(--accent); }                       /* "due now" */
html .ut-unv { color: var(--text-muted); }                                              /* "unverified" */
html .ao-edited { color: var(--text-muted); }                                           /* "edited after this run" */
html .ao-tl-dot.after i { background: var(--accent); }
html .ao-tl-dot.after span { color: var(--accent); }
html .cr-trend-d.up, html[data-tone] .cr-trend-d.up { color: var(--text); }             /* "↑ 321.7%" */
html .mc-u-chip.miss, html[data-tone] .mc-u-chip.miss { color: var(--text-muted); border-color: var(--border-hi); } /* "what is it?" */
html .tst-src.own { color: var(--text-muted); }
html .toptab-admin.active { color: var(--accent); }
html .anchor-mode.on, html .ref-refresh.on,
html[data-tone] .anchor-mode.on, html[data-tone] .ref-refresh.on { color: var(--accent); background: var(--accent-weak); border-color: var(--accent-border); }
html .ao-meter.info i { background: var(--accent); }
/* AI-drawn marks are a label, not a warning: the brain colour */
html .ref-cell.ai .ref-img, html .ref-strip-i.ai, html[data-tone] .ref-strip-i.ai { border-color: var(--brain); }
html .anchor-thumb-item.is-ai { outline-color: var(--brain); }
html .ref-mark .rm-ai, html .anchor-thumb-ai, html .fit-mark i { background: linear-gradient(135deg, var(--brain), #c7a6ff); }
/* a workspace resting at its daily cap is fine, not a problem */
html .orb.capped { background: radial-gradient(circle at 34% 30%, #d9d6e0, var(--text-faint) 72%); animation: none; }
html .status-pill.capped .orb-dot { background: var(--text-faint); box-shadow: none; }
/* "capped" (the day's posts are done) on a workspace: informational, so neutral (workspaces.js) */
html .ws-top-state.warn, html[data-tone] .ws-top-state.warn { color: var(--text-muted); }
html .hero-chip.warn, html[data-tone] .hero-chip.warn { background: var(--surface-2); border-color: var(--border); color: var(--text-muted); }
html .sday-cap.at-cap { color: var(--text-muted); }
/* Out of credits (credits.js outOfCreditsModal): the balance is a number, not a warning; the
   dialog's warning mark keeps the amber, it is the thing that needs doing. */
html .ooc-nums div:first-child b, html[data-tone] .ooc-nums div:first-child b { color: var(--text); }
/* U7: the neutral tile takes the place (and the size) of the poster it stands in for */
.lib-card .poster-ph { width: 100%; aspect-ratio: 9 / 16; }
.feed-thumb.poster-ph, .wsp-shot.poster-ph, .acx-thumb.poster-ph, .acx-post .poster-ph { display: block; }
.acx-post .poster-ph { width: 100%; height: 100%; }

/* A playing / focused Library card is ringed all the way round (owner, 2026-10-15). The tone-B
   rule drew the selection ring INSET, and on a card the thumbnail paints over an inset shadow, so
   only the caption area showed purple. An outer ring sits outside the picture; the card's
   overflow:hidden clips its children, not its own shadow. */
html[data-tone="b"] .lib-card.playing { box-shadow: 0 0 0 1.5px var(--accent), 0 0 22px color-mix(in srgb, var(--accent) 22%, transparent); }
html[data-tone="b"] .lib-card.lib-focus { box-shadow: 0 0 0 2px var(--accent), 0 0 28px 4px color-mix(in srgb, var(--accent) 45%, transparent); }

/* ==== SETTINGS PAGE (settings.js, redesign 2026-10-15) ======================================
   The Team Settings language (.tm-sec): a label column and the control beside it, stacked on a
   phone, with a sticky section list on wide screens. Fills, not frames. Radius scale: 12px
   (--r-md) for fills and rows, the shared input/button radii for controls, a pill for chips.
   The gradient primary appears only on a dirty form's Save. ---------------------------------- */
.stg-head h1 { margin-bottom: 6px; }
.stg-sub { margin: 0 0 20px; font-size: .9rem; color: var(--text-muted); }
.stg { display: grid; grid-template-columns: 184px minmax(0, 1fr); gap: 40px; max-width: 1080px; align-items: start; }
.stg-nav { position: sticky; top: 96px; display: grid; gap: 2px; padding-top: 18px; }
.stg-nav button { text-align: left; padding: 8px 12px; border: 0; border-radius: var(--r-md); background: transparent; cursor: pointer;
  font: inherit; font-size: .86rem; font-weight: 500; color: var(--text-muted); }
.stg-nav button:hover { color: var(--text); background: rgba(255,255,255,.04); }
.stg-nav button.on { color: var(--text); font-weight: 600; background: var(--surface); }
.stg-nav button:focus-visible { outline: none; box-shadow: 0 0 0 1.5px var(--accent); }
.stg-body { display: grid; min-width: 0; }
.stg-sec { display: grid; grid-template-columns: minmax(170px, 230px) minmax(0, 1fr); gap: 16px 40px; padding: 26px 0;
  border-top: 1px solid var(--border); scroll-margin-top: 88px; }
.stg-sec:first-child { border-top: 0; padding-top: 16px; }
.stg-sec-l h2 { margin: 0 0 4px; font-family: var(--font-sans); font-size: .98rem; font-weight: 600; letter-spacing: 0; color: var(--text); }
.stg-sec-l p { margin: 0; font-size: .84rem; line-height: 1.5; color: var(--text-muted); }
.stg-sec-r { display: grid; gap: 14px; min-width: 0; max-width: 560px; align-content: start; }
.stg-form, .stg-block { display: grid; gap: 6px; min-width: 0; }
.stg-field { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: .84rem; font-weight: 600; color: var(--text); }
.stg-sublabel { margin-top: 4px; font-size: .8rem; font-weight: 500; color: var(--text-muted); }
.stg-form > .select, .stg-inline > .select { width: 100%; min-width: 0; }
.stg-inline { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.stg-inline > .select { flex: 1 1 240px; }
.stg-acts { display: inline-flex; gap: 8px; }
.stg-acts.hidden, .stg-saved.hidden, .stg-verify.hidden, .stg-chip.hidden, .stg-kv.hidden { display: none; }
.stg-form-foot { min-height: 0; }
.stg-form-foot:not(:has(.stg-acts:not(.hidden), .stg-saved:not(.hidden), .stg-help:not(:empty))) { display: none; }
.stg-help { margin: 0; font-size: .8rem; line-height: 1.5; color: var(--text-muted); }
.stg-help:empty, .stg-err:empty { display: none; }
.stg-help b { color: var(--text); font-weight: 600; }
.stg-err { margin: 0; font-size: .8rem; line-height: 1.45; color: var(--danger); }
.view-settings [aria-invalid="true"] { border-color: var(--danger) !important; }
.stg-saved { display: inline-flex; align-items: center; gap: 5px; font-size: .8rem; font-weight: 600; color: var(--ok); white-space: nowrap; }
.stg-saved svg { width: 14px; height: 14px; }
@media (prefers-reduced-motion: no-preference) { .stg-saved { animation: stgSaved 2.6s ease forwards; } }
@keyframes stgSaved { 0%, 70% { opacity: 1; } 100% { opacity: 0; } }
.stg-show { border: 0; padding: 2px 6px; border-radius: 8px; background: transparent; cursor: pointer; font: inherit; font-size: .78rem; font-weight: 600; color: var(--text-muted); }
.stg-show:hover { color: var(--text); background: rgba(255,255,255,.05); }
.stg-kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 20px; margin: 0; }
.stg-kv dt { font-size: .8rem; color: var(--text-muted); }
.stg-kv dd { margin: 0; font-size: .86rem; color: var(--text); }
.stg-email { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; min-height: 40px; padding: 8px 12px;
  border-radius: var(--r-md); background: var(--surface); }
.stg-email-v { font-size: .9rem; color: var(--text); overflow-wrap: anywhere; min-width: 0; }
.stg-chip { display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: var(--r-pill); font-size: .72rem; font-weight: 600; }
.stg-chip.ok { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
.stg-chip.warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
.stg-verify { display: grid; gap: 8px; justify-items: start; padding: 12px 14px; border-radius: var(--r-md);
  background: color-mix(in srgb, var(--warn) 7%, transparent); }
.stg-verify p { margin: 0; font-size: .82rem; line-height: 1.5; color: var(--text-muted); }
.stg-row { display: flex; align-items: center; justify-content: space-between; gap: 12px 20px; padding: 14px 16px;
  border-radius: var(--r-md); background: var(--surface); }
.stg-row.stg-row-top { align-items: flex-start; }
.stg-row b { display: block; font-size: .9rem; font-weight: 600; color: var(--text); }
.stg-row p { margin: 4px 0 0; font-size: .82rem; line-height: 1.5; color: var(--text-muted); }
.stg-row > button { flex: none; }
.stg-list { margin: 8px 0 0; padding-left: 18px; display: grid; gap: 3px; font-size: .84rem; line-height: 1.45; color: var(--text-muted); }
.stg-sw { flex: none; display: inline-flex; align-items: center; gap: 10px; }
html[data-tone] .stg-sw .switch input:checked + .track { background: var(--accent); box-shadow: none; }
.stg-link { display: flex; align-items: center; justify-content: space-between; gap: 16px; width: 100%; padding: 14px 16px; border: 0;
  border-radius: var(--r-md); background: var(--surface); cursor: pointer; text-align: left; font: inherit; color: var(--text); }
.stg-link:hover { background: var(--surface-2); }
.stg-link:focus-visible { outline: none; box-shadow: 0 0 0 1.5px var(--accent); }
.stg-link > span:first-child { display: grid; gap: 3px; min-width: 0; }
.stg-link b { font-size: .9rem; font-weight: 600; }
.stg-link > span:first-child > span { font-size: .82rem; line-height: 1.45; color: var(--text-muted); }
.stg-link-go { flex: none; display: inline-flex; align-items: center; gap: 4px; font-size: .82rem; font-weight: 600; color: var(--text-muted); }
.stg-link:hover .stg-link-go { color: var(--text); }
.stg-link-go svg { width: 15px; height: 15px; }
html[data-tone="b"] :is(.stg-row, .stg-link, .stg-email, .stg-nav button.on) { background: rgba(255,255,255,.035); }
html[data-tone="b"] .stg-link:hover { background: rgba(255,255,255,.06); }
@media (max-width: 1023px) {
  .stg { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .stg-nav { display: none; }
}
@media (max-width: 640px) {
  .stg-sec { grid-template-columns: minmax(0, 1fr); gap: 12px; padding: 22px 0; }
  .stg-inline > .select { flex-basis: 100%; }
  .stg-row:not(.stg-row-top) { flex-direction: column; align-items: stretch; }
  .stg-row:not(.stg-row-top) > button { align-self: flex-start; }
  .stg-link-go { font-size: 0; gap: 0; }
}

/* ==== SAVE CHANGES BAR, BRIEF DRAFT, WORKSPACE CHANGE RECORD (savebar.js, brain.js, wschanges.js, 2026-10-15) ====
   The bar rides on top of the step's own fixed action bar (#askForm / .wizard-nav), only while an
   existing workspace has unsaved changes, and briefly to say they saved. */
/* OPTION B (owner, 2026-10-15). One primary at a time: while something is unsaved, Save changes is
   the only filled button and Next, ‹ Back and Start turn grey; once saved, Next is the primary
   again. Every button in the bar is 40px tall, 12px corners, 600 14px. A hairline divides the save
   group (Discard · Save changes) from the navigation (‹ Back · Next). */
.savebar { flex: 1 1 auto; min-width: 0; display: flex; }
.savebar.hidden { display: none; }
.has-savebar .bar-inner > .step-go:not(.step-back), .has-savebar .bar-inner > #wizBack { margin-left: 0; }
.savebar .sb-inner { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 10px; }
.savebar .sb-state { flex: 1 1 auto; display: inline-flex; align-items: center; gap: 8px; min-width: 0;
  font-size: 13px; color: var(--text-muted); }
.savebar .sb-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.savebar[data-state="dirty"] .sb-text, .savebar[data-state="saving"] .sb-text { color: var(--text); font-weight: 600; }
.savebar .sb-what { font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.savebar .sb-short, .savebar .sb-shortbtn { display: none; }
.savebar .sb-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.savebar[data-state="saved"] .sb-dot { display: none; }
.savebar[data-state="saving"] .sb-dot { animation: sb-pulse 1s ease-in-out infinite; }
.savebar[data-state="error"] .sb-dot { background: var(--danger); }
.savebar[data-state="error"] .sb-text { color: var(--danger); font-weight: 600; }
.savebar .sb-acts { flex: none; display: inline-flex; align-items: center; gap: 8px; }
.savebar .sb-acts.hidden { display: none; }
.savebar .sb-div { flex: none; width: 1px; height: 24px; margin: 0 4px; background: rgba(255,255,255,.08); }
.savebar[data-state="saved"] .sb-div, .savebar:has(.sb-acts.hidden) .sb-div { display: none; }
@keyframes sb-pulse { 50% { opacity: .35; } }

/* The one shape, for every button in an edit-mode bar. */
:is(html, html[data-tone]) .has-savebar .bar-inner :is(.step-go, .sb-acts > button) {
  height: 40px; min-height: 40px; padding: 0 16px; border-radius: 12px; font-size: 14px; font-weight: 600;
  line-height: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap; }
:is(html, html[data-tone]) .has-savebar .split-go { height: 40px; border-radius: 12px; overflow: hidden; }
:is(html, html[data-tone]) .has-savebar .split-go > .split-main { border-radius: 12px 0 0 12px; }
:is(html, html[data-tone]) .has-savebar .split-go > .split-caret { border-radius: 0 12px 12px 0; padding: 0 13px; }
/* Discard: a quiet text button. */
:is(html, html[data-tone]) .has-savebar .sb-acts > .sb-discard { background: transparent; border: 0; box-shadow: none;
  color: var(--text-muted); }
:is(html, html[data-tone]) .has-savebar .sb-acts > .sb-discard:hover { color: var(--text); background: rgba(255,255,255,.04); }
/* Unsaved: the navigation steps back to grey; Save changes keeps the primary fill. */
:is(html, html[data-tone]) .has-savebar.sb-dirty .bar-inner > :is(#wizNext, #askSubmit, #wizBack),
:is(html, html[data-tone]) .has-savebar.sb-dirty .split-go,
:is(html, html[data-tone]) .has-savebar.sb-dirty .split-go > :is(.split-main, .split-caret) {
  background: rgba(255,255,255,.07); color: var(--text); box-shadow: none; border-color: transparent; filter: none; }
:is(html, html[data-tone]) .has-savebar.sb-dirty .split-go > :is(.split-main, .split-caret) { background: transparent; }
:is(html, html[data-tone]) .has-savebar.sb-dirty .split-go > .split-caret { border-left: 1px solid rgba(255,255,255,.08); }
:is(html, html[data-tone]) .has-savebar.sb-dirty .bar-inner > :is(#wizNext, #askSubmit, #wizBack):hover,
:is(html, html[data-tone]) .has-savebar.sb-dirty .split-go:hover { background: rgba(255,255,255,.11); }
:is(html, html[data-tone]) .has-savebar.sb-dirty #wizBack { border: 0; }
@media (max-width: 640px) {
  /* One row: the save group first, then the navigation; no divider; short words. */
  .savebar .sb-div, .savebar .sb-text, .savebar .sb-what, .savebar .sb-long { display: none; }
  .savebar .sb-short, .savebar .sb-shortbtn { display: inline; }
  .savebar .sb-state { flex: 0 1 auto; font-size: 12px; gap: 6px; }
  .savebar[data-state="dirty"] .sb-short { color: var(--text); font-weight: 600; }
  .savebar .sb-inner { gap: 6px; }
  .savebar .sb-acts { gap: 4px; margin-left: auto; }
  :is(html, html[data-tone]) .has-savebar .bar-inner :is(.step-go, .sb-acts > button) { padding: 0 12px; }
  :is(html, html[data-tone]) .has-savebar .bar-inner { column-gap: 8px; }
}

/* An unsaved brief from an earlier visit, offered back above the box (brain.js checkBriefDraft). */
.brief-draft { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px;
  margin: 0 0 10px; padding: 9px 12px; border-radius: var(--r-md); font-size: .84rem; color: var(--text);
  background: var(--warn-weak); border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent); }
.brief-draft-acts { display: inline-flex; gap: 8px; }

/* Admin: what changed, from → to (video detail and the workspace drawer). */
.wsc-block { margin: 18px 0 0; }
.wsc-block h4 { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; }
.wsc-n { font-size: .74rem; font-weight: 500; color: var(--text-muted); text-transform: none; letter-spacing: 0; }
.wsc-list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 8px; }
.wsc-item { padding: 9px 12px; border-radius: var(--r-md); background: var(--surface); border-left: 3px solid var(--border); }
.wsc-item.after { border-left-color: var(--warn); }
.wsc-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: .76rem; color: var(--text-muted); }
.wsc-who { color: var(--text); font-weight: 600; }
.wsc-src, .wsc-tag { display: inline-flex; align-items: center; height: 19px; padding: 0 7px; border-radius: var(--r-pill);
  font-size: .68rem; font-weight: 600; background: var(--surface-2); color: var(--text-muted); }
.wsc-src.s-admin { color: var(--danger); background: var(--danger-weak); }
.wsc-tag.warn { color: var(--warn); background: var(--warn-weak); }
.wsc-tag.after { color: var(--warn); }
.wsc-lines { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 3px; font-size: .8rem; line-height: 1.45; }
.wsc-lines li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 7px; min-width: 0; }
.wsc-lines b { font-weight: 600; color: var(--text); }
.wsc-lines li.long { display: grid; grid-template-columns: minmax(0, 1fr); }
.wsc-from { color: var(--text-muted); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--text-muted) 50%, transparent); overflow-wrap: anywhere; }
.wsc-to { color: var(--text); overflow-wrap: anywhere; }
.wsc-lines li.long .wsc-arrow { display: none; }
.wsc-arrow { color: var(--faint); }
.wsc-cell { min-width: 220px; }
.wsc-cell .wsc-tag { margin-right: 6px; }
.wsc-note { margin: 0 0 8px; }
.wsc-drawer-list .adl-table td { vertical-align: top; }
html[data-tone="b"] .wsc-item { background: rgba(255,255,255,.035); }
