/* Video Pro -- shared styles. Same "Obsidian Glass" dark system the other
   Studio OS tools use (translucent panels, soft blur, restrained borders),
   with its own accent (magenta/pink-violet) instead of reusing an existing
   tool's hue -- see the accepted planning artifact for why.

   Redesign pass: pulled from a reference video editor mockup -- floating
   rounded surfaces instead of boxy flat panels, a second accent hue (cyan)
   reserved specifically for "smart"/AI-adjacent cues so it reads as a
   distinct signal rather than just a second decoration, toggle switches on
   things that can genuinely be turned on/off, and a colored-fill custom
   range control (same technique Studio OS's own .glass-range uses) instead
   of the browser's default slider chrome. */

:root {
  --bg: #0b0c10;
  --panel: rgba(255,255,255,0.05);
  --panel-2: rgba(255,255,255,0.035);
  --panel-solid: #16171d;
  --border: rgba(255,255,255,0.10);
  --text: #f3f1f6;
  --text-dim: #a9a5b4;
  --text-faint: #726d81;
  /* "Sorbet Light" -- picked over the original magenta for being colorful
     without the harshness: peach into pink into lavender, plus a real
     multi-stop gradient token (--accent-grad) for the surfaces that carry
     the full wash (brand mark, primary button, active preset, an "on"
     switch) rather than just a single flat hue. --accent stays a single
     representative pink for everything that CAN'T render a gradient --
     native accent-color, border/hover states, color-mix() inputs. */
  --accent: #f472b6;
  --accent-2: #c084fc;
  --accent-soft: rgba(244,114,182,0.14);
  --accent-line: rgba(244,114,182,0.4);
  --accent-2-line: rgba(192,132,252,0.4);
  --accent-grad: linear-gradient(135deg, #fdba74, #f472b6, #c084fc);
  /* Reserved for AI/"smart" cues only (the assistant teaser, future
     AI-generated content) -- keeping it off everything else is what makes
     it read as a distinct signal instead of a second decorative accent. */
  --cyan: #5eead4;
  --cyan-soft: rgba(94,234,212,0.14);
  --cyan-line: rgba(94,234,212,0.4);
  /* Audio's own hue -- its track row and inspector control read as a
     distinct lane, not a property tucked inside the video clip. */
  --audio: #f2b84b;
  --audio-line: rgba(242,184,75,0.4);
  --glass-blur: blur(22px) saturate(1.5);
  --glass-strong: rgba(255,255,255,0.09);
  --glass-shadow: 0 20px 60px rgba(0,0,0,0.45);
  /* A softer, shorter-radius blur for smaller glass surfaces (toolbar,
     clips, buttons) -- the full --glass-blur reads right on a big panel but
     turns mushy on something 32-48px tall. */
  --glass-blur-sm: blur(10px) saturate(1.4);
  --danger: #c0392b;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

body {
  background-image:
    radial-gradient(60% 50% at 15% 0%, rgba(253,186,116,0.09), transparent 60%),
    radial-gradient(55% 45% at 60% 0%, rgba(244,114,182,0.09), transparent 60%),
    radial-gradient(50% 40% at 100% 100%, rgba(192,132,252,0.10), transparent 60%),
    radial-gradient(40% 30% at 85% 0%, rgba(94,234,212,0.06), transparent 60%);
  background-attachment: fixed;
  min-height: 100vh;
}

a { color: inherit; }

.btn {
  /* Frosted rather than flat -- picks up whatever's behind it (the ambient
     wash on body, or another panel's own color) through the blur, which is
     the whole point of a glass control: it belongs to the surface behind
     it, not just to itself. */
  background: rgba(255,255,255,0.055);
  backdrop-filter: var(--glass-blur-sm);
  -webkit-backdrop-filter: var(--glass-blur-sm);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 18px;
  font-size: 13px;
  font-weight: 550;
  font-family: inherit;
  cursor: pointer;
  user-select: none;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn:hover:not(:disabled) { border-color: var(--accent); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* The one button meant to actually pop -- carries the full accent-grad
   wash plus a soft specular sheen (the diagonal highlight glass catches)
   instead of flat white. */
.btn.primary {
  background: var(--accent-grad); border-color: transparent; color: #1a0f14; font-weight: 700;
  box-shadow: 0 4px 20px rgba(244,114,182,0.28), inset 0 1px 0 rgba(255,255,255,0.45);
  position: relative; overflow: hidden;
}
.btn.primary::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, rgba(255,255,255,0.35) 0%, transparent 40%);
}
.btn.primary:hover:not(:disabled) { border-color: transparent; filter: brightness(1.04); }
.btn.ghost { background: rgba(255,255,255,0.03); }
.btn.sm { padding: 5px 14px; font-size: 11.5px; }

/* Reusable pill toggle switch (Off/On), used wherever a real feature can be
   turned on without losing its own settings -- e.g. hiding a text overlay
   without deleting it. Same control shape studio-os's own .switch uses. */
.switch { position: relative; display: inline-block; width: 34px; height: 20px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.switch .track {
  position: absolute; inset: 0; background: var(--border); border-radius: 999px;
  transition: background 0.2s ease; cursor: pointer;
}
.switch .thumb {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: #fff;
  border-radius: 50%; transition: transform 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.3); pointer-events: none;
}
/* "On" carries the same accent-grad wash as the primary button, so a
   switch you've flipped reads as part of the same glass family instead of
   a flat color borrowed from a different system. */
.switch input:checked + .track { background: var(--accent-grad); }
.switch input:checked + .track + .thumb { transform: translateX(14px); }
/* Smaller variant for a checkbox that sits inline next to its own text
   label (the per-clip "force on" override), rather than opposite a section
   header the way every other .switch on this page does. */
.switch.small { width: 28px; height: 16px; }
.switch.small .thumb { width: 12px; height: 12px; }
.switch.small input:checked + .track + .thumb { transform: translateX(12px); }

/* One row per audio track in the always-visible mixer tile -- label, a
   volume slider that eats the remaining width, its live percentage, then
   the mute switch, all on one line so three tracks stack compactly. */
.mixer-row { display: flex; align-items: center; gap: 10px; }
.mixer-row + .mixer-row { margin-top: 14px; }
.mixer-track-label {
  width: 22px; flex-shrink: 0; font-size: 11px; font-weight: 650; color: var(--text-dim);
  font-variant-numeric: tabular-nums; display: inline-flex; align-items: center; gap: 5px;
}
/* Each row picks up the SAME color its track already wears on the timeline
   (see .timeline-track-label .dot) -- both the little dot and the slider's
   own fill, so three tracks in a row don't all read as one identical grey
   bar repeated three times, and a color you already associate with "A2" on
   the timeline means the same thing here. Just accent-color, same safe
   mechanism as everywhere else -- no track/thumb restyling, no risk to
   dragging. */
.dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.dot-a1 { background: var(--audio); }
.dot-a2 { background: color-mix(in srgb, var(--audio) 55%, white); }
.dot-a3 { background: var(--accent-2); }
/* Specificity has to beat input[type="range"].glass-range's own accent-color
   (0,2,1) -- matching that same compound selector plus the extra class,
   rather than just `.mixer-slider-a1` alone, is what actually wins. */
input[type="range"].glass-range.mixer-slider-a1 { accent-color: var(--audio); }
input[type="range"].glass-range.mixer-slider-a2 { accent-color: color-mix(in srgb, var(--audio) 55%, white); }
input[type="range"].glass-range.mixer-slider-a3 { accent-color: var(--accent-2); }
.mixer-value { flex-shrink: 0; width: 34px; text-align: right; }
.mixer-row input[type="range"] { flex: 1; min-width: 0; }
/* The "This clip" row (no slider, just a label + its own mute switch) --
   pushes the two apart instead of leaving the switch stranded mid-row the
   way the fixed 22px track-label width would. */
.mixer-row.simple { justify-content: space-between; }
.mixer-row.simple .mixer-track-label { width: auto; }
/* Separates the always-on A1/A2/A3 rows from the appended "whichever clip
   is selected" part below them -- thin enough to read as a break, not
   another bordered box. */
.mixer-divider { height: 1px; background: var(--border); margin: 14px 0 12px; }
.audio-clip-part .inspector-field { margin-top: 12px; }
/* A row with nothing behind it yet (e.g. A3 before any music is imported)
   controls a track that doesn't exist -- pointer-events:none makes the
   whole row properly inert (slider AND switch, not just one input at a
   time), and the dimming matches how a disabled .glass-range already reads
   elsewhere in this panel. */
.mixer-row.unavailable { opacity: 0.35; pointer-events: none; }

/* The per-clip "play anyway" override -- a small switch plus its own label
   on one line, rather than the switch living up in the section header the
   way the section's own enable/mute switch does (this one isn't the
   section's main toggle, it's a narrow exception to it). */
.checkbox-row { display: flex; align-items: center; gap: 8px; }
.checkbox-row label:not(.switch) { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; cursor: pointer; }
/* Our own `display: flex` above otherwise outranks the UA stylesheet's
   `[hidden] { display: none }` (same specificity, author sheet loads
   later) and the row would stay visible despite the attribute. */
.checkbox-row[hidden] { display: none; }

/* Plain native range input, tinted with accent-color -- the exact technique
   Portrait Pro's own sliders use (see its .slider-row input[type=range]:
   just `accent-color`, nothing else). Several rounds of a from-scratch
   custom thumb + a JS-driven drag/overlay system, built to work around a
   real Safari click-to-jump quirk, ended up LESS reliable overall than just
   handing the whole gesture back to the browser's own native slider
   handling -- Portrait Pro never needed any of that custom machinery, and
   copying its plain-native approach is the actual fix. This trades away the
   old colored left-fill and the bipolar two-tone track for a native thumb
   that's simply reliable to grab and drag everywhere, same as Portrait Pro.
   outline: none on focus is deliberate too -- a highlighted-and-selected
   look was reading as a rendering glitch rather than a focus ring. */
input[type="range"].glass-range {
  width: 100%; accent-color: var(--accent); cursor: pointer; margin: 0; height: 20px;
}
input[type="range"].glass-range:disabled { opacity: 0.35; cursor: not-allowed; }
input[type="range"].glass-range:focus { outline: none; }
/* Temp/Tint's blue<->orange / green<->magenta cue now lives ON the real
   slider itself (see applyBipolarAccent in app.js, which sets accent-color
   inline based on which side of 0 the value is on) rather than a second
   decorative bar underneath it -- accent-color is the one thing about this
   input that was always safe to touch (it never affects hit-testing or
   drag), so this stays just as reliable as the plain single-accent sliders. */

/* ---------- Login page ---------- */
.auth-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 24px; }
.auth-card {
  width: 100%; max-width: 380px; border: 1px solid var(--border);
  background: var(--panel); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow); border-radius: 22px; padding: 32px 28px;
}
.auth-card .brand { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; }
.auth-card .brand .mark {
  width: 32px; height: 32px; border-radius: 10px;
  background: var(--accent-grad);
  display: flex; align-items: center; justify-content: center; color: #fff; flex-shrink: 0;
}
.auth-card .brand .mark svg { width: 18px; height: 18px; }
.auth-card h1 { font-size: 18px; margin: 0; letter-spacing: -0.01em; }
.auth-card p.tag { margin: 2px 0 0; font-size: 12px; color: var(--text-faint); }
.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.field label { font-size: 12px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; }
.field input {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 11px; color: var(--text); font-size: 14px; font-family: inherit;
}
.field input:focus { outline: none; border-color: var(--accent); }
.auth-error { color: var(--danger); font-size: 13px; min-height: 18px; margin-bottom: 10px; }
.auth-submit { width: 100%; padding: 10px 0; border-radius: 999px; font-size: 14px; justify-content: center; }
.auth-hint { margin-top: 18px; font-size: 12px; color: var(--text-faint); text-align: center; line-height: 1.5; }

/* ---------- Editor shell ---------- */
.editor-shell { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }

/* Purely decorative title strip (macOS-style traffic lights + centered
   name) -- costs nothing and immediately reads as "a real app," not a
   browser tab full of controls. Doubles as a natural home if this ever
   does get wrapped in a native shell later (see the launch plan's Option D
   note), since that's genuinely what this chrome mimics. */
.title-bar {
  display: flex; align-items: center; justify-content: center; position: relative;
  height: 34px; flex-shrink: 0; background: #000; border-bottom: 1px solid var(--border);
}
.title-bar .traffic-lights { position: absolute; left: 14px; display: flex; gap: 8px; }
.title-bar .traffic-lights span { width: 11px; height: 11px; border-radius: 50%; }
.title-bar .traffic-lights span:nth-child(1) { background: #ff5f57; }
.title-bar .traffic-lights span:nth-child(2) { background: #febc2e; }
.title-bar .traffic-lights span:nth-child(3) { background: #28c840; }
.title-bar .title { font-size: 12.5px; color: var(--text-faint); font-weight: 550; }

.topbar {
  display: flex; align-items: center; gap: 10px; padding: 12px 18px;
  border-bottom: 1px solid var(--border); background: var(--panel); backdrop-filter: var(--glass-blur);
  flex-shrink: 0;
}
.topbar .spacer { flex: 1; }
.topbar .icon-btn {
  width: 34px; height: 34px; border-radius: 999px; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.05); backdrop-filter: var(--glass-blur-sm); -webkit-backdrop-filter: var(--glass-blur-sm);
  border: 1px solid var(--border); color: var(--text-dim); cursor: pointer;
}
.topbar .icon-btn:hover:not(:disabled) { color: var(--text); border-color: var(--accent-line); }
.topbar .icon-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.topbar .icon-btn svg { width: 17px; height: 17px; }
.brand-mini { display: flex; align-items: center; gap: 9px; font-size: 14px; font-weight: 700; color: var(--text); margin-right: 8px; letter-spacing: -0.01em; }
.brand-mini .mark {
  width: 26px; height: 26px; border-radius: 8px; flex-shrink: 0;
  background: var(--accent-grad);
  display: flex; align-items: center; justify-content: center; color: #fff;
}
.brand-mini .mark svg { width: 15px; height: 15px; }

/* AI-copilot teaser -- Phase 3 in the roadmap, not built yet. Shown as a
   deliberately non-interactive, clearly-labeled preview of what's coming
   rather than either hiding the idea entirely or faking a working button --
   the cyan accent (reserved for exactly this) is what signals "smart
   feature," not the pill shape alone. */
.ai-teaser {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px 7px 11px; border-radius: 999px;
  background: var(--cyan-soft); border: 1px solid var(--cyan-line); color: var(--cyan);
  backdrop-filter: var(--glass-blur-sm); -webkit-backdrop-filter: var(--glass-blur-sm);
  font-size: 12px; font-weight: 650; cursor: default; margin-right: 4px;
}
.ai-teaser svg { width: 14px; height: 14px; }
.ai-teaser .soon { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); margin-left: 2px; }
.user-email { font-size: 12px; color: var(--text-faint); margin-right: 2px; }

.workspace { flex: 1; display: flex; min-height: 0; }

.media-panel {
  width: 260px; flex-shrink: 0; border-right: 1px solid var(--border);
  background: var(--panel-2); display: flex; flex-direction: column; padding: 16px; overflow-y: auto;
}
.media-panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.media-panel-head h2 { font-size: 13px; margin: 0; font-weight: 650; }
.media-panel .empty { font-size: 12.5px; color: var(--text-faint); margin-top: 8px; }
.media-panel .inspector-section:first-child { margin-top: 0; }

/* Basic color grading -- Filters preset row + Adjust sliders, both real
   (see webcodecs-engine.js's cssAdjustFilter/applyToneOverlay), living in
   the left panel's own "Adjust" tab. */
/* Fixed 3-column grid, not flex-wrap -- 5 presets always lay out as a neat
   3-then-2 block (exactly 2 rows) regardless of the panel's width, instead
   of flex-wrap's variable wrap point (which left a lone "Vivid" stranded on
   its own third row at the panel's usual width). */
.filter-preset-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
.filter-preset {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 999px;
  padding: 5px 4px; font-size: 10px; font-weight: 600; color: var(--text-dim);
  cursor: pointer; font-family: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.filter-preset:hover { border-color: var(--accent-line); color: var(--text); }
.filter-preset.active { background: var(--accent-grad); border-color: transparent; color: #1a0f14; font-weight: 700; }
.reset-link {
  background: none; border: none; padding: 0; font-size: 10.5px; font-weight: 650;
  color: var(--text-faint); cursor: pointer; font-family: inherit; text-transform: uppercase; letter-spacing: 0.04em;
}
.reset-link:hover { color: var(--accent); }


.stage-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.stage {
  flex: 1; display: flex; align-items: center; justify-content: center; padding: 28px;
  min-height: 0; position: relative;
}
/* The preview "floats" -- generous rounding, a strong shadow, and a hairline
   glow ring instead of a flat bordered rectangle -- reads as the centerpiece
   of the app instead of one more panel among several. */
.stage canvas {
  max-width: 100%; max-height: 100%; background: #000; border-radius: 16px;
  box-shadow: var(--glass-shadow), 0 0 0 1px var(--glass-strong);
}
/* The big, primary "get started" import target -- lives in the stage
   itself (the centerpiece of the app) rather than a small box off to the
   side, so the very first thing you can do is exactly the thing you came
   to do. Once a clip is loaded this is hidden and the canvas takes over;
   the media panel's own "+" covers adding more after that. */
.stage-drop {
  width: 100%; max-width: 420px; padding: 48px 32px; border-radius: 20px;
  border: 1.5px dashed var(--border); text-align: center; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  color: var(--text-faint); background: var(--panel);
}
.stage-drop svg { width: 34px; height: 34px; color: var(--text-faint); }
.stage-drop:hover, .stage-drop.drag-over { border-color: var(--accent); background: var(--accent-soft); }
.stage-drop:hover svg, .stage-drop.drag-over svg { color: var(--accent); }
.stage-drop:hover .stage-drop-title, .stage-drop.drag-over .stage-drop-title { color: var(--text); }
.stage-drop-title { font-size: 15px; font-weight: 650; color: var(--text-dim); }
.stage-drop-sub { font-size: 12.5px; line-height: 1.5; max-width: 300px; }
.stage-drop input { display: none; }
.stage:fullscreen canvas, .stage:-webkit-full-screen canvas { border-radius: 0; box-shadow: none; max-width: 100vw; max-height: 100vh; }
.stage:fullscreen, .stage:-webkit-full-screen { background: #000; }

.transport {
  display: flex; align-items: center; gap: 14px; padding: 12px 22px;
  border-top: 1px solid var(--border); flex-shrink: 0;
}
.transport .icon-btn {
  width: 32px; height: 32px; border-radius: 999px; display: flex; align-items: center; justify-content: center;
  background: var(--panel-2); border: 1px solid var(--border); color: var(--text-dim); cursor: pointer;
}
.transport .icon-btn:hover:not(:disabled) { color: var(--text); border-color: var(--accent-line); }
.transport .icon-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.transport .icon-btn svg { width: 15px; height: 15px; }
.transport .timecode { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.transport .scrubber { flex: 1; }

.inspector-panel {
  width: 270px; flex-shrink: 0; border-left: 1px solid var(--border);
  background: var(--panel-2); padding: 18px; overflow-y: auto;
}
.inspector-panel h2 { font-size: 13px; margin: 0 0 4px; font-weight: 650; }
.inspector-panel .empty { font-size: 12.5px; color: var(--text-faint); margin-top: 8px; }
.inspector-section {
  margin-top: 18px; padding: 14px; border-radius: 14px; background: var(--panel); border: 1px solid var(--border);
}
.inspector-section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.inspector-section-head label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 650; }
/* Collapsible tool sections, same pattern as Portrait Pro's own Look
   category rows -- a chevron that flips 180deg on open, its body collapsing
   to nothing rather than just dimming, so a long inspector with everything
   open at once (Text overlay + Audio + Fade + Trim, all real controls) can
   actually be put away section by section for optimal use of space. */
.inspector-section:not(.open) .inspector-section-head { margin-bottom: 0; }
.section-toggle-label {
  display: flex; align-items: center; gap: 6px; background: none; border: none; padding: 0;
  cursor: pointer; font-family: inherit; min-width: 0;
}
/* Explicit rotate(0deg) rather than leaving this un-set (which computes to
   "none") -- transitioning between an actual rotation and the special
   "none" keyword doesn't reliably animate back once it's been rotated, in
   at least one browser tested against this. Two numeric rotate() values
   interpolate cleanly every time. */
.section-chevron { flex-shrink: 0; color: var(--text-faint); transform: rotate(0deg); transition: transform 0.15s ease; }
.inspector-section.open .section-chevron { transform: rotate(180deg); }
.section-toggle-label:hover .section-chevron { color: var(--text-dim); }
.inspector-section:not(.open) .inspector-section-body { display: none; }
.inspector-field { margin-top: 0; }
.inspector-field + .inspector-field { margin-top: 12px; }
.inspector-field > label { display: block; font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px; }
.inspector-field .label-row.solo-value { justify-content: flex-end; }
.inspector-field .label-row { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
.inspector-field .label-row label { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; }
.inspector-field .label-row .value { font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.inspector-field .row > div { flex: 1; min-width: 0; }
/* Editable counterpart to the plain ".value" span above -- lets Trim be set
   by typing an exact number instead of fighting a mouse drag for precision. */
.inspector-field .label-row input.value-input {
  width: 56px; background: var(--panel-solid); border: 1px solid var(--border); border-radius: 6px;
  padding: 2px 6px; color: var(--text-dim); font-size: 11px; font-family: inherit;
  font-variant-numeric: tabular-nums; text-align: right;
}
.inspector-field .label-row input.value-input:focus { outline: none; border-color: var(--accent); color: var(--text); }
.inspector-field .label-row input.value-input::-webkit-inner-spin-button,
.inspector-field .label-row input.value-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.inspector-field .label-row input.value-input[type="number"] { -moz-appearance: textfield; }
.inspector-field input[type="text"] {
  width: 100%; background: var(--panel-solid); border: 1px solid var(--border); border-radius: 10px;
  padding: 8px 11px; color: var(--text); font-size: 13px; font-family: inherit;
}
.inspector-field input[type="text"]:focus { outline: none; border-color: var(--accent); }
/* A textarea, not an input, so Enter inserts a real line break instead of
   doing nothing -- a caption/title that ran off the edge of the frame used
   to have no way to wrap onto a second line at all. */
.inspector-field textarea.text-overlay-input {
  width: 100%; background: var(--panel-solid); border: 1px solid var(--border); border-radius: 10px;
  padding: 8px 11px; color: var(--text); font-size: 13px; font-family: inherit; line-height: 1.4;
  resize: vertical; min-height: 54px;
}
.inspector-field textarea.text-overlay-input:focus { outline: none; border-color: var(--accent); }
.inspector-field textarea.text-overlay-input:disabled { opacity: 0.5; cursor: not-allowed; resize: none; }
.inspector-field .row { display: flex; gap: 10px; }
/* Native color input, boxed to match the rest of the glass inputs instead of
   the browser's own bare swatch -- padding pushes the actual color chip in
   from the border on every engine that draws one (Chromium/Firefox/Safari
   all differ slightly here, this keeps it consistent-looking regardless). */
.inspector-field input[type="color"].color-swatch {
  width: 100%; height: 34px; background: var(--panel-solid); border: 1px solid var(--border); border-radius: 10px;
  padding: 3px; cursor: pointer;
}
.inspector-field input[type="color"].color-swatch:disabled { opacity: 0.4; cursor: not-allowed; }
.inspector-field input[type="color"].color-swatch::-webkit-color-swatch-wrapper { padding: 0; border-radius: 7px; overflow: hidden; }
.inspector-field input[type="color"].color-swatch::-webkit-color-swatch { border: none; border-radius: 7px; }
.inspector-field .row input { flex: 1; }
/* Toolbar-inline variant (the Remove button lives alongside Cutter/+Video/
   etc. now, not as its own full-width row at the bottom of the inspector). */
.btn.danger { color: var(--danger); border-color: rgba(192,57,43,0.4); }
.btn.danger:hover:not(:disabled) { background: rgba(192,57,43,0.1); border-color: var(--danger); }

.timeline-panel {
  /* Default tall enough for all four rows (Video/Audio/Music/Text) at once
     -- was 200px, sized back when there were only two rows, which silently
     clipped the later ones since overflow-y was OFF (see below). Height is
     re-set inline in px once the user drags the resize handle. */
  height: 280px; flex-shrink: 0; border-top: 1px solid var(--border);
  background: var(--panel-2); display: flex; flex-direction: column; min-height: 120px;
  /* Dragging a clip/playhead/handle is a mousedown-then-move over plain text
     (clip names, track labels, ruler numbers) -- without this, the browser
     reads that as a text-selection drag and highlights everything under the
     cursor instead of (or alongside) the app's own drag behavior. Nothing
     in this panel is ever meant to be selected/copied as text. */
  user-select: none; -webkit-user-select: none;
}
/* Drag-to-resize handle -- lets the timeline grow past its default height
   for projects with several tracks, instead of being permanently stuck at
   one fixed size. */
.timeline-resize-handle {
  height: 6px; flex-shrink: 0; cursor: ns-resize; background: transparent; position: relative;
}
.timeline-resize-handle::after {
  content: ""; position: absolute; left: 50%; top: 2px; width: 36px; height: 3px;
  transform: translateX(-50%); border-radius: 999px; background: var(--border);
}
.timeline-resize-handle:hover::after, .timeline-resize-handle.dragging::after { background: var(--accent); }
.timeline-toolbar {
  display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-bottom: 1px solid var(--border);
  background: rgba(255,255,255,0.025); backdrop-filter: var(--glass-blur-sm); -webkit-backdrop-filter: var(--glass-blur-sm);
}
.timeline-toolbar .spacer { flex: 1; }
.timeline-zoom { display: flex; align-items: center; gap: 8px; width: 120px; }
.timeline-zoom svg { width: 13px; height: 13px; color: var(--text-faint); flex-shrink: 0; }
/* overflow-y was `hidden` -- with four track rows that no longer fit even
   the taller default above, that silently clipped the Music/Text rows with
   no way to reach them at all. `auto` is the actual fix; the resize handle
   above just makes scrolling less necessary. */
.timeline-tracks { flex: 1; overflow-x: auto; overflow-y: auto; position: relative; padding: 12px 16px; }
.timeline-ruler { height: 18px; position: relative; margin-bottom: 8px; font-size: 10px; color: var(--text-faint); margin-left: 64px; cursor: pointer; }
/* Tick marks + timecodes (see renderRuler in app.js) -- DaVinci-Resolve
   style: short unlabeled ticks every minor interval, a taller labeled tick
   every 5th one. Anchored to the ruler's own bottom edge and growing
   upward so the labels (pinned to the top) never collide with the ticks. */
.ruler-tick { position: absolute; bottom: 0; width: 0; height: 5px; border-left: 1px solid var(--border); pointer-events: none; }
.ruler-tick.major { height: 9px; border-left-color: var(--text-dim); }
.ruler-tick-label {
  position: absolute; left: 4px; top: 0; font-size: 10px; color: var(--text-faint);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.timeline-track-row { display: flex; align-items: stretch; gap: 8px; margin-bottom: 8px; }
.timeline-track-label {
  width: 56px; flex-shrink: 0; display: flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-dim); border-radius: 8px; padding: 0 8px;
}
.timeline-track-label .dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.timeline-track-label.video .dot { background: var(--accent); }
/* A lighter tint of the same accent -- reads as "video, but the other
   track" rather than an unrelated color needing its own legend. */
.timeline-track-label.video2 .dot { background: color-mix(in srgb, var(--accent) 55%, white); }
.timeline-track-label.audio .dot { background: var(--audio); }
.timeline-track-label.audio2 .dot { background: color-mix(in srgb, var(--audio) 55%, white); }
.timeline-track-label.music .dot { background: var(--accent-2); }
.timeline-track-label.text .dot { background: var(--cyan); }
.timeline-track {
  height: 48px; position: relative; background: var(--panel); border-radius: 10px; flex: 1;
  /* Picks up the ambient body wash through the blur -- the same "sidebar
     reflects the wallpaper behind it" idea, just applied to a track lane
     instead of a sidebar. */
  backdrop-filter: var(--glass-blur-sm); -webkit-backdrop-filter: var(--glass-blur-sm);
}
.timeline-track.audio-track, .timeline-track.music-track, .timeline-track.text-track { height: 32px; }
.timeline-clip {
  position: absolute; top: 3px; bottom: 3px; border-radius: 8px;
  background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 82%, white), color-mix(in srgb, var(--accent) 66%, black));
  border: 1px solid var(--accent-line); overflow: hidden; cursor: grab; display: flex; align-items: center; padding: 0 9px;
  /* inset highlight along the top edge is the "glass catching light" cue --
     paired with the ::before sheen below (a soft diagonal streak, not a
     hard shine) rather than the gradient fill alone doing all the work. */
  box-shadow: 0 4px 12px -6px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.35);
  backdrop-filter: var(--glass-blur-sm); -webkit-backdrop-filter: var(--glass-blur-sm);
}
.timeline-clip::before {
  /* z-index 1, same as .label -- source order then puts this ABOVE the
     waveform canvas (z-index 0) but still under the label text, since the
     label element itself comes after this pseudo-element in paint order. */
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(120deg, rgba(255,255,255,0.28) 0%, transparent 35%);
}
/* Same shape/behavior as a V1 clip, just noticeably lighter -- so which
   track a clip is sitting on reads at a glance, matching the two tracks'
   own dot colors. */
.timeline-clip.video2-clip {
  background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 55%, white), color-mix(in srgb, var(--accent) 35%, white));
}
.timeline-clip.selected { box-shadow: 0 0 0 2px #fff; }
.timeline-clip .label { position: relative; z-index: 1; font-size: 10.5px; font-weight: 650; color: #fff; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Real decoded waveform peaks (see waveform.js), stretched behind the label
   -- pointer-events:none so drag/trim still targets the clip div itself. */
.timeline-clip .waveform { position: absolute; inset: 0; z-index: 0; pointer-events: none; width: 100%; height: 100%; display: block; }
.timeline-clip .trim-handle { position: absolute; top: 0; bottom: 0; width: 9px; cursor: ew-resize; z-index: 2; }
.timeline-clip .trim-handle.left { left: 0; }
.timeline-clip .trim-handle.right { right: 0; }
/* DaVinci-Resolve-style edit-point marker, drawn over two adjacent clips
   that touch with no gap (see drawCutMarkers in app.js) -- sits above both
   clips' own content (z-index 2 is the trim handles) and never intercepts
   pointer events, so it's purely a visual "there's a cut here" tick. */
.cut-marker {
  position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px dashed rgba(255,255,255,0.6);
  transform: translateX(-0.5px); pointer-events: none; z-index: 3;
}
/* Fade markers (see renderFadeOverlay in app.js) -- a shaded triangle
   ramping from the clip's own top corner down to the fade point, plus a
   small draggable dot right where the ramp's diagonal edge meets the top
   of the clip. pointer-events:none on the shade so it never blocks
   dragging/trimming the clip underneath; only the dot itself is
   interactive. z-index 4 puts the dot above even the cut marker (3) and
   the trim handles (2), since at zero fade it sits exactly on the clip's
   own corner and has to win that hit-test to be grabbable at all. */
.fade-shade { position: absolute; inset: 0; background: rgba(0,0,0,0.45); pointer-events: none; z-index: 0; }
.fade-handle {
  position: absolute; top: 0; width: 9px; height: 9px; border-radius: 50%;
  background: #fff; border: 1.5px solid rgba(0,0,0,0.5); cursor: ew-resize; z-index: 4;
}
.fade-handle-in { transform: translate(-50%, -50%); }
.fade-handle-out { transform: translate(50%, -50%); }
.fade-handle:hover { background: var(--accent); }
.timeline-clip.text-clip {
  background: linear-gradient(160deg, color-mix(in srgb, var(--cyan) 30%, var(--panel-solid)), var(--panel-solid));
  border-color: var(--cyan-line);
}
.timeline-clip.text-clip .label { color: var(--cyan); }
.timeline-clip.text-clip.disabled { opacity: 0.4; }
.timeline-clip.audio-clip {
  background: linear-gradient(160deg, color-mix(in srgb, var(--audio) 85%, white), color-mix(in srgb, var(--audio) 55%, black));
  border-color: var(--audio-line);
}
.timeline-clip.audio-clip .label { color: #241a06; }
.timeline-clip.audio-clip.disabled { opacity: 0.4; }
.timeline-clip.audio-clip.audio2-clip {
  background: linear-gradient(160deg, color-mix(in srgb, var(--audio) 55%, white), color-mix(in srgb, var(--audio) 30%, white));
}
/* Highlighted while a clip is being dragged vertically over this row as a
   drop target for moving it to a different video track (see
   onClipPointerDown in app.js) -- purely a "this is where it'll land"
   affordance, not a persistent state. */
.timeline-track.drop-target { outline: 2px dashed var(--accent); outline-offset: -2px; }

/* Live "does this line up?" cue while dragging a clip -- green once an edge
   touches another clip's edge EXACTLY (zero gap -- no blank frame when this
   plays back), red the instant the proposed position would actually
   overlap/merge one on its own track. One shared line spanning every
   track row, same positioning trick as .timeline-playhead below (absolute
   + margin-left to cross #timelineTracks's own left padding) -- a music
   cue landing exactly on a video cut is just as worth seeing as two clips
   touching on the same row, so this isn't confined to the row being
   dragged. */
.proximity-marker {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0;
  margin-left: 80px;
  border-left: 2px dashed transparent;
  pointer-events: none;
  z-index: 5;
  display: none;
}
.proximity-marker.near { border-left-color: #33e070; }
.proximity-marker.merge { border-left-color: #ff4d4d; }
.timeline-clip.music-clip {
  background: linear-gradient(160deg, color-mix(in srgb, var(--accent-2) 85%, white), color-mix(in srgb, var(--accent-2) 55%, black));
  border-color: var(--accent-2-line);
}
.timeline-clip.music-clip .label { color: #fff; }
.timeline-clip.music-clip.disabled { opacity: 0.4; }
/* margin-left is 80px, not the "64px" (56px track-label + 8px flex gap)
   you'd expect matching the ruler/track-row's own offset -- position:
   absolute is measured from the CONTAINING BLOCK's padding edge, which
   does NOT include #timelineTracks's own 16px left padding the way a
   normal-flow element (the ruler is position:relative, i.e. normal flow)
   gets for free. Skipping that 16px here was exactly why a click that
   correctly computed the right time still drew the line 16px left of
   where you clicked -- 64+16=80 is what actually lines up with the tracks. */
.timeline-playhead {
  position: absolute; top: 0; bottom: 0; width: 2px; background: #fff; z-index: 5; pointer-events: none;
  box-shadow: 0 0 8px rgba(255,255,255,0.7); margin-left: 80px;
}

.hidden { display: none !important; }

/* ---------- Export settings modal ---------- */
.modal-overlay {
  position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.55); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.modal-card {
  width: 100%; max-width: 320px; border: 1px solid var(--border); border-radius: 18px;
  background: var(--panel-solid); box-shadow: var(--glass-shadow); padding: 22px 22px 18px;
}
.modal-card h3 { margin: 0 0 16px; font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
.modal-field { margin-bottom: 14px; }
.modal-field label {
  display: block; font-size: 10.5px; color: var(--text-faint); text-transform: uppercase;
  letter-spacing: 0.04em; margin-bottom: 6px;
}
.select-input {
  width: 100%; background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 11px; color: var(--text); font-size: 13px; font-family: inherit; cursor: pointer;
}
.select-input:focus { outline: none; border-color: var(--accent); }
/* The dropdown's OWN closed box picks up --text fine, but the expanded
   option list is rendered by the OS/browser chrome (typically a plain
   white popup on Windows), not our dark panel -- inheriting --text's
   near-white color onto that light background left every option nearly
   invisible. Setting color/background directly on <option> is one of the
   few things browsers actually honor inside a native select popup. */
.select-input option { background: var(--panel-solid); color: var(--text); }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }

/* ---------- Export progress / success / error modal ---------- */
/* Same shared glass-modal language other Studio OS tools already use
   (Culling Pro's export dialog: a translucent blurred backdrop over a
   solid glass card) -- this one just centers its content since it's
   status, not a form. */
#exportProgressOverlay #exportStepProcessing,
#exportProgressOverlay #exportStepSuccess,
#exportProgressOverlay #exportStepError { text-align: center; }
#exportProgressOverlay h3 { margin: 0 0 6px; }
.modal-sub { margin: 0 0 18px; font-size: 13px; color: var(--text-dim); line-height: 1.5; }
/* A real, non-fatal caveat (the export finished, but had to leave audio
   out) -- amber rather than the success/error icon's own green/red so it
   reads as its own distinct signal, not a restatement of either. */
.modal-warning {
  padding: 10px 12px; border-radius: 10px; background: rgba(242,184,75,0.12);
  border: 1px solid rgba(242,184,75,0.35); color: var(--audio); text-align: left;
}
.modal-hint { margin: 14px 0 0; font-size: 11px; color: var(--text-faint); line-height: 1.5; }

.modal-spinner {
  width: 34px; height: 34px; margin: 4px auto 16px; border-radius: 50%;
  border: 3px solid var(--border); border-top-color: var(--accent);
  animation: modal-spin 0.8s linear infinite;
}
@keyframes modal-spin { to { transform: rotate(360deg); } }

/* Same track/fill/label shape as Culling Pro's own .export-progress, just
   in Video Pro's own accent instead of Culling Pro's coral. */
.export-progress { display: flex; align-items: center; gap: 10px; margin: 0; }
.export-progress-track { flex: 1; height: 6px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
.export-progress-fill { height: 100%; width: 0%; background: var(--accent); border-radius: 999px; transition: width 0.2s ease; }
.export-progress-label { font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; flex-shrink: 0; min-width: 34px; text-align: right; }

.modal-result-icon {
  width: 52px; height: 52px; margin: 4px auto 16px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.modal-result-icon svg { width: 24px; height: 24px; }
.modal-result-icon.success { background: rgba(79,214,160,0.14); color: #4fd6a0; }
.modal-result-icon.error { background: rgba(192,57,43,0.14); color: var(--danger); }
#exportStepSuccess .btn, #exportStepError .btn { width: 100%; justify-content: center; }
