/* ========== Storyboard Tool — themable design system ==========
   Default ("cream") is a calm warm light palette; an opt-in dark "blue"
   theme overrides the variables below via [data-theme="blue"] on <html>.
   Component CSS is built almost entirely on top of these vars, so
   switching themes is a single attribute flip — no per-component restyle. */

:root {
  --bg: #f5f3ed;
  --bg-elev: #ffffff;
  --surface: #ffffff;
  --surface-2: #efece2;
  --border: #e6e1cf;
  --border-strong: #d4cdb4;
  --text: #14110e;
  --text-2: #5e5a52;
  --text-3: #95918a;
  --accent: #1a1815;
  --accent-2: #322d28;
  --highlight: #d8693f;          /* terracotta */
  --highlight-2: #f0b454;        /* warm gold */
  --highlight-soft: rgba(216,105,63,0.10);
  --pop: #6e56cf;                /* electric purple — sparingly */
  --good: #2e7d5b;
  --good-soft: rgba(46,125,91,0.12);
  --danger: #b3261e;
  --danger-soft: rgba(179,38,30,0.10);
  --gradient-hot: linear-gradient(135deg, #d8693f 0%, #f0b454 100%);
  --gradient-cool: linear-gradient(135deg, #6e56cf 0%, #4a8fd1 100%);

  /* Background blob colors — declared as vars so theme switch repaints them.
     Used by body::before / body::after for the soft drifting accent glow. */
  --blob-1: #f0b454;
  --blob-2: #6e56cf;
  --blob-opacity: 0.22;

  /* Skeleton shimmer — themed too, otherwise a bright white sweep on a dark
     navy bg looks like a flashbang. */
  --skel-base-a: #ebe7dd;
  --skel-base-b: #f5f2ea;
  --skel-shimmer: rgba(255,255,255,0.65);

  --radius: 14px;
  --radius-sm: 10px;
  --radius-xs: 6px;
  --shadow-1: 0 1px 2px rgba(20,18,15,0.04), 0 1px 3px rgba(20,18,15,0.06);
  --shadow-2: 0 4px 12px rgba(20,18,15,0.06), 0 2px 4px rgba(20,18,15,0.04);
  --shadow-3: 0 24px 48px -12px rgba(20,18,15,0.18), 0 8px 16px -8px rgba(20,18,15,0.10);

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* Kitty mascot — single SVG source-of-truth for ALL loading indicators
     and the brand badge. Wrapped in a CSS var so we can swap a different
     pose without hunting every spinner rule. */
  --kitty-mascot: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><path d='M14 24 L17 7 L29 21 Z' fill='%23e89548'/><path d='M50 24 L47 7 L35 21 Z' fill='%23e89548'/><path d='M18.5 21 L19.5 12 L24.5 19 Z' fill='%23f4b9a3'/><path d='M45.5 21 L44.5 12 L39.5 19 Z' fill='%23f4b9a3'/><ellipse cx='32' cy='37' rx='22' ry='20' fill='%23f4b46a'/><ellipse cx='18' cy='41' rx='4.2' ry='3' fill='%23f08a8a' opacity='0.55'/><ellipse cx='46' cy='41' rx='4.2' ry='3' fill='%23f08a8a' opacity='0.55'/><path d='M22 34.5 Q25 31 28 34.5' stroke='%23332218' stroke-width='2.2' fill='none' stroke-linecap='round'/><path d='M36 34.5 Q39 31 42 34.5' stroke='%23332218' stroke-width='2.2' fill='none' stroke-linecap='round'/><path d='M30 41 Q32 43.5 34 41 Q33 44.5 32 44.5 Q31 44.5 30 41 Z' fill='%23d36b6b'/><path d='M32 44.5 Q30 47.5 28.5 46.5 M32 44.5 Q34 47.5 35.5 46.5' stroke='%23332218' stroke-width='1.6' fill='none' stroke-linecap='round'/><line x1='5' y1='38' x2='15' y2='38' stroke='%23332218' stroke-width='1' stroke-linecap='round' opacity='0.5'/><line x1='5' y1='42' x2='15' y2='41' stroke='%23332218' stroke-width='1' stroke-linecap='round' opacity='0.5'/><line x1='49' y1='38' x2='59' y2='38' stroke='%23332218' stroke-width='1' stroke-linecap='round' opacity='0.5'/><line x1='49' y1='41' x2='59' y2='42' stroke='%23332218' stroke-width='1' stroke-linecap='round' opacity='0.5'/></svg>");
}

/* ----- Blue (dark navy) theme -----
   Cool, modern dark palette: deep navy bg with electric-blue accents.
   Greens / reds stay on a similar hue family but slightly brightened
   for legibility on dark surfaces. */
:root[data-theme="blue"] {
  --bg: #0c1422;             /* deep navy */
  --bg-elev: #14213a;
  --surface: #14213a;
  --surface-2: #1a2a47;
  --border: #233659;
  --border-strong: #2f4878;
  --text: #e7ecf5;
  --text-2: #9bb0d1;
  --text-3: #6075a0;
  --accent: #f4f7fc;
  --accent-2: #c7d3eb;
  --highlight: #4d8eff;         /* electric blue */
  --highlight-2: #7ab6ff;
  --highlight-soft: rgba(77, 142, 255, 0.14);
  --pop: #a384ff;               /* periwinkle */
  --good: #34d399;
  --good-soft: rgba(52, 211, 153, 0.14);
  --danger: #ef5350;
  --danger-soft: rgba(239, 83, 80, 0.16);
  --gradient-hot:  linear-gradient(135deg, #4d8eff 0%, #7ab6ff 100%);
  --gradient-cool: linear-gradient(135deg, #6e56cf 0%, #4d8eff 100%);

  --blob-1: #4d8eff;
  --blob-2: #6e56cf;
  --blob-opacity: 0.28;

  --skel-base-a: #18243e;
  --skel-base-b: #1f2d4d;
  --skel-shimmer: rgba(122, 182, 255, 0.18);

  /* Shadows: on a dark bg, soft white-ish would be wrong — use deeper
     navy-tinted ambient shadows. */
  --shadow-1: 0 1px 2px rgba(0,0,0,0.35), 0 1px 3px rgba(0,0,0,0.45);
  --shadow-2: 0 4px 12px rgba(0,0,0,0.40), 0 2px 4px rgba(0,0,0,0.30);
  --shadow-3: 0 24px 48px -12px rgba(0,0,0,0.55), 0 8px 16px -8px rgba(0,0,0,0.35);
}

* { box-sizing: border-box; }

/* Respect OS-level "reduce motion" — kills all infinite animations
   (kitty bob, blob drift, switch pulse, shimmer, ge-pulse, errPulse) and
   makes transitions effectively instant. Big perf win for users on slow
   GPUs / battery-saver / VMs as a side effect. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg); color: var(--text);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;
  font-feature-settings: "ss01", "cv11", "ss03";
  font-size: 14px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
body { display: flex; position: relative; overflow: hidden; }

/* Subtle animated background blobs — colored via theme vars so they
   morph from warm gold/purple (cream) to electric blue/periwinkle (blue). */
body::before, body::after {
  content: ""; position: fixed; pointer-events: none; z-index: 0;
  width: 540px; height: 540px; border-radius: 50%;
  filter: blur(80px); opacity: var(--blob-opacity);
  transition: opacity 0.4s var(--ease-out);
}
body::before {
  top: -200px; left: -200px;
  background: radial-gradient(circle, var(--blob-1) 0%, transparent 70%);
  animation: drift1 22s ease-in-out infinite alternate;
}
body::after {
  bottom: -240px; right: -120px;
  background: radial-gradient(circle, var(--blob-2) 0%, transparent 70%);
  animation: drift2 28s ease-in-out infinite alternate;
}
@keyframes drift1 { from { transform: translate(0,0); } to { transform: translate(40px, 60px); } }
@keyframes drift2 { from { transform: translate(0,0); } to { transform: translate(-50px, -30px); } }
.sidebar, main { position: relative; z-index: 1; }

button, input, textarea, select { font: inherit; color: inherit; }
::selection { background: var(--highlight-soft); }

/* ---------- Sidebar ---------- */
.sidebar {
  width: 264px; min-width: 264px; height: 100vh;
  background: var(--bg-elev);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 14px;
  padding: 18px 14px;
}
.brand {
  font-size: 16px; font-weight: 700; letter-spacing: -0.02em;
  display: flex; align-items: center; gap: 8px; padding: 4px 6px 12px;
}
.brand .brand-chip {
  color: var(--text-3); font-size: 10px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 2px 6px; border: 1px solid var(--border);
  border-radius: 999px;
  margin-left: 4px;
}
.brand-mascot {
  width: 28px; height: 28px; flex-shrink: 0;
  background-image: var(--kitty-mascot);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  display: inline-block;
  transform-origin: 50% 80%;
  animation: kitty-bob 2.2s var(--ease-in-out) infinite alternate;
}

/* ---------- user chip (sidebar bottom) ---------- */
.user-chip {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; margin-top: 4px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 12px; color: var(--text-2);
  transition: background 0.15s var(--ease-out);
}
.user-chip:hover { background: var(--bg-elev); }
.user-chip[hidden] { display: none; }
.user-chip .avatar {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--gradient-hot); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 12px; letter-spacing: 0;
  flex-shrink: 0;
  box-shadow: 0 4px 10px -4px rgba(216,105,63,0.45);
}
.user-chip .email {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 500; color: var(--text);
}
.user-chip .logout {
  background: transparent; border: none; padding: 4px 8px;
  font-size: 14px; color: var(--text-3); cursor: pointer;
  border-radius: 6px; line-height: 1;
  transition: all 0.15s var(--ease-out);
}
.user-chip .logout:hover {
  color: var(--danger); background: var(--danger-soft);
  transform: none; box-shadow: none;
}

.project-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; margin-top: 4px; padding-right: 2px; }

/* Sidebar search */
.search-wrap {
  position: relative;
  margin-top: 8px;
}
.search-wrap input {
  width: 100%;
  padding: 8px 28px 8px 30px;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font-family: inherit;
  transition: border-color 0.15s var(--ease-out), background 0.15s var(--ease-out);
}
.search-wrap input::placeholder { color: var(--text-3); }
.search-wrap input:focus {
  outline: none;
  border-color: var(--highlight);
  background: var(--surface);
}
.search-wrap::before {
  content: "";
  position: absolute;
  left: 9px; top: 50%;
  width: 12px; height: 12px;
  margin-top: -6px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239aa0a6' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><line x1='21' y1='21' x2='16.65' y2='16.65'/></svg>");
  background-repeat: no-repeat;
  pointer-events: none;
  opacity: 0.85;
}
.search-clear {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%);
  width: 22px; height: 22px;
  padding: 0;
  background: transparent;
  border: none;
  color: var(--text-3);
  font-size: 16px; line-height: 1;
  cursor: pointer;
  border-radius: 4px;
}
.search-clear:hover {
  background: var(--bg-elev);
  color: var(--text);
  transform: translateY(-50%);
  box-shadow: none;
}
.project-list-empty {
  padding: 16px 8px;
  font-size: 12px;
  color: var(--text-3);
  text-align: center;
  font-style: italic;
}

/* Archived badge for sidebar items */
.project-item .name .archived-badge {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px;
  flex-shrink: 0;
  opacity: 0.7;
}

/* Archived banner inside the project view */
.archived-banner {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 0 24px 12px;
  padding: 12px 14px;
  background: linear-gradient(135deg, rgba(255,193,7,0.08), rgba(255,152,0,0.04));
  border: 1px solid rgba(255,152,0,0.25);
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--text-2);
  line-height: 1.45;
}
.archived-banner .ico { font-size: 18px; line-height: 1.2; flex-shrink: 0; }
.archived-banner .msg { flex: 1; }
.project-list::-webkit-scrollbar { width: 6px; }
.project-list::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }

.project-item {
  padding: 9px 12px; border-radius: var(--radius-sm); cursor: pointer;
  border: 1px solid transparent;
  transition: background 0.15s var(--ease-out), border-color 0.15s var(--ease-out);
}
.project-item:hover { background: var(--surface-2); }
.project-item.active { background: var(--bg-elev); border-color: var(--border); box-shadow: var(--shadow-1); }
.project-item .name {
  font-weight: 500; font-size: 13px; color: var(--text);
  display: flex; align-items: center; gap: 6px;
}
.project-item .name .shared-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--highlight-soft); color: var(--highlight);
  font-size: 10px; font-weight: 600;
  flex-shrink: 0;
}
.project-item .name .name-text {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.project-item .meta { color: var(--text-3); font-size: 11px; margin-top: 2px; letter-spacing: 0.01em; }

/* ---------- Sharing modal ---------- */
.sharing-list {
  display: flex; flex-direction: column; gap: 4px;
  max-height: 220px; overflow-y: auto;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 6px;
}
.sharing-list:empty::before {
  content: "Пока никто, кроме владельца.";
  color: var(--text-3); font-size: 12px; padding: 8px 6px;
}
.sharing-list .row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 6px;
  background: transparent;
  transition: background 0.15s var(--ease-out);
}
.sharing-list .row:hover { background: var(--bg-elev); }
.sharing-list .row .avatar {
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--gradient-hot); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 11px;
  flex-shrink: 0;
}
.sharing-list .row .em {
  flex: 1; font-size: 12px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sharing-list .row .rm {
  background: transparent; border: none;
  color: var(--text-3); font-size: 14px; cursor: pointer;
  padding: 4px 8px; border-radius: 4px; line-height: 1;
}
.sharing-list .row .rm:hover {
  background: var(--danger-soft); color: var(--danger);
  transform: none; box-shadow: none;
}

/* ---------- Main ---------- */
main {
  flex: 1; height: 100vh; overflow-y: auto;
  padding: 24px 32px 60px;
}
.empty {
  color: var(--text-3); text-align: center; margin-top: 38vh;
  font-size: 13px; letter-spacing: 0.01em;
}
.hidden { display: none !important; }

.topbar { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; }
.title-input {
  flex: 1; background: transparent; border: none; color: var(--text);
  font-size: 22px; font-weight: 600; letter-spacing: -0.02em; outline: none;
  padding: 4px 0; border-bottom: 1px solid transparent;
  transition: border-color 0.15s var(--ease-out);
}
.title-input:hover { border-bottom-color: var(--border); }
.title-input:focus { border-bottom-color: var(--accent); }

.stage {
  color: var(--text-2); font-size: 11px; padding: 4px 10px;
  border: 1px solid var(--border); background: var(--surface);
  border-radius: 999px; letter-spacing: 0.02em; font-weight: 500;
  display: inline-flex; align-items: center; gap: 6px;
}
.stage.generating { color: var(--highlight); border-color: var(--highlight); background: var(--highlight-soft); }
.stage .pulse { width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: pulse 1.4s ease-in-out infinite; }
.stage .reset-gen {
  margin-left: 6px; cursor: pointer; opacity: 0.6;
  padding: 0 4px; border-radius: 4px;
  transition: all 0.15s var(--ease-out);
}
.stage .reset-gen:hover { opacity: 1; background: rgba(0,0,0,0.06); color: var(--danger); }
@keyframes pulse { 0%,100%{opacity:0.3;transform:scale(0.8)} 50%{opacity:1;transform:scale(1.1)} }

/* ---------- Theme toggle (sidebar bottom) ----------
   Mirrors the look of the neighbouring settings/logout controls so the
   sidebar bottom stays a coherent strip of utility actions. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  justify-content: flex-start;
  margin-top: 6px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.theme-toggle .theme-icon {
  font-size: 14px;
  line-height: 1;
  display: inline-flex;
  filter: saturate(1.1);
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.theme-toggle:hover .theme-icon { transform: rotate(20deg); }
.theme-toggle:active .theme-icon { transform: rotate(-30deg) scale(0.85); }
.theme-toggle .theme-label {
  color: var(--text-2);
}

/* Same shape as theme-toggle, but bell-shaped wiggle on hover. */
.sound-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  justify-content: flex-start;
  margin-top: 6px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.sound-toggle .sound-icon {
  font-size: 14px;
  line-height: 1;
  display: inline-flex;
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.sound-toggle:hover .sound-icon { transform: rotate(-15deg) scale(1.1); }
.sound-toggle:active .sound-icon { transform: rotate(15deg) scale(0.9); }
.sound-toggle .sound-label { color: var(--text-2); }

/* ---------- Cost chips (Wavespeed spend) ---------- */
/* Top-bar pill: lifetime spend on the active project. Muted when $0 (nothing
   has been generated yet), warm/active when there's actual money on the line. */
.project-cost { display: inline-flex; align-items: center; }
.cost-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-3);
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: help;
  transition: background 0.18s, color 0.18s, border-color 0.18s;
}
.cost-pill.has-spend {
  background: var(--highlight-soft);
  color: var(--highlight);
  border-color: rgba(216, 105, 63, 0.35);
  font-weight: 600;
}

/* Per-scene spend: small chip glued to the right of the scene badge. Same
   visual language as the topbar pill so users mentally connect them. */
.cost-chip {
  display: inline-flex;
  align-items: center;
  font-size: 10px;
  padding: 3px 7px;
  border-radius: 999px;
  background: var(--highlight-soft);
  color: var(--highlight);
  border: 1px solid rgba(216, 105, 63, 0.25);
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: help;
}

/* Inline "≈ $X" hint that sits next to the bulk-generate progress status. */
.cost-est {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid var(--border);
}

/* ---------- Tabs ---------- */
.tabs {
  display: flex; gap: 2px; padding: 4px;
  background: var(--surface-2); border-radius: 999px;
  margin-bottom: 22px; width: fit-content;
}
.tab {
  background: transparent; color: var(--text-2); border: none;
  padding: 7px 16px; font-size: 12px; font-weight: 500;
  border-radius: 999px; cursor: pointer; letter-spacing: 0.01em;
  transition: all 0.2s var(--ease-out);
}
.tab:hover { color: var(--text); }
.tab.active { background: var(--bg-elev); color: var(--text); box-shadow: var(--shadow-1); }
.tab-pane { display: none; animation: fadeIn 0.3s var(--ease-out); }
.tab-pane.active { display: block; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ---------- Buttons ---------- */
button {
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border);
  padding: 8px 14px; border-radius: var(--radius-xs);
  cursor: pointer; font-size: 12px; font-weight: 500;
  letter-spacing: 0.01em;
  /* Explicit transition list — `transition: all` forces style recalc on
     every animatable property (filter, opacity, width, etc.) even when
     only the four below ever animate on hover/focus/active. */
  transition:
    background 0.18s var(--ease-out),
    border-color 0.18s var(--ease-out),
    color 0.18s var(--ease-out),
    transform 0.18s var(--ease-out),
    box-shadow 0.18s var(--ease-out);
  display: inline-flex; align-items: center; gap: 6px;
}
button:hover { background: var(--surface-2); border-color: var(--border-strong); transform: translateY(-1px); box-shadow: var(--shadow-1); }
button:active { transform: translateY(0); }
button:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }

button.primary {
  background: var(--accent); color: #fff; border-color: var(--accent);
  position: relative; overflow: hidden;
}
button.primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
button.primary::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(120deg, transparent 30%, rgba(255,255,255,0.18) 50%, transparent 70%);
  transform: translateX(-100%); transition: transform 0.6s var(--ease-out);
}
button.primary:hover::after { transform: translateX(100%); }

button.hot {
  background: var(--gradient-hot); color: #fff; border: none;
  box-shadow: 0 8px 24px -6px rgba(216,105,63,0.45);
}
button.hot:hover { box-shadow: 0 10px 28px -4px rgba(216,105,63,0.6); transform: translateY(-1px); }

/* Inline kitty loader inside any button — same SVG mascot as the global
   one, just sized down. We tweaked the bob a bit faster so it reads as
   "active" instead of "asleep". */
button .btn-spinner {
  width: 18px; height: 18px;
  background-image: var(--kitty-mascot);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  display: inline-block;
  transform-origin: 50% 80%;
  animation: kitty-bob 1.1s var(--ease-in-out) infinite alternate;
  vertical-align: middle;
}
button.is-loading { pointer-events: none; opacity: 0.85; }
button.ghost { background: transparent; border-color: transparent; }
button.ghost:hover { background: var(--surface-2); border-color: var(--border); }
button.danger-ghost { background: transparent; color: var(--danger); border-color: transparent; }
button.danger-ghost:hover { background: var(--danger-soft); border-color: transparent; color: var(--danger); }

/* ---------- Inputs ---------- */
label {
  display: block; color: var(--text-2); margin-bottom: 6px;
  font-size: 11px; font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase;
}
input[type="text"], input[type="password"], textarea {
  width: 100%; background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 10px 12px; outline: none;
  transition: border-color 0.15s var(--ease-out), box-shadow 0.15s var(--ease-out);
}
input:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(47,47,47,0.08); }
textarea { resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; line-height: 1.55; }

.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 14px; }
.row-actions { display: flex; gap: 10px; align-items: center; margin: 16px 0; flex-wrap: wrap; }
.status { color: var(--text-3); font-size: 12px; }
.status.error { color: var(--danger); }
.status.ok { color: var(--good); }
.muted { color: var(--text-3); font-size: 12px; margin-bottom: 12px; }

/* ---------- Characters ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 18px; }
.char-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px; display: flex; flex-direction: column; gap: 8px;
  transition: box-shadow 0.2s var(--ease-out);
}
.char-card:hover { box-shadow: var(--shadow-2); }
.char-card h4 { margin: 0; font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.char-card .desc { color: var(--text-3); font-size: 12px; min-height: 30px; line-height: 1.4; }
.char-card .thumbs { display: flex; flex-wrap: wrap; gap: 6px; min-height: 64px; }
.char-card .thumbs img {
  width: 56px; height: 56px; object-fit: cover;
  border-radius: var(--radius-xs); border: 1px solid var(--border);
}
.char-card label.upload {
  display: flex; justify-content: center; align-items: center;
  background: var(--surface-2); padding: 7px 10px; border-radius: var(--radius-xs);
  border: 1px dashed var(--border-strong); cursor: pointer; font-size: 11px;
  text-transform: none; letter-spacing: 0; font-weight: 500;
  transition: background 0.15s var(--ease-out);
}
.char-card label.upload:hover { background: var(--bg); }
.char-card input[type=file] { display: none; }
.char-card details summary::-webkit-details-marker { display: none; }
.char-card details summary { padding: 4px 0; }

/* ---------- Storyboard carousel ---------- */
.carousel-wrap { position: relative; }
.storyboard {
  position: relative;
  display: flex; align-items: stretch;
  overflow-x: auto; overflow-y: visible;
  /* `proximity` instead of `mandatory` — snap kicks in only when the user
     stops near a card edge, doesn't fight trackpad inertia. Combined with
     scroll-padding so snap targets are aligned to the card column, not the
     scroller's left edge. `mandatory` here was forcing snaps every frame
     against viewport-based padding (`50vw - 200px`) that was wrong for the
     new cast-row layout — that's what was making the carousel feel "jumpy". */
  scroll-snap-type: x proximity;
  scroll-padding-inline: 28px;
  scroll-behavior: smooth;
  /* Vertical padding used to be 60px to leave room for the focused-card
     aura glow; that effect is gone now so this just collapses to breathing
     room. Horizontal padding is plain pixels so it scales correctly inside
     nested .cast-row containers (which aren't 100vw wide). */
  padding: 24px 28px;
  gap: 24px;
  /* Prevent accidental sub-pixel jitter from overscroll bounce when the
     storyboard is the only horizontally-scrollable thing on the page. */
  overscroll-behavior-x: contain;
}
.storyboard::-webkit-scrollbar { height: 6px; }
.storyboard::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
.storyboard::-webkit-scrollbar-track { background: transparent; }

.scene-card {
  flex: 0 0 360px;
  /* Snap to the left edge — cards "queue up" cleanly from start of the row,
     matches how every other horizontal-rail UI does it (Netflix etc). The
     old `center` align together with mandatory snap was what made scrolling
     overshoot and bounce-back on every gesture. */
  scroll-snap-align: start;
  position: relative;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px;
  display: flex; flex-direction: column; gap: 10px;
  transition: box-shadow 0.25s var(--ease-out), border-color 0.25s var(--ease-out);
}
.scene-card:hover {
  box-shadow: var(--shadow-2); border-color: var(--border-strong);
}
.scene-card.has-error { border-color: var(--danger); }
.scene-card.has-error::before { background: linear-gradient(135deg, #ff7a6c, #ff3838); }

.scene-error {
  background: var(--danger-soft);
  border: 1px solid rgba(179,38,30,0.25);
  border-radius: var(--radius-sm); padding: 10px 12px;
  font-size: 11px; color: var(--danger); line-height: 1.45;
  display: flex; align-items: flex-start; gap: 8px;
}
.scene-error[hidden] { display: none; }
.scene-error::before { content: "⚠"; font-size: 14px; line-height: 1; flex-shrink: 0; margin-top: 1px; }

.refine-box {
  background: var(--highlight-soft);
  border: 1px solid rgba(216,105,63,0.25);
  border-radius: var(--radius-sm);
  padding: 10px;
  animation: fadeIn 0.2s var(--ease-out);
}
.refine-box[hidden] { display: none; }

.model-switch {
  display: inline-flex; gap: 0; padding: 3px;
  background: var(--surface-2); border-radius: 999px;
  border: 1px solid var(--border);
  box-shadow: inset 0 1px 2px rgba(20,18,15,0.04);
}
.model-switch button {
  background: transparent; border: none;
  padding: 6px 14px; font-size: 12px; font-weight: 500;
  border-radius: 999px; cursor: pointer; color: var(--text-3);
  transition: all 0.18s var(--ease-out);
  box-shadow: none;
  letter-spacing: 0.01em;
}
.model-switch button:hover {
  color: var(--text); background: rgba(20,18,15,0.04);
  transform: none; box-shadow: none;
}
.model-switch button.active {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 8px -2px rgba(20,18,15,0.25), inset 0 1px 0 rgba(255,255,255,0.08);
}
.model-switch button.active::before {
  content: "✓"; margin-right: 4px; font-size: 10px;
  display: inline-block; opacity: 0.85;
}
.model-switch button.active:hover { background: var(--accent-2); }
.model-switch button.is-disabled {
  color: var(--text-3); opacity: 0.55;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  cursor: not-allowed;
}
.model-switch button.is-disabled:hover {
  color: var(--text-3); background: transparent;
  transform: none; box-shadow: none;
}
.model-switch button.is-disabled::after {
  content: "🚫"; margin-left: 4px; font-size: 10px;
  text-decoration: none; display: inline-block;
}

/* iOS-style toggle switch (e.g. "Без музыки и пения" on Script + Videos
   tabs). Looks like a real switch, not a button — track + sliding knob,
   colour shifts grey → red when active, with a soft glow halo when ON.
   Extra horizontal margin separates it from the action buttons around. */
.toggle-switch {
  /* Reset from default <button> styles. */
  appearance: none;
  background: transparent;
  border: none;
  padding: 6px 4px;
  margin: 0 14px;             /* breathing room from neighbour buttons */
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font: inherit;
  color: var(--text-3);
  font-size: 13px;
  line-height: 1;
  transition: color 0.22s var(--ease-out), transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
  -webkit-tap-highlight-color: transparent;
}
.toggle-switch:hover { color: var(--text-2); transform: none; box-shadow: none; }
.toggle-switch:focus-visible {
  outline: 2px solid var(--highlight, #4a90e2);
  outline-offset: 3px;
  border-radius: 8px;
}

.toggle-switch .switch-track {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  background: #c5cad0;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.18);
  transition: background 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
  flex-shrink: 0;
}
.toggle-switch .switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), 0 0 0 0.5px rgba(0, 0, 0, 0.05);
  /* Transform-based slide is composite-only — `left` would trigger layout
     on every frame of the 280ms slide. */
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1),
              box-shadow 0.25s var(--ease-out);
}

.toggle-switch .switch-label {
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: color 0.22s var(--ease-out), font-weight 0.22s var(--ease-out);
}

/* ON state — track turns red, knob slides right, soft red glow halo.
   The "halo" pulse used to animate `box-shadow` directly, which forces a
   paint pass every frame for every visible toggle. We now keep the static
   shadow on .switch-track and animate a sibling ::after halo via
   `transform: scale` + `opacity` (composite-only, no paint). */
.toggle-switch.is-on { color: var(--danger, #d23a3a); }
.toggle-switch.is-on .switch-track {
  background: var(--danger, #d23a3a);
  box-shadow:
    0 0 0 2px rgba(210, 58, 58, 0.18),
    0 4px 12px -3px rgba(210, 58, 58, 0.45),
    inset 0 1px 2px rgba(0, 0, 0, 0.15);
}
/* The pulsing ring lives on the track itself via ::after — pseudo-elements
   inherit the rounded shape via inset:0 + border-radius:inherit. */
.toggle-switch .switch-track { position: relative; }
.toggle-switch .switch-track::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: transparent;
  box-shadow: 0 0 0 2px rgba(210, 58, 58, 0.45);
  transform: scale(1);
  /* No paint cost when toggle is OFF — opacity:0 + no animation. */
}
.toggle-switch.is-on .switch-track::after {
  animation: switch-track-pulse 2.2s ease-in-out infinite;
}
.toggle-switch.is-on .switch-knob {
  /* `transform: translateX` instead of `left` — composite-only, no layout. */
  transform: translateX(18px);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 0 6px rgba(255, 255, 255, 0.35);
}
.toggle-switch.is-on .switch-label { font-weight: 600; }
.toggle-switch.is-on:hover .switch-track {
  background: #b93131;
}

/* Pop animation on state flip (added briefly via JS as .just-toggled). */
.toggle-switch.just-toggled { animation: switch-pop 0.42s cubic-bezier(0.34, 1.56, 0.64, 1); }

@keyframes switch-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}
@keyframes switch-track-pulse {
  0%, 100% { transform: scale(1);    opacity: 0.55; }
  50%      { transform: scale(1.18); opacity: 0;    }
}

.style-presets { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.style-presets .chip {
  position: relative;
  padding: 5px 10px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: 11px; cursor: pointer; color: var(--text-2);
  transition: all 0.15s var(--ease-out);
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: 5px;
}
.style-presets .chip:hover { background: var(--bg-elev); color: var(--text); border-color: var(--border-strong); }
.style-presets .chip.active { background: var(--highlight-soft); border-color: var(--highlight); color: var(--highlight); font-weight: 500; }
.style-presets .chip .icon { font-size: 13px; line-height: 1; }
.style-presets .chip .edit {
  opacity: 0; margin-left: 4px; padding: 0 2px;
  font-size: 10px; color: var(--text-3);
  transition: opacity 0.15s var(--ease-out);
}
.style-presets .chip:hover .edit { opacity: 1; }
.style-presets .chip .edit:hover { color: var(--text); }
.style-presets .chip.add {
  background: transparent; border-style: dashed; color: var(--text-3);
}
.style-presets .chip.add:hover { color: var(--highlight); border-color: var(--highlight); }

.icon-grid {
  display: grid; grid-template-columns: repeat(12, 1fr); gap: 4px;
  max-height: 180px; overflow-y: auto;
  padding: 8px; background: var(--surface-2); border-radius: var(--radius-sm);
}
.icon-grid .icon-cell {
  width: 100%; aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; cursor: pointer; border-radius: var(--radius-xs);
  transition: all 0.12s var(--ease-out);
}
.icon-grid .icon-cell:hover { background: var(--bg-elev); transform: scale(1.15); }
.icon-grid .icon-cell.selected { background: var(--highlight); }
.icon-grid::-webkit-scrollbar { width: 6px; }
.icon-grid::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }

.style-refs-thumbs { display: flex; flex-wrap: wrap; gap: 8px; min-height: 8px; margin-top: 8px; }
.style-refs-thumbs .thumb {
  position: relative; width: 76px; height: 76px;
  border-radius: var(--radius-xs); overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.style-refs-thumbs .thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.style-refs-thumbs .thumb .x {
  position: absolute; top: 4px; right: 4px;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(20,18,15,0.7); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; cursor: pointer; opacity: 0;
  transition: opacity 0.15s var(--ease-out);
}
.style-refs-thumbs .thumb:hover .x { opacity: 1; }
.refine-box textarea { font-size: 12px; min-height: 50px; background: var(--surface); }
.refine-box label { margin-bottom: 4px; }

.scene-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.scene-head h4 { margin: 0; font-size: 13px; font-weight: 600; letter-spacing: -0.005em; }
.badge {
  font-size: 10px; padding: 3px 8px; border-radius: 999px;
  background: var(--surface-2); color: var(--text-3);
  font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase;
}
.badge.approved { background: var(--good-soft); color: var(--good); }
.badge.generating { background: var(--highlight-soft); color: var(--highlight); }

.media {
  aspect-ratio: 9/16; width: 100%;
  background: var(--surface-2); border-radius: var(--radius-sm);
  overflow: hidden; display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: 12px; position: relative;
}
.media img, .media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.media img { animation: imgIn 0.4s var(--ease-out); }
@keyframes imgIn { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: scale(1); } }
.media.skeleton {
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, var(--skel-base-a) 0%, var(--skel-base-b) 100%);
}
/* Shimmer sweep via a pseudo-element + `transform: translateX` instead of
   animating `background-position`. Bulk "Generate all" can attach .skeleton
   to N cells at once; old version forced a paint pass per cell per frame. */
.media.skeleton::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg, transparent 0%, var(--skel-shimmer) 50%, transparent 100%
  );
  transform: translateX(-100%);
  animation: shimmer 1.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%);  }
}
.media .spinner {
  width: 56px; height: 56px;
  background-image: var(--kitty-mascot);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  position: absolute;
  inset: 0;
  margin: auto;          /* centers without transform so kitty-bob can own it */
  transform-origin: 50% 80%;
  animation: kitty-bob 1.3s var(--ease-in-out) infinite alternate;
  border: none;
}

.media.has-error {
  background: linear-gradient(135deg, rgba(255,80,80,0.12), rgba(179,38,30,0.18));
  border: 2px solid rgba(179,38,30,0.35);
}
.media .error-icon {
  position: relative;
  width: 110px; height: 110px; border-radius: 50%;
  background: var(--danger);
  color: #fff;
  font-size: 78px; font-weight: 800; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 12px 32px -8px rgba(179,38,30,0.45);
  animation: errBoom 0.6s var(--ease-out);
}
/* Halo pulse moved to a pseudo-element scaling/fading instead of
   animating the parent's box-shadow (which forces a paint pass per frame
   for every visible errored card). */
.media .error-icon::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(179, 38, 30, 0.35);
  pointer-events: none;
  z-index: -1;
  animation: errPulse 2.2s ease-in-out 0.6s infinite;
}
@keyframes errBoom {
  0%   { transform: scale(0.4); opacity: 0; }
  55%  { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(1); }
}
@keyframes errPulse {
  0%,100% { transform: scale(1);    opacity: 0.4; }
  50%     { transform: scale(1.18); opacity: 0;   }
}
/* The first `@keyframes spin` here was dead — `.spinner` and `.btn-spinner`
   now use `kitty-bob`. Kept the rule only because some old browsers
   complain about unresolved animation names from cached HTML. */
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- per-scene album of past generations ----------
   Shown only when a scene has 2+ stored versions. Active thumb has a
   gold/terracotta highlight ring; arrows step active by ±1. Thumbs are
   <button>s so keyboard navigation works for free. */
.album {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 8px 0 0;
  padding: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.album-nav {
  width: 26px; height: 56px;
  flex-shrink: 0;
  padding: 0;
  display: inline-flex;
  align-items: center; justify-content: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-2);
  font-size: 18px; line-height: 1;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s, transform 0.15s;
}
.album-nav:hover:not(:disabled) {
  border-color: var(--highlight);
  color: var(--highlight);
  background: var(--highlight-soft);
}
.album-nav:active:not(:disabled) { transform: scale(0.92); }
.album-nav:disabled {
  opacity: 0.3;
  cursor: default;
}
.album-strip {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  flex: 1;
  padding: 2px 0;
  scroll-behavior: smooth;
  scrollbar-width: thin;
}
.album-strip::-webkit-scrollbar { height: 4px; }
.album-strip::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 2px; }
.album-thumb {
  position: relative;
  flex-shrink: 0;
  width: 32px;          /* 9:16 mini — narrow enough to fit ~8 thumbs in a 360px card */
  height: 56px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 6px;
  background: #0d0e10;  /* dark fallback so an empty video frame doesn't flash white */
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.album-thumb:hover { transform: translateY(-1px); }
.album-thumb img, .album-thumb video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.album-thumb .v-num {
  position: absolute;
  bottom: 1px; right: 1px;
  font-size: 8px; font-weight: 600;
  line-height: 1.1;
  background: rgba(0,0,0,0.7);
  color: #fff;
  padding: 1px 3px;
  border-radius: 2px;
  letter-spacing: 0.02em;
  pointer-events: none;
}
.album-thumb.active {
  border-color: var(--highlight);
  box-shadow: 0 0 0 1px var(--highlight), 0 0 8px rgba(216, 105, 63, 0.4);
}
.album-thumb.active .v-num {
  background: var(--highlight);
}

.meta-line { font-size: 11px; color: var(--text-3); letter-spacing: 0.01em; }
.scene-card textarea { font-size: 12px; min-height: 70px; }
.scene-card label { margin-bottom: 4px; }
.scene-card .actions { display: flex; gap: 4px; flex-wrap: wrap; }
.scene-card .actions button { padding: 6px 10px; font-size: 11px; }

.final-prompt-wrap > summary { padding: 6px 0; cursor: pointer; }
.final-prompt {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; line-height: 1.5;
  background: var(--surface-2); padding: 10px;
  border-radius: var(--radius-xs); max-height: 260px; overflow: auto;
  white-space: pre-wrap; margin-top: 6px; color: var(--text-2);
}

.carousel-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--bg-elev); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; box-shadow: var(--shadow-2);
  z-index: 10; transition: all 0.2s var(--ease-out);
  font-size: 18px; color: var(--text);
}
.carousel-nav:hover { background: var(--surface-2); transform: translateY(-50%) scale(1.05); }
.carousel-nav.prev { left: 16px; }
.carousel-nav.next { right: 16px; }

.progress-chip {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 999px; padding: 6px 14px;
  box-shadow: var(--shadow-1);
  font-size: 12px; color: var(--text-2);
  margin-left: 8px;
}
.progress-chip .dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--highlight);
  animation: pulse 1.4s ease-in-out infinite;
}

/* ---------- Modal ----------
   Bumped scrim opacity from 0.42 → 0.56 to compensate for dropping the
   `backdrop-filter: blur(6px)` — full-viewport backdrop-filter is one of
   the most expensive paint ops in the engine, especially on top of the
   body blob layer. The deeper scrim reads as the same "everything else
   recedes" effect without the composite cost. */
.modal {
  position: fixed; inset: 0; background: rgba(20,18,15,0.56);
  display: flex; align-items: center; justify-content: center; z-index: 50;
  animation: fadeIn 0.18s var(--ease-out);
}
.modal-content {
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 24px; width: 460px; display: flex; flex-direction: column; gap: 10px;
  box-shadow: var(--shadow-3);
  animation: popIn 0.32s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes popIn {
  /* Slightly more pronounced lift + tiny overshoot via easing curve so
     it lands with a "bounce" feel — reads as a deliberate UI element,
     not a system dialog. */
  from { transform: translateY(14px) scale(0.94); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
.modal-content h3 { margin: 0 0 4px 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.modal-content input { margin-bottom: 6px; }
/* Highlight + slight grow on focus so the input feels like the obvious next
   action when the modal lands. */
.modal-content input:focus {
  border-color: var(--highlight);
  box-shadow: 0 0 0 3px var(--highlight-soft);
}

/* ---------- Final video ---------- */
#final-preview { display: flex; flex-direction: column; align-items: center; padding: 24px 0; }
#final-preview video {
  width: min(420px, 80%); border-radius: var(--radius);
  border: 1px solid var(--border); box-shadow: var(--shadow-3);
}
#final-preview a {
  margin-top: 16px; color: var(--accent); text-decoration: none;
  font-weight: 500; padding: 8px 14px; border: 1px solid var(--border);
  border-radius: var(--radius-xs); background: var(--bg-elev);
  transition: all 0.15s var(--ease-out);
}
#final-preview a:hover { background: var(--surface-2); box-shadow: var(--shadow-1); }

/* ---------- Toasts ---------- */
#toast-container {
  position: fixed; top: 20px; right: 20px; z-index: 100;
  display: flex; flex-direction: column; gap: 10px;
  pointer-events: none;
}
.toast {
  background: var(--bg-elev); border: 1px solid var(--border);
  border-left: 3px solid var(--text-3);
  border-radius: var(--radius-sm); padding: 12px 16px;
  box-shadow: var(--shadow-3);
  font-size: 13px; min-width: 260px; max-width: 380px;
  display: flex; align-items: flex-start; gap: 10px;
  pointer-events: auto;
  animation: toastIn 0.4s var(--ease-out);
  transform-origin: right center;
}
.toast.removing { animation: toastOut 0.3s var(--ease-out) forwards; }
@keyframes toastIn { from { transform: translateX(120%) scale(0.95); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes toastOut { to { transform: translateX(120%) scale(0.95); opacity: 0; } }
.toast.success { border-left-color: var(--good); }
.toast.error { border-left-color: var(--danger); }
.toast.info { border-left-color: var(--highlight); }
.toast .icon { width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: #fff; margin-top: 1px; }
.toast.success .icon { background: var(--good); }
.toast.error .icon { background: var(--danger); }
.toast.info .icon { background: var(--highlight); }
.toast .msg { flex: 1; line-height: 1.45; color: var(--text); }
.toast .msg strong { display: block; margin-bottom: 2px; font-weight: 600; }
.toast .close {
  cursor: pointer; color: var(--text-3); font-size: 16px; line-height: 1;
  padding: 2px 4px; margin: -2px -4px; border-radius: 4px;
}
.toast .close:hover { background: var(--surface-2); color: var(--text); }

/* ---------- Global loading overlay ---------- */
#loader-overlay {
  position: fixed; inset: 0; z-index: 90;
  /* Higher opacity replaces the dropped `backdrop-filter: blur(8px)` —
     full-viewport blur stacked on top of the body blobs was a measurable
     paint cost on every long-running operation. */
  background: rgba(245,243,237,0.86);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px;
  animation: fadeIn 0.25s var(--ease-out);
}
/* .kitty-loader is the only consumer now — the legacy `.ring` selector
   was removed; index.html uses `.kitty-loader-xl` directly. */
.kitty-loader {
  width: 56px; height: 56px;
  background-image: var(--kitty-mascot);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  transform-origin: 50% 80%;
  animation: kitty-bob 1.4s var(--ease-in-out) infinite alternate;
  border: none;
  filter: drop-shadow(0 8px 24px rgba(20,18,15,0.12));
}
.kitty-loader-xl { width: 96px; height: 96px; }
.kitty-loader-sm { width: 28px; height: 28px; }
#loader-overlay .label { color: var(--text-2); font-size: 13px; letter-spacing: 0.02em; font-weight: 500; }
#loader-overlay .sub { color: var(--text-3); font-size: 11px; max-width: 360px; text-align: center; line-height: 1.5; }

/* Pulse for storyboard while generating */
.storyboard.is-generating,
.storyboard-stack.is-generating {
  background:
    radial-gradient(ellipse at center top, var(--highlight-soft) 0%, transparent 50%);
}

/* ============================================
   Multi-cast UI
   ============================================
   A project can have multiple "casts" — parallel re-renders with alternative
   character refs. Renders as stacked rows on the Frames/Videos tabs, plus a
   per-cast ref-group inside each character card on Characters tab.
*/

/* Stack of cast rows on Frames / Videos panes. */
.storyboard-stack {
  display: flex; flex-direction: column;
  gap: 18px;
  padding: 4px 0 32px;
}
.cast-row {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
  /* Subtle inner highlight so each row reads as a distinct "frame" without
     adding a heavy shadow that would compete with the focused scene-card. */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}
.cast-row > .cast-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 18px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  gap: 12px;
}
.cast-row .cast-label {
  display: flex; align-items: center; gap: 10px;
  min-width: 0; flex: 1;
}
.cast-row .cast-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--highlight);
  flex: 0 0 auto;
  box-shadow: 0 0 0 3px var(--highlight-soft);
}
.cast-row .cast-name {
  font-size: 13px; font-weight: 600;
  color: var(--text-1);
  letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cast-row .cast-progress {
  font-size: 11px;
  white-space: nowrap;
}
.cast-row .cast-tools {
  display: flex; gap: 6px; align-items: center;
  flex: 0 0 auto;
}
.cast-row .cast-tools button {
  padding: 5px 10px;
  font-size: 11px;
}
.cast-row .cast-tools button:disabled {
  opacity: 0.35; cursor: not-allowed;
}

/* Per-row carousel: same look as the original .storyboard but vertically
   stacked. Reduce vertical padding so 2-3 rows fit on a laptop screen. */
.cast-row .cast-carousel {
  position: relative;
}
/* No extra vertical padding on the storyboard inside a cast-row —
   .cast-row already has its own padding from .cast-row > .cast-head, so
   stacking another 60px (the old default) made each row 2x taller than
   needed and contributed to the carousel feeling "off". */
.cast-row .storyboard {
  padding-top: 16px;
  padding-bottom: 18px;
}
.cast-row:not(:first-child) .scene-card {
  flex-basis: 320px;
}

/* Cast bar (on Characters tab) — chips + add button.
   Shows what casts exist and lets the user spawn a new one. */
.cast-bar {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 14px;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
}
.cast-bar .cast-bar-label {
  font-size: 11px;
  color: var(--text-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-right: 4px;
}
.cast-chip {
  display: inline-flex; align-items: center;
  padding: 4px 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12px;
  color: var(--text-2);
  font-weight: 500;
}
.cast-chip[data-cast="main"] {
  background: var(--highlight-soft);
  border-color: rgba(0,0,0,0);
  color: var(--text-1);
}
.cast-bar .cast-add {
  margin-left: auto;
  font-size: 11px;
  padding: 5px 12px;
}

/* Characters tab: vertical stack of cast rows, mirroring the storyboard
   layout. Each row is one cast; inside, a grid of compact character cards
   scoped to that cast. */
.char-cast-stack {
  display: flex; flex-direction: column;
  gap: 18px;
}
.char-cast-row {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 14px 16px 16px;
}
.char-cast-row > .char-cast-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 0 0 12px 0;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.char-cast-row > .char-cast-head .cast-label {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  min-width: 0;
}
.char-cast-row .cast-fallback-hint {
  font-size: 11px;
  font-style: italic;
}
.char-cast-row .char-grid {
  /* Horizontal scrollable row (per user request — much easier to scan when
     there are 3+ characters). Same proximity-snap pattern as the storyboard
     carousels so it doesn't fight the user's scroll inertia. */
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 14px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;
  padding: 4px 4px 12px 4px;
  scrollbar-gutter: stable;
}
.char-cast-row .char-grid > .char-card {
  /* Fixed-width tiles so the row scrolls cleanly instead of cards
     stretching to fit the container. */
  flex: 0 0 260px;
  scroll-snap-align: start;
}
.char-cast-row .char-grid > .char-card.compact {
  flex-basis: 220px;
}
.char-cast-row:not(:first-child) {
  background: var(--bg);
  /* Slightly muted secondary rows — distinguishes "alternative variants"
     from the canonical one without making them look broken. */
}
.char-cast-row:not(:first-child) > .char-cast-head .cast-dot {
  background: var(--text-3);
  box-shadow: 0 0 0 3px rgba(255,255,255,0.04);
}

/* Compact cards on alt-cast rows: just name + refs + upload. No tag,
   description, summary, or analyze button — that lives on the Главная card. */
.char-card.compact {
  padding: 10px;
  gap: 6px;
}
.char-card.compact h4 {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
}
.char-card.compact .fallback-line {
  font-size: 11px;
  line-height: 1.4;
  min-height: 14px;
}
.char-card.compact .fallback-line.is-fallback {
  font-style: italic;
  opacity: 0.75;
}
.char-card.compact .thumbs {
  min-height: 50px;
  gap: 4px;
}
.char-card.compact .thumbs img {
  width: 50px; height: 50px;
}
.char-card.compact .upload {
  font-size: 11px;
  padding: 6px 10px;
}

/* Final tab — one player per cast that has been stitched. */
.final-cast {
  margin-bottom: 24px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.final-cast h4 {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.final-cast video {
  width: 100%; max-width: 480px;
  display: block;
  border-radius: 8px;
  background: #000;
}
.final-cast a {
  display: inline-block;
  margin-top: 8px;
  font-size: 12px;
  color: var(--highlight);
  text-decoration: none;
}
.final-cast a:hover { text-decoration: underline; }

/* ---------- character library ("Альбом") ---------- */
.library-btn {
  width: 100%;
  text-align: left;
  margin-top: 2px;
  font-size: 12px;
  display: flex; align-items: center; gap: 6px;
}
.library-view {
  padding: 22px 28px 40px;
  display: flex; flex-direction: column;
  gap: 18px;
  height: 100%;
  overflow-y: auto;
}
.library-topbar {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
}
.library-title { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.library-sub { font-size: 12px; line-height: 1.4; max-width: 540px; }

.library-empty {
  margin: 60px auto;
  text-align: center;
  padding: 40px 28px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  max-width: 480px;
  background: var(--surface);
}
.library-empty-icon { font-size: 40px; margin-bottom: 8px; opacity: 0.7; }
.library-empty-title { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
.library-empty-sub { font-size: 12px; color: var(--text-3); line-height: 1.5; }

.library-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 18px;
}
.library-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  display: flex; flex-direction: column; gap: 12px;
  transition: box-shadow 0.2s var(--ease-out);
}
.library-card:hover { box-shadow: var(--shadow-2); }
.library-card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.library-card-name {
  font-size: 15px; font-weight: 600; letter-spacing: -0.01em;
  cursor: pointer;
  min-width: 0;
  padding: 2px 6px 2px 0;
  border-radius: 4px;
}
.library-card-name:hover { background: var(--bg); }
.library-delete { font-size: 12px; padding: 4px 8px; }

.library-portraits {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
.library-portrait-slot {
  position: relative;
  aspect-ratio: 9/16;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.library-portrait-slot img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.library-portrait-slot.loading {
  border-style: dashed;
  border-color: var(--highlight);
}
.library-portrait-placeholder {
  font-size: 18px;
  color: var(--text-3);
  opacity: 0.5;
}
.library-portrait-label {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  background: linear-gradient(to top, rgba(0,0,0,0.65), transparent);
  color: #fff;
  font-size: 9px;
  text-align: center;
  padding: 8px 2px 3px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.library-tag-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-3);
  margin: 4px 0 -4px 0;
}
.library-tag-input {
  font-size: 12px;
  padding: 7px 9px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-family: inherit;
}
.library-tag-input:focus {
  outline: none;
  border-color: var(--highlight);
}
.library-summary-wrap summary { cursor: pointer; padding: 4px 0; }
.library-summary-wrap summary::-webkit-details-marker { display: none; }
.library-summary-wrap summary::before {
  content: "▶ ";
  font-size: 9px;
  display: inline-block;
  transition: transform 0.15s;
}
.library-summary-wrap[open] summary::before { transform: rotate(90deg); }
.library-analyze {
  font-size: 12px;
  padding: 6px 12px;
  white-space: nowrap;
}

.library-refs-label {
  font-size: 11px; margin-bottom: 4px;
}
.library-refs-strip {
  display: flex; flex-wrap: wrap; gap: 6px;
}
/* Each ref is a button so the click-to-pick-frontal is keyboard-accessible
   and the hover affordance reads as "yes this does something". */
.library-ref-tile {
  position: relative;
  padding: 0;
  background: transparent;
  border: 2px solid var(--border);
  border-radius: 5px;
  width: 44px; height: 44px;
  cursor: pointer;
  overflow: hidden;
  transition: transform 0.12s, border-color 0.12s;
}
.library-ref-tile img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.library-ref-tile:hover:not(:disabled) {
  border-color: var(--highlight);
  transform: translateY(-1px);
}
.library-ref-tile:disabled {
  cursor: default;
}
.library-ref-star {
  position: absolute;
  top: -4px; right: -4px;
  width: 16px; height: 16px;
  border-radius: 50%;
  font-size: 10px;
  line-height: 16px;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-3);
  opacity: 0;
  transition: opacity 0.15s, transform 0.15s, background 0.15s;
}
.library-ref-tile:hover:not(.is-frontal):not(:disabled) .library-ref-star {
  opacity: 0.7;
}
.library-ref-tile.is-frontal {
  border-color: #f5b942;
  /* Subtle warm glow to make the frontal pop without screaming. */
  box-shadow: 0 0 0 2px rgba(245, 185, 66, 0.25);
}
.library-ref-tile.is-frontal .library-ref-star {
  opacity: 1;
  background: #f5b942;
  color: #1a1a1a;
  border-color: #f5b942;
  transform: scale(1.1);
}

/* "Выбери фронтальную" warning chip in the card head — only visible until
   the user picks one. Subtle amber, not aggressive red — it's a nudge, not
   an error. */
.library-incomplete-chip {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: rgba(245, 185, 66, 0.18);
  color: #c68a1c;
  border: 1px solid rgba(245, 185, 66, 0.45);
  border-radius: 10px;
  white-space: nowrap;
  text-transform: uppercase;
  cursor: help;
}

.library-card-actions {
  display: flex; align-items: center; gap: 8px;
  margin-top: 4px;
}
.library-gen-portraits {
  font-size: 12px;
  padding: 6px 12px;
  flex: 1;
  white-space: nowrap;
}
.library-cost {
  font-size: 11px;
  white-space: nowrap;
}
.library-card-status {
  font-size: 11px;
  line-height: 1.4;
  min-height: 14px;
}
.library-card-status.error { color: #d6534b; }

/* Generic standalone spinner (library cards, etc.) — same kitty.
   Sized small enough to live next to short status labels. */
.spinner {
  display: inline-block;
  width: 22px; height: 22px;
  background-image: var(--kitty-mascot);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  transform-origin: 50% 80%;
  animation: kitty-bob 1.2s var(--ease-in-out) infinite alternate;
  vertical-align: middle;
  border: none;
}
/* Kept so any 3rd-party / inline use of `spin` still resolves. */
@keyframes spin { to { transform: rotate(360deg); } }
/* Gentle ear-to-ear head wiggle — the only animation our kitty needs.
   Origin is set on each consumer (`transform-origin: 50% 80%`) so the
   rotation looks like the head pivoting at the chin/neck, not the
   whole face swinging from a flagpole. */
@keyframes kitty-bob {
  from { transform: rotate(-7deg); }
  to   { transform: rotate(7deg); }
}

/* Library: "add new" modal preview strip */
.library-add-upload {
  margin-top: 6px;
  display: inline-block;
  cursor: pointer;
  padding: 10px 14px;
  border: 1px dashed var(--border-strong);
  border-radius: 6px;
  font-size: 12px;
}
.library-add-preview {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 10px;
  max-height: 180px;
  overflow-y: auto;
}
.library-add-preview img {
  width: 64px; height: 64px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
}

/* Library picker modal — grid of saved-char tiles to choose from. */
.library-pick {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.library-pick-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.library-pick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 12px;
  overflow-y: auto;
  padding: 4px;
  max-height: 60vh;
}
.library-pick-tile {
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0;
  overflow: hidden;
  cursor: pointer;
  display: flex; flex-direction: column;
  transition: border-color 0.15s, transform 0.15s;
}
.library-pick-tile:hover {
  border-color: var(--highlight);
  transform: translateY(-2px);
}
.library-pick-tile img {
  width: 100%;
  aspect-ratio: 9/16;
  object-fit: cover;
  display: block;
}
.library-pick-noimg {
  width: 100%; aspect-ratio: 9/16;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg);
  color: var(--text-3);
  font-size: 32px;
}
.library-pick-meta {
  padding: 8px 10px 10px;
  display: flex; flex-direction: column; gap: 3px;
  font-size: 12px;
}
.library-pick-name { font-weight: 600; }
.library-pick-count { font-size: 10px; }
.library-pick-incomplete {
  font-size: 10px;
  color: #c68a1c;
  font-weight: 600;
  letter-spacing: 0.02em;
  margin-top: 2px;
}
.library-pick-tag {
  font-size: 10px;
  color: var(--text-3);
  font-style: italic;
  line-height: 1.3;
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* From-library button on char cards — slightly different accent so the
   "import from album" affordance reads as a shortcut, not another upload. */
.char-card .from-library {
  font-size: 12px;
  padding: 6px 10px;
}
.char-card .save-to-library {
  font-size: 11px;
  padding: 5px 10px;
  color: var(--highlight);
}
.char-card.compact .from-library {
  font-size: 11px;
  padding: 6px 8px;
}

/* ---------- Script tab: video → script importer ---------- */
.script-label-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 6px;
}
.video-import-btn {
  display: inline-flex; align-items: center; gap: 7px;
  cursor: pointer; user-select: none;
  font-size: 11px; font-weight: 500;
  color: var(--text-2);
  padding: 5px 11px;
  border: 1px dashed var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  text-transform: none; letter-spacing: 0;
  transition: all 0.18s var(--ease-out);
}
.video-import-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
  border-style: solid;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.video-import-btn:active { transform: translateY(0); box-shadow: none; }
.video-import-btn .vi-icon { font-size: 13px; line-height: 1; }
.video-import-btn .vi-text { letter-spacing: 0.01em; }

/* ---------- Global edit: big yellow button + modal ---------- */
.global-edit-btn {
  display: inline-flex; align-items: center; gap: 8px;
  cursor: pointer; user-select: none;
  font-size: 12px; font-weight: 600;
  padding: 9px 14px 9px 10px;
  border: 1.5px solid #f4b400;
  background: linear-gradient(180deg, #fff3c4 0%, #ffd84d 100%);
  color: #5a3d00;
  border-radius: 8px;
  letter-spacing: 0.02em;
  text-transform: none;
  box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset, 0 2px 6px rgba(244,180,0,0.25);
  transition: all 0.18s var(--ease-out);
  position: relative;
}
.global-edit-btn:hover {
  background: linear-gradient(180deg, #ffe88a 0%, #ffc107 100%);
  border-color: #d99a00;
  transform: translateY(-1px);
  box-shadow: 0 1px 0 rgba(255,255,255,0.7) inset, 0 4px 12px rgba(244,180,0,0.35);
}
.global-edit-btn:active { transform: translateY(0); box-shadow: 0 1px 3px rgba(244,180,0,0.3); }
.global-edit-btn .ge-bang {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px;
  background: #5a3d00; color: #fff;
  border-radius: 50%;
  font-weight: 800; font-size: 13px; line-height: 1;
  font-family: ui-sans-serif, system-ui, sans-serif;
}
/* Pulsing halo via a pseudo-element: composite-only `transform: scale` +
   `opacity` instead of growing `box-shadow` every frame. 3 of these can
   live on screen simultaneously (script/frames/videos tabs) — old paint
   cost added up. */
.global-edit-btn .ge-bang::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(244, 180, 0, 0.55);
  pointer-events: none;
  z-index: -1;
  animation: ge-pulse 2.2s ease-in-out infinite;
}
.global-edit-btn .ge-text { letter-spacing: 0.02em; }
@keyframes ge-pulse {
  0%, 100% { transform: scale(1);   opacity: 0.55; }
  50%      { transform: scale(1.6); opacity: 0;    }
}

.global-edit-modal h3 { color: #5a3d00; }
.global-edit-modal h3::before {
  content: "!";
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  background: #f4b400; color: #fff;
  border-radius: 50%;
  font-weight: 800; font-size: 14px;
  margin-right: 10px;
  vertical-align: -3px;
}
#modal-global-edit .modal-content {
  border-top: 3px solid #f4b400;
}
.ge-examples {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px;
}
.ge-example-chip {
  font-size: 11px;
  padding: 5px 10px;
  border: 1px dashed var(--border-strong);
  background: var(--surface);
  color: var(--text-2);
  border-radius: 999px;
  cursor: pointer;
  text-transform: none;
  font-weight: 500;
  letter-spacing: 0;
  transition: all 0.15s var(--ease-out);
}
.ge-example-chip:hover {
  border-style: solid;
  border-color: #f4b400;
  color: #5a3d00;
  background: #fff8dc;
}

/* ---------- Video import modal ---------- */
.video-import-modal h3 {
  margin: 0 0 4px;
}
.vi-drop {
  display: block;
  cursor: pointer;
  border: 1.5px dashed var(--border-strong);
  border-radius: 10px;
  padding: 18px 16px;
  background: var(--surface);
  transition: all 0.18s var(--ease-out);
  user-select: none;
}
.vi-drop:hover {
  border-color: var(--accent);
  background: var(--surface-2, var(--surface));
}
.vi-drop-empty {
  display: flex; align-items: center; gap: 14px;
  color: var(--text-2);
}
.vi-drop-icon {
  font-size: 28px; opacity: 0.7;
}
.vi-drop-text {
  flex: 1;
  font-size: 13px;
  line-height: 1.5;
}
.vi-drop-hint {
  font-size: 11px;
  opacity: 0.7;
}
.vi-drop-filled {
  display: flex; align-items: center; gap: 12px;
}
.vi-drop-filled .vi-file-icon {
  font-size: 22px;
}
.vi-drop-filled .vi-file-info {
  flex: 1;
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0;
}
.vi-drop-filled .vi-file-name {
  font-weight: 600;
  font-size: 13px;
  color: var(--accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vi-drop-filled .vi-file-size {
  font-size: 11px;
  color: var(--text-2);
}
.vi-file-clear {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-2);
  width: 26px; height: 26px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 12px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  transition: all 0.15s var(--ease-out);
  flex-shrink: 0;
}
.vi-file-clear:hover {
  border-color: var(--danger);
  color: var(--danger);
  background: rgba(220,53,69,0.06);
}
.video-import-modal textarea {
  resize: vertical;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12px;
  line-height: 1.5;
}

