/* ===========================================
   EDIT PAGE — image tools + Clip Editor
   ===========================================

   Every rule in this file was lifted VERBATIM out of index.html's inline
   <style> block (it ran from the "Inpaint tool styles" comment to
   .inpaint-generate-icon). Nothing about the cascade changed: the inline block
   sits before every <link> in <head>, so this file is linked immediately after
   it and before css/responsive.css, which owns the <= 900px overrides for the
   same components. js/e2e/light-theme-batch4.spec.js pins that position, and
   js/e2e/light-theme-batch4.dark-baseline.json pins the resulting dark
   computed styles element by element.

   The one substantive change is the token block below. The dark literals that
   used to be spelled out inline (#0d0d14 for the tool rail, #111 for the dock
   and the timeline blocks, #0a0a11 for the overlay hints and the recents
   thumbnails, ...) are now named --ed-* custom properties, so
   css/theme-light-components.css can repoint them for .light-theme instead of
   restating whole rules. Every default below is the exact value it replaced,
   which is why the dark baseline still matches byte for byte.
   =========================================== */

:root {
  /* Chrome around the canvas: the tool rail, the action dock, the sidebar. */
  --ed-rail-bg: #0d0d14;
  --ed-dock-bg: #111;
  --ed-sidebar-bg: #111;
  --ed-hairline: #444;

  /* The editing stage. Deliberately dark in BOTH themes — a mask edge or an
     exposure cannot be judged against a white page, which is why every photo
     editor keeps a dark canvas surround in light mode too. Light theme frames
     it (see css/theme-light-components.css) rather than lightening it. */
  --ed-stage-bg: #0a0a0a;

  /* Overlay hint pill floating on the stage ("Scroll to zoom ...") */
  --ed-hint-bg: rgba(10, 10, 17, 0.72);
  --ed-hint-fg: var(--text-muted);

  /* Clip Editor timeline: the block behind a filmstrip, the not-yet-sampled
     filmstrip tile, and the recents thumbnails on the start screen. */
  --ed-block-bg: #111;
  --ed-film-bg: #14141b;
  --ed-film-stripe-a: #16161d;
  --ed-film-stripe-b: #1c1c24;
  --ed-thumb-bg: #0a0a11;
  --ed-chip-bg: rgba(10, 10, 17, 0.78);
  --ed-chip-strong-bg: rgba(10, 10, 17, 0.82);
  --ed-chip-actions-bg: rgba(8, 8, 14, 0.78);
  --ed-badge-bg: rgba(0, 0, 0, 0.45);
  --ed-badge-strong-bg: rgba(0, 0, 0, 0.55);
}

/* Inpaint tool styles (lives inside the Edit tab's workspace) */
/* Mirrors `.edit-surface .edit-canvas-wrapper` below: the two-class
   selector outranks any single-class `.inpaint-canvas-wrapper { position }`
   rule in the responsive sheet, whatever the load order. Without it the
   wrapper can be knocked back to `position: relative`, and since every
   child of it is absolutely positioned it then collapses to height 0 and
   clips the canvases away — the "black box" inpaint bug. */
.edit-surface .inpaint-canvas-wrapper {
  position: absolute;
  inset: 0;
}

.inpaint-canvas-wrapper {
  position: absolute;
  inset: 0;
  background: var(--ed-stage-bg);
  overflow: hidden;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.inpaint-upload-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  cursor: pointer;
  padding: 60px;
  transition: all 0.2s;
  border: 2px dashed transparent;
  border-radius: 8px;
}

.inpaint-upload-placeholder:hover {
  background: rgba(255, 46, 187, 0.05);
}

.inpaint-upload-icon {
  line-height: 0;
  margin-bottom: 16px;
  opacity: 0.9;
}

.inpaint-upload-text {
  color: var(--text-primary);
  font-size: 1.1rem;
  margin-bottom: 8px;
}

.inpaint-upload-hint {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* The stage holds both canvases at the fitted display size and is
   translated/scaled for pan & zoom. Canvas pixels stay at the image's
   native resolution; only the CSS transform changes. */
.inpaint-stage {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  display: none;
}

.inpaint-stage canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.inpaint-stage canvas {
  cursor: none; /* replaced by the live brush ring */
}

@media (pointer: coarse) {
  .inpaint-stage canvas { cursor: crosshair; }
}

.can-pan,
.can-pan .inpaint-stage canvas { cursor: grab; }
.is-panning,
.is-panning .inpaint-stage canvas { cursor: grabbing; }

#inpaintMaskCanvas {
  pointer-events: none;
  opacity: 0.6;
}

/* Action buttons stay docked at the bottom of the scrolling panel —
   the canvas captures the wheel for zooming, so the primary action
   must be reachable without scrolling */
.edit-session-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
  padding: 8px 10px;
  background: rgba(255, 165, 0, 0.08);
  border: 1px solid rgba(255, 165, 0, 0.35);
  border-radius: 8px;
}

.edit-session-bar #editSessionSaveBtn {
  flex: 1 1 100%;
}

.edit-session-bar .edit-session-status {
  flex: 1;
  font-size: 0.7rem;
  font-weight: 600;
  color: #ffa500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.edit-session-bar button {
  background: var(--bg-hover);
  border: 1px solid var(--ed-hairline);
  border-radius: 6px;
  color: var(--text-primary);
  padding: 6px 10px;
  font-size: 0.78rem;
  cursor: pointer;
  white-space: nowrap;
}

.edit-session-bar button:disabled {
  opacity: 0.45;
  cursor: default;
}

.edit-session-bar #editSessionSaveBtn {
  background: linear-gradient(135deg, #ff2ebb, #00b2ff);
  border: none;
  font-weight: 600;
}

/* Secondary buttons inside the tool panels (Undo / Clear Mask / Reset crop /
   Reset clone / Delete layer ...). These were eight identical
   `style="flex: 1; padding: 8px 12px; background: var(--bg-hover); border: 1px
   solid #444; ..."` attributes, and an inline style outranks every stylesheet,
   so that #444 hairline could never be re-inked for the light theme. The
   declarations below are exactly what those attributes produced — the dark
   baseline proves it element by element — with the hairline tokenised. */
.edit-panel-btn {
  flex: 1;
  padding: 8px 12px;
  background: var(--bg-hover);
  border: 1px solid var(--ed-hairline);
  border-radius: 6px;
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.85rem;
}

/* The one full-width variant (Reset crop). */
.edit-panel-btn-wide {
  /* 0 1 auto == the flex defaults the attribute this replaced never set. */
  flex: 0 1 auto;
  width: 100%;
  padding: 10px;
  font-size: 0.9rem;
}

.edit-action-dock {
  position: sticky;
  bottom: 0;
  z-index: 6;
  /* margin-top auto pins it to the sidebar bottom when content is short;
     sticky keeps it visible when the sidebar scrolls */
  margin: auto -16px -16px;
  padding: 10px 16px 16px;
  background: linear-gradient(to top, var(--ed-dock-bg) 72%, transparent);
}

/* ===========================================
   EDIT TAB — PRO EDITOR LAYOUT
   tool rail | workspace | options sidebar | results rail
   =========================================== */
.edit-pro-layout {
  display: flex;
  /* ITEM 1: 136px accounted for navbar+subtabs. The footer clearance is 0
     while Image Edit or Video Edit is active so these editor workspaces can
     use the full app height. */
  height: calc(100vh - 136px - var(--site-footer-clearance));
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
}

.edit-toolbar {
  flex: 0 0 68px;
  background: var(--ed-rail-bg);
  border-right: 1px solid var(--border-color);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 10px 6px;
  gap: 4px;
}

.edit-tool-btn {
  background: none;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--text-secondary);
  padding: 10px 2px 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: background 0.15s, color 0.15s;
}

.edit-tool-btn:hover {
  background: rgba(255, 255, 255, 0.05);
  color: var(--text-primary);
}

.edit-tool-btn.active {
  background: rgba(157, 78, 221, 0.18);
  border-color: rgba(157, 78, 221, 0.45);
  color: #fff;
}

.edit-workspace {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 16px;
  background: var(--bg-primary);
  overflow: hidden;
}

/* One surface visible at a time; each fills the workspace */
.edit-surface {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  overflow: hidden;
}

.edit-surface.reference-upload {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 0;
}

#cropPreviewContainer {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
}

.text-tool-emoji-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 4px;
}

.text-tool-emoji-grid button {
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  font-size: 1.05rem;
  padding: 4px 0;
  cursor: pointer;
  line-height: 1.4;
}

.text-tool-emoji-grid button:hover {
  background: rgba(157, 78, 221, 0.18);
}

.edit-overlay-hint {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.72rem;
  color: var(--ed-hint-fg);
  background: var(--ed-hint-bg);
  padding: 4px 14px;
  border-radius: 999px;
  pointer-events: none;
  white-space: nowrap;
  z-index: 3;
}

@media (pointer: coarse) {
  .edit-overlay-hint { display: none; }
}

.edit-sidebar {
  flex: 0 0 300px;
  min-height: 0;
  background: var(--ed-sidebar-bg);
  border-left: 1px solid var(--border-color);
  padding: 16px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.edit-sidebar-header h2 {
  margin: 0;
  font-size: 1.15rem;
  background: linear-gradient(135deg, #ff2ebb, #00b2ff);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.edit-sidebar-header .tagline {
  margin-top: 4px;
  color: var(--text-secondary);
  font-size: 0.8rem;
}

/* Results rail: fixed single column like the Inpaint tab */
#editSection .right-panel {
  flex: 0 0 380px;
  min-height: 0;
  min-width: 300px;
  border-left: 1px solid var(--border-color);
  overflow-y: auto;
  overscroll-behavior: contain;
}

#editSection .output-grid {
  grid-template-columns: 1fr;
}

/* Eraser/blur mask viewport fills its workspace surface */
.edit-canvas-wrapper {
  position: relative;
  background: var(--ed-stage-bg);
  overflow: hidden;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.edit-surface .edit-canvas-wrapper {
  position: absolute;
  inset: 0;
}

@media (max-width: 900px) {
  .edit-pro-layout {
    flex-direction: column;
    height: auto;
  }
  .edit-toolbar {
    flex: none;
    flex-direction: row;
    overflow-x: auto;
    border-right: none;
    border-bottom: 1px solid var(--border-color);
    padding: 6px;
  }
  .edit-tool-btn {
    flex: 1 0 auto;
    min-width: 64px;
  }
  .edit-workspace {
    flex: none;
    min-height: 62vh;
  }
  .edit-sidebar {
    flex: none;
    border-left: none;
    border-top: 1px solid var(--border-color);
  }
  #editSection .right-panel {
    flex: none;
    border-left: none;
  }
}

/* Edit page sub-tabs (Image Edit / Video Edit) + Clip Editor (Video Edit)
   NOTE: intentionally NOT sharing .education-subtab/-content classes —
   switchEducationSubtab() (Learn tab) queries those globally with no
   #editSection scoping, so reusing them let visiting Learn blank out
   the Edit page. Keep these fully separate, self-contained rules.

   #editSection is a .tab-section, so .tab-section.active gives it
   `display:flex` with no flex-direction (i.e. row). Before the sub-tab
   split its only child was the .edit-pro-layout wrapper, so row vs
   column was invisible. Now it has three children (subtab bar + two
   panels) that must stack vertically — force column here, scoped to
   #editSection only so other tabs' generic .tab-section behavior is
   untouched. */
#editSection {
  flex-direction: column;
  /* THE zoom-overflow root cause: #editSection is a flex item of
     .container with default min-width:auto, so zoomed timeline content
     inflated it past the viewport (all descendant max-width:100% caps
     then computed against the inflated width). Clamp it here — every
     containment rule below only works because of this one. */
  min-width: 0;
  max-width: 100%;
}

.edit-subtabs {
  margin: 0 0 12px 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
  border-bottom: 1px solid var(--border-color);
}

.edit-subtab {
  padding: 16px 24px;
  color: var(--text-secondary);
  font-size: 0.95rem;
  font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  gap: 8px;
}

.edit-subtab:hover {
  color: var(--text-primary);
  background: rgba(255,255,255,0.03);
}

.edit-subtab.active {
  color: var(--text-primary);
  border-bottom-color: #ff2ebb;
}

/* Inline SVG icons inherit currentColor: muted when inactive, brightened
   on hover, accent-pink when the sub-tab is active. */
.edit-subtab-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.edit-subtab-icon svg {
  width: 18px;
  height: 18px;
  display: block;
}
.edit-subtab.active .edit-subtab-icon { color: #ff2ebb; }

/* Panel wrapper: not sized/positioned by .tab-section's flex context
   (that now only applies to #editSection itself), so give it its own
   flex sizing within the #editSection column and let tall content
   (e.g. the Clip Editor's topbar/stage/transport/timeline stack)
   scroll instead of being clipped when the viewport is short. */
.edit-subtab-content {
  display: none;
  flex: 1;
  overflow: hidden;
}

.edit-subtab-content.active {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
  /* Never let zoomed timeline content widen the page — it must scroll
     inside .clip-editor-timeline-scroll. */
  overflow-x: hidden;
}

@media (min-width: 901px) {
  body.image-edit-subtab-active .container,
  body.video-edit-subtab-active .container {
    padding-bottom: 0;
  }

  #editImageSection.edit-subtab-content.active {
    overflow: hidden;
  }

  #editImageSection .edit-pro-layout {
    height: 100%;
    max-height: 100%;
    overflow: hidden;
  }
}

/* ITEM 1: the editor gets the full app viewport. When this sub-tab is
   active, syncFooterVisibility() hides the fixed footer and sets
   --site-footer-clearance to 0px. The fallback clearance below keeps the
   inspector above the footer if that state is not active yet at startup. */
#editVideoSection {
  box-sizing: border-box;
  height: calc(100vh - 136px - var(--site-footer-clearance));
  max-height: calc(100vh - 136px - var(--site-footer-clearance));
  flex: 0 1 calc(100vh - 136px - var(--site-footer-clearance));
  padding-bottom: var(--site-footer-clearance);
  scroll-padding-bottom: calc(var(--site-footer-clearance) + 16px);
}

/* ===== Clip Editor (CapCut-style timeline) ===== */
.clip-editor-layout {
  --ce-accent: var(--accent-primary, #ff2ebb);
  --ce-accent-soft: rgba(255, 46, 187, 0.14);
  --ce-track-h: 76px;
  --ce-audio-h: 40px;
  --ce-ruler-h: 27px; /* ITEM 6 (ergonomics): taller ruler, centred labels */
  /* Full-width editor: use the available width with only small horizontal
     padding. Removed the old max-width:1040px + margin:auto that squeezed
     the editor into a centered card on wide screens. */
  padding: 12px clamp(16px, 2.5vw, 40px);
  width: 100%;
  /* Contain zoomed-timeline width at every flex level — min-width:auto
     on any ancestor lets max-content leak out and widen the page. */
  --ce-preview-min-h: clamp(140px, 18vh, 280px);
  min-width: 0;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* ITEM 1 (fit-to-viewport): fill the scroll parent's height and become a
     column that distributes space to the workspace, so the whole editor
     (topbar + preview + transport + timeline + inspector) fits without the
     inspector row hiding behind the footer. */
  flex: 1 1 auto;
  min-height: 0;
}

/* EDITING-state header: one compact row. The sub-tab already names the
   view, so there is no title/blurb here — just the back control (left) and
   the Export cluster (right). ~44px of vertical rhythm keeps the header
   out of the way and hands the space to the preview. On the welcome screen
   both children are hidden, so the row has no height at all. */
.clip-editor-topbar {
  position: relative;
  z-index: 20;
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.clip-editor-topbar > * { pointer-events: auto; }
/* Only reserve the ~44px header row when something is actually in it (the
   editing state). On the welcome screen both children are [hidden], so the
   row collapses to zero and leaves no empty gap above the hero. */
.clip-editor-topbar:has(> :not([hidden])) { min-height: 44px; }

/* "Back to start screen" — a real, readable secondary button (previously a
   muted ghost that read as disabled). Full-opacity border + primary text,
   accent on hover. Only shown while editing (toggled from state). */
.clip-editor-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* ITEM 4 (ergonomics): ≥32px comfortable target, ~13px text. */
  min-height: 32px;
  padding: 6px 14px;
  border-radius: 8px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-primary);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.clip-editor-back-btn[hidden] { display: none !important; }
.clip-editor-back-btn:hover {
  background: var(--bg-hover, #2a2a2a);
  border-color: var(--ce-accent, #ff2ebb);
  color: var(--text-primary);
}
.clip-editor-back-btn:focus-visible { outline: 2px solid var(--ce-accent, #ff2ebb); outline-offset: 2px; }
.clip-editor-back-btn .clip-editor-back-glyph { font-size: 1em; line-height: 1; color: var(--ce-accent, #ff2ebb); }

/* Export cluster: hide the whole cluster (button + reason) when there are
   no clips — the welcome screen shows no disabled/nagging Export control. */
.clip-editor-export-cluster[hidden] { display: none !important; }

.clip-editor-export-cluster {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.clip-editor-export-reason {
  font-size: 0.75rem;
  color: var(--warning, #ffaa00);
  max-width: 22ch;
  text-align: right;
  line-height: 1.3;
}
.clip-editor-export-reason:empty { display: none; }

/* Shared button */
.clip-editor-btn {
  padding: 9px 16px;
  min-height: 38px;
  border-radius: 8px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.1s ease, box-shadow 0.18s ease;
}
.clip-editor-btn:hover { background: var(--bg-hover, #2a2a2a); border-color: var(--ce-accent); }
.clip-editor-btn:active { transform: translateY(1px); }
.clip-editor-btn:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }

.clip-editor-btn.primary {
  background: var(--accent-gradient, linear-gradient(135deg, #ff2ebb, #00b2ff));
  color: #fff;
  border: none;
  box-shadow: 0 2px 12px rgba(255, 46, 187, 0.28);
}
.clip-editor-btn.primary:hover { filter: brightness(1.06); }
.clip-editor-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  filter: none;
  box-shadow: none;
  transform: none;
}

.clip-editor-export-total {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.28);
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
}

/* ===== Welcome / empty state ===== */
.clip-editor-empty[hidden],
.clip-editor-workspace[hidden] { display: none !important; }
/* The empty state fills the workspace height. The whole panel is one
   scrolling column: hero first (top-aligned with generous padding), then
   the recent grid below. We deliberately do NOT use justify-content:center
   here — when the content (hero + grid) exceeds the viewport, centering an
   overflowing flex column pushes the top of the content ABOVE the scroll
   origin, making the hero/hint row unreachable and clipped at the panel top.
   margin-top:auto on the hero would recreate that; instead we top-align and
   let a comfortable top padding give the hero breathing room. */
.clip-editor-empty {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  gap: 0;
  padding: clamp(40px, 6vh, 72px) 20px clamp(32px, 5vh, 56px);
  overflow-y: auto;
}
/* Subtle brand-pink radial glow behind the hero. Non-interactive, very low
   opacity; hidden entirely for reduced-motion users to avoid any shimmer. */
.clip-editor-empty::before {
  content: '';
  position: absolute;
  top: 34%;
  left: 50%;
  width: min(680px, 90%);
  height: 420px;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(255, 46, 187, 0.16), rgba(255, 46, 187, 0.05) 55%, transparent 78%);
  filter: blur(6px);
  pointer-events: none;
  z-index: 0;
}
.clip-editor-hero {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  max-width: 560px;
}
.clip-editor-hero-icon {
  font-size: 3rem;
  line-height: 1;
  filter: drop-shadow(0 4px 18px rgba(255, 46, 187, 0.28));
}
.clip-editor-hero-title {
  margin: 0;
  font-size: clamp(1.6rem, 3.4vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}
.clip-editor-hero-sub {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--text-secondary);
  max-width: 42ch;
}
.clip-editor-hero-cta {
  padding: 13px 30px;
  font-size: 0.95rem;
  border-radius: 10px;
  box-shadow: 0 6px 24px rgba(255, 46, 187, 0.34);
}
.clip-editor-hero-cta:hover { transform: translateY(-1px); }
.clip-editor-hero-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 4px;
}
.clip-editor-hero-library {
  min-height: 44px;
  padding-inline: 22px;
}
.clip-editor-import-status {
  min-height: 1.2em;
  color: var(--text-secondary);
  font-size: 0.78rem;
  line-height: 1.4;
}
.clip-editor-import-status:empty { display: none; }
.clip-editor-import-status[data-tone="error"] { color: var(--error, #ff6b7a); }
.clip-editor-import-status[data-tone="success"] { color: var(--success, #35d07f); }
.clip-editor-import-status[data-tone="working"] { color: var(--accent-secondary, #6fc8ff); }

/* Inline feature hints — one muted line, icon accents, no cards. */
.clip-editor-hero-hints {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 4px;
  margin-top: 10px;
  font-size: 0.82rem;
  color: var(--text-muted, #8a8a95);
}
.clip-editor-hero-hint {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.clip-editor-hero-hint svg {
  width: 15px;
  height: 15px;
  display: block;
  color: var(--ce-accent, #ff2ebb);
}
.clip-editor-hero-hint-sep {
  color: var(--border-light, #3a3a3a);
  user-select: none;
}

/* Constraints line — the single, quiet place the limits are stated in copy.
   Muted and small so it reads as fine print under the CTA, not marketing. */
.clip-editor-hero-limits {
  margin: 6px 0 0;
  font-size: 0.78rem;
  color: var(--text-muted, #8a8a95);
  letter-spacing: 0.01em;
}

/* ===== "Continue where you left off" — grid of previous edits =====
   Lazy-loaded row of the user's clip-editor exports (model === 'clip-editor').
   Loaded only when the empty state is shown; never blocks the editor. */
.clip-editor-recent {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 980px;
  margin: 40px auto 0;
  text-align: left;
}
.clip-editor-recent[hidden] { display: none !important; }
.clip-editor-recent-title {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted, #8a8a95);
  margin: 0 0 14px 2px;
}
/* Uniform-tile grid. align-items:start keeps every tile the same intrinsic
   structure (fixed-ratio thumb + fixed-height caption), so all cards have
   identical heights and rows align. 150px min → 8 items make two tidy rows
   on wide screens within the 980px max-width. */
.clip-editor-recent-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  align-items: start;
  gap: 16px;
}
.clip-editor-recent-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg-secondary, #16161d);
  border: 1px solid var(--border-color, #262630);
  transition: border-color 0.16s ease, transform 0.14s ease, box-shadow 0.16s ease;
}
/* Keyboard focus ring on the tile itself (buttons live inside it). */
.clip-editor-recent-tile:focus-visible {
  outline: 2px solid var(--ce-accent, #ff2ebb);
  outline-offset: 2px;
}
.clip-editor-recent-tile:hover,
.clip-editor-recent-tile:focus-within {
  border-color: var(--ce-accent, #ff2ebb);
  transform: translateY(-2px);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 46, 187, 0.25);
}
/* Fixed portrait aspect (content is predominantly 9:16). ANY source shape —
   portrait, landscape, square — cover-crops into this identical box, so
   every tile's thumbnail is exactly the same size and no letterboxing or
   mid-card badge floating occurs. */
.clip-editor-recent-thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--ed-thumb-bg);
}
.clip-editor-recent-thumb video,
.clip-editor-recent-thumb img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: var(--ed-thumb-bg);
}
/* Small corner "edited" chip. */
.clip-editor-recent-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--ed-chip-bg);
  border: 1px solid rgba(255, 46, 187, 0.5);
  color: #fff;
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  pointer-events: none;
  backdrop-filter: blur(2px);
}
/* Duration badge, bottom-right of the thumbnail. */
.clip-editor-recent-duration {
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 2;
  padding: 2px 7px;
  border-radius: 5px;
  background: var(--ed-chip-strong-bg);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
/* Fixed-height caption row so every card is identical in height regardless
   of date text length; single line, ellipsis on overflow. */
.clip-editor-recent-meta {
  box-sizing: border-box;
  height: 34px;
  display: flex;
  align-items: center;
  padding: 0 11px;
  font-size: 0.75rem;
  color: var(--text-muted, #8a8a95);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Hover/focus action overlay: Continue editing + Use as clip. Confined to
   the thumbnail box (inset:0) so it never overflows the smaller tile. */
.clip-editor-recent-actions {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 8px;
  padding: 12px;
  background: var(--ed-chip-actions-bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.16s ease;
}
.clip-editor-recent-tile:hover .clip-editor-recent-actions,
.clip-editor-recent-tile:focus-within .clip-editor-recent-actions {
  opacity: 1;
  pointer-events: auto;
}
.clip-editor-recent-action {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: var(--bg-secondary, #16161d);
  color: var(--text-primary, #fff);
  font-size: 0.74rem;
  font-weight: 600;
  line-height: 1.2;
  padding: 8px 8px;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background 0.12s ease, border-color 0.12s ease, filter 0.12s ease;
}
.clip-editor-recent-action:hover { background: var(--bg-hover, #2a2a2a); border-color: var(--ce-accent, #ff2ebb); }
.clip-editor-recent-action:focus-visible { outline: 2px solid var(--ce-accent, #ff2ebb); outline-offset: 2px; }
.clip-editor-recent-action.primary {
  background: var(--accent-gradient, linear-gradient(135deg, #ff2ebb, #00b2ff));
  border: none;
  color: #fff;
}
.clip-editor-recent-action.primary:hover { filter: brightness(1.08); }
.clip-editor-recent-empty,
.clip-editor-recent-loading {
  font-size: 0.8rem;
  color: var(--text-secondary);
  padding: 6px 2px;
}
@media (prefers-reduced-motion: reduce) {
  .clip-editor-empty::before { display: none; }
  .clip-editor-hero-cta:hover,
  .clip-editor-recent-tile:hover,
  .clip-editor-recent-tile:focus-within { transform: none; }
  .clip-editor-recent-tile,
  .clip-editor-recent-actions,
  .clip-editor-recent-action,
  .clip-editor-hero-cta { transition: none; }
}

/* Workspace layout */
.clip-editor-workspace {
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* ITEM 1: the workspace absorbs the layout's remaining height and
     distributes it: preview-pane flexes (shrinks), timeline + inspector
     stay at their natural height. */
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
}

/* Phone-only workspace navigator. The three editor surfaces stay mounted;
   these controls only change which surface is visible, preserving media,
   selection, playhead, and transform state across mode switches. */
.clip-editor-phone-modes {
  display: none;
}
.clip-editor-phone-tools,
.clip-editor-phone-sheet-backdrop,
.clip-editor-inspector-close {
  display: none;
}
.clip-editor-inspector-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* Preview pane — the flexible element, but never allowed to collapse.
   On short screens the video sub-tab is the scroll container; preserving a
   useful preview is more important than squeezing the stage to zero. */
.clip-editor-preview-pane {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex: 1 1 auto;
  min-height: 0;
  min-block-size: calc(var(--ce-preview-min-h) + 58px);
}

.clip-editor-stage-slot {
  display: flex;
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 0;
  align-items: center;
  justify-content: center;
}

.clip-editor-stage {
  position: relative;
  /* Photoshop-style transparency canvas. The checker remains visible
     through letterboxing and whenever a transformed clip no longer fills
     the output frame. */
  background-color: #c9c9c9;
  background-image:
    linear-gradient(45deg, #efefef 25%, transparent 25%),
    linear-gradient(-45deg, #efefef 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #efefef 75%),
    linear-gradient(-45deg, transparent 75%, #efefef 75%);
  background-size: 24px 24px;
  background-position: 0 0, 0 12px, 12px -12px, -12px 0;
  border-radius: 12px;
  /* The output frame remains the crop mask, while the Photoshop-style
     transform chrome can extend beyond it. Media clipping lives on the
     inner viewport instead of this outer interaction layer. */
  overflow: visible;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Cap on tall windows, but keep a real preview on short ones. The parent
     panel can scroll; the stage itself should never collapse out of sight. */
  min-height: var(--ce-preview-min-h);
  max-height: min(52vh, 100%);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.clip-editor-media-viewport {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: inherit;
}
/* Keep the Clip Editor on the same standard aspect-ratio set used by the
   rest of the creation UI. Legacy semantic preset names remain styled so
   older saved edit recipes still recreate correctly. */
.clip-editor-stage[data-preset="9:16"],
.clip-editor-stage[data-preset="portrait"]  { aspect-ratio: 9 / 16; width: min(280px, 70vw); }
.clip-editor-stage[data-preset="2:3"]       { aspect-ratio: 2 / 3;  width: min(320px, 74vw); }
.clip-editor-stage[data-preset="3:4"]       { aspect-ratio: 3 / 4;  width: min(360px, 78vw); }
.clip-editor-stage[data-preset="4:5"]       { aspect-ratio: 4 / 5;  width: min(400px, 80vw); }
.clip-editor-stage[data-preset="1:1"],
.clip-editor-stage[data-preset="square"]    { aspect-ratio: 1 / 1;  width: min(420px, 84vw); }
.clip-editor-stage[data-preset="5:4"]       { aspect-ratio: 5 / 4;  width: min(500px, 88vw); }
.clip-editor-stage[data-preset="4:3"]       { aspect-ratio: 4 / 3;  width: min(520px, 90vw); }
.clip-editor-stage[data-preset="3:2"]       { aspect-ratio: 3 / 2;  width: min(560px, 92vw); }
.clip-editor-stage[data-preset="16:9"],
.clip-editor-stage[data-preset="landscape"] { aspect-ratio: 16 / 9; width: min(560px, 92vw); }
.clip-editor-stage video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  background: transparent;
  transform-origin: center center;
  will-change: transform, opacity;
}
.clip-editor-stage.transform-editable { cursor: default; }
.clip-editor-stage.transform-dragging { cursor: grabbing; }

/* Direct-manipulation transform box. Its geometry is calculated from the
   actual object-fit:contain media rectangle, then transformed with the
   exact values written to the EDL. */
.clip-editor-transform-box {
  --ce-transform-handle-inverse: 1;
  position: absolute;
  z-index: 10;
  border: 1px solid rgba(255, 255, 255, 0.98);
  box-shadow: 0 0 0 1px rgba(16, 18, 24, 0.86), 0 0 0 2px rgba(255, 46, 187, 0.28);
  transform-origin: center center;
  pointer-events: none;
  touch-action: none;
  user-select: none;
  will-change: left, top, width, height, transform;
}
.clip-editor-transform-box.active { pointer-events: auto; }
.clip-editor-transform-box[hidden] { display: none !important; }
.clip-editor-transform-move {
  position: absolute;
  inset: 0;
  cursor: move;
  pointer-events: auto;
  background: transparent;
}
.clip-editor-transform-handle {
  position: absolute;
  width: 11px;
  height: 11px;
  padding: 0;
  border: 1.5px solid #fff;
  border-radius: 2px;
  background: #1a1d26;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.9), 0 1px 4px rgba(0, 0, 0, 0.45);
  pointer-events: auto;
  z-index: 2;
}
/* Handles sit on the transformed media perimeter (half inside, half
   outside), matching Photoshop instead of retreating into the crop. */
.clip-editor-transform-handle[data-handle="nw"] { left: 0; top: 0; cursor: nwse-resize; transform-origin: center; transform: translate(-50%, -50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="n"]  { left: 50%; top: 0; cursor: ns-resize; transform-origin: center; transform: translate(-50%, -50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="ne"] { right: 0; top: 0; cursor: nesw-resize; transform-origin: center; transform: translate(50%, -50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="e"]  { right: 0; top: 50%; cursor: ew-resize; transform-origin: center; transform: translate(50%, -50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="se"] { right: 0; bottom: 0; cursor: nwse-resize; transform-origin: center; transform: translate(50%, 50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="s"]  { left: 50%; bottom: 0; cursor: ns-resize; transform-origin: center; transform: translate(-50%, 50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="sw"] { left: 0; bottom: 0; cursor: nesw-resize; transform-origin: center; transform: translate(-50%, 50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-handle[data-handle="w"]  { left: 0; top: 50%; cursor: ew-resize; transform-origin: center; transform: translate(-50%, -50%) scale(var(--ce-transform-handle-inverse)); }
.clip-editor-transform-rotate-stem {
  position: absolute;
  left: 50%;
  top: -30px;
  width: 1px;
  height: 30px;
  background: rgba(255, 255, 255, 0.92);
  transform: translateX(-50%);
  transform-origin: top center;
  pointer-events: none;
}
.clip-editor-transform-rotate {
  position: absolute;
  left: 50%;
  top: -30px;
  width: 15px;
  height: 15px;
  padding: 0;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--ce-accent, #ff2ebb);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.9), 0 2px 7px rgba(0, 0, 0, 0.45);
  cursor: grab;
  pointer-events: auto;
  z-index: 3;
  transform: translate(-50%, -50%) scale(var(--ce-transform-handle-inverse));
}
.clip-editor-transform-origin {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 14px;
  border: 1px solid rgba(255, 255, 255, 0.96);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.82);
  transform: translate(-50%, -50%) scale(var(--ce-transform-handle-inverse));
  pointer-events: none;
  z-index: 3;
}
.clip-editor-transform-origin::before,
.clip-editor-transform-origin::after {
  content: '';
  position: absolute;
  background: rgba(255, 255, 255, 0.96);
}
.clip-editor-transform-origin::before { left: 50%; top: -4px; bottom: -4px; width: 1px; transform: translateX(-50%); }
.clip-editor-transform-origin::after { top: 50%; left: -4px; right: -4px; height: 1px; transform: translateY(-50%); }
.clip-editor-transform-rotate:active { cursor: grabbing; }
.clip-editor-transform-box.is-transforming .clip-editor-transform-handle,
.clip-editor-transform-box.is-transforming .clip-editor-transform-rotate {
  box-shadow: 0 0 0 2px var(--ce-accent, #ff2ebb), 0 2px 8px rgba(0, 0, 0, 0.5);
}
/* ITEM 3: both stage videos occupy the same box; the primary is in normal
   flow, the double-buffer (B) is stacked over it and never eats pointer
   events. Opacity is driven from JS during a transition. */
.clip-editor-stage-video-b {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  z-index: 1;
  background: transparent;
}

@media (max-height: 700px) {
  .clip-editor-layout {
    --ce-preview-min-h: 140px;
    gap: 8px;
    padding-top: 8px;
    padding-bottom: 8px;
  }
  .clip-editor-preview-pane { gap: 6px; }
  .clip-editor-stage { max-height: min(42vh, 100%); }
  .clip-editor-transport { padding: 6px 10px; }
}

@media (max-width: 700px) {
  .clip-editor-preview-pane { justify-content: flex-start; }
  .clip-editor-stage[data-preset="9:16"],
  .clip-editor-stage[data-preset="portrait"]  { width: min(280px, 70vw, 23.625vh); }
  .clip-editor-stage[data-preset="2:3"]       { width: min(320px, 74vw, 28vh); }
  .clip-editor-stage[data-preset="3:4"]       { width: min(360px, 78vw, 31.5vh); }
  .clip-editor-stage[data-preset="4:5"]       { width: min(400px, 80vw, 33.6vh); }
  .clip-editor-stage[data-preset="1:1"],
  .clip-editor-stage[data-preset="square"]    { width: min(420px, 84vw, 42vh); }
  .clip-editor-stage[data-preset="5:4"]       { width: min(500px, 88vw, 52.5vh); }
  .clip-editor-stage[data-preset="4:3"]       { width: min(520px, 90vw, 56vh); }
  .clip-editor-stage[data-preset="3:2"]       { width: min(560px, 92vw, 63vh); }
  .clip-editor-stage[data-preset="16:9"],
  .clip-editor-stage[data-preset="landscape"] { width: min(560px, 92vw, 74.667vh); }
}

@media (max-width: 767px) {
  #editVideoSection {
    height: var(--vix-content-block-size);
    max-height: var(--vix-content-block-size);
    flex: 1 1 var(--vix-content-block-size);
    padding-bottom: 0;
    scroll-padding-bottom: 0;
    overflow: hidden;
  }

  .clip-editor-layout {
    --ce-preview-min-h: 100px;
    height: 100%;
    max-height: 100%;
    padding: 8px 12px max(8px, env(safe-area-inset-bottom));
    gap: 8px;
    overflow: hidden;
  }

  .clip-editor-workspace {
    position: relative;
    display: grid;
    /* Preview owns all remaining height. Timeline and tools consume only
       their real content height, so an empty audio lane can never create
       a large black band that steals space from the canvas. Preserve a
       compact minimum canvas on short phones so wrapped transport controls
       cannot collapse the preview row to zero. */
    grid-template-rows: minmax(min(var(--ce-preview-min-h), 24vh), 1fr) auto auto;
    gap: 8px;
    overflow: hidden;
  }

  .clip-editor-phone-modes {
    display: none !important;
  }

  .clip-editor-workspace > .clip-editor-preview-pane,
  .clip-editor-workspace > .clip-editor-timeline {
    display: flex !important;
  }

  .clip-editor-workspace > .clip-editor-preview-pane {
    grid-row: 1;
  }

  .clip-editor-workspace > .clip-editor-timeline {
    grid-row: 2;
    min-height: 0;
    flex-direction: column;
  }

  .clip-editor-phone-tools {
    grid-row: 3;
    display: flex;
    align-items: stretch;
    gap: 6px;
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    padding: 2px 2px max(2px, env(safe-area-inset-bottom));
  }
  .clip-editor-phone-tools::-webkit-scrollbar { display: none; }

  .clip-editor-phone-tool {
    display: inline-flex;
    flex: 1 0 64px;
    min-width: 64px;
    min-height: 48px;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 2px;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font: inherit;
    font-size: 1rem;
    cursor: pointer;
  }
  .clip-editor-phone-tool span {
    font-size: 0.68rem;
    font-weight: 700;
  }
  .clip-editor-phone-tool:focus-visible {
    outline: 2px solid var(--ce-accent);
    outline-offset: -2px;
  }

  .clip-editor-phone-sheet-backdrop {
    position: absolute;
    inset: 0;
    z-index: 70;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: rgba(0, 0, 0, 0.54);
    cursor: pointer;
  }
  .clip-editor-phone-sheet-backdrop:not([hidden]) { display: block; }

  .clip-editor-workspace > .clip-editor-inspector {
    display: none !important;
  }
  .clip-editor-workspace > .clip-editor-inspector.phone-sheet-open:not([hidden]) {
    position: absolute;
    inset: auto 0 0;
    z-index: 71;
    display: block !important;
    max-height: min(68%, calc(100% - 32px));
    overflow-y: auto;
    overscroll-behavior: contain;
    border-radius: 18px 18px 0 0;
    padding-bottom: max(16px, env(safe-area-inset-bottom));
    box-shadow: 0 -18px 48px rgba(0, 0, 0, 0.5);
  }
  .clip-editor-inspector-close {
    display: inline-flex;
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 1.4rem;
    cursor: pointer;
  }

  .clip-editor-preview-pane {
    display: grid !important;
    grid-template-rows: minmax(0, 1fr) auto;
    align-items: stretch;
    justify-items: center;
    justify-content: stretch;
    min-block-size: 0;
    overflow: hidden;
  }

  .clip-editor-stage-slot {
    container-type: size;
    align-self: stretch;
    overflow: visible;
  }

  /* Size the canvas from its actual allocated panel, not viewport height.
     This keeps every aspect ratio inside both portrait and landscape phone
     layouts while allowing the canonical shell viewport variable to own
     browser-chrome and safe-area changes. */
  .clip-editor-stage {
    min-height: min(var(--ce-preview-min-h), 24vh);
    max-height: none;
  }
  .clip-editor-stage[data-preset="9:16"],
  .clip-editor-stage[data-preset="portrait"]  { width: min(90cqw, calc(100cqh * 9 / 16)) !important; }
  .clip-editor-stage[data-preset="2:3"]       { width: min(90cqw, calc(100cqh * 2 / 3)) !important; }
  .clip-editor-stage[data-preset="3:4"]       { width: min(90cqw, calc(100cqh * 3 / 4)) !important; }
  .clip-editor-stage[data-preset="4:5"]       { width: min(90cqw, calc(100cqh * 4 / 5)) !important; }
  .clip-editor-stage[data-preset="1:1"],
  .clip-editor-stage[data-preset="square"]    { width: min(90cqw, 100cqh) !important; }
  .clip-editor-stage[data-preset="5:4"]       { width: min(90cqw, calc(100cqh * 5 / 4)) !important; }
  .clip-editor-stage[data-preset="4:3"]       { width: min(90cqw, calc(100cqh * 4 / 3)) !important; }
  .clip-editor-stage[data-preset="3:2"]       { width: min(90cqw, calc(100cqh * 3 / 2)) !important; }
  .clip-editor-stage[data-preset="16:9"],
  .clip-editor-stage[data-preset="landscape"] { width: min(90cqw, calc(100cqh * 16 / 9)) !important; }

  .clip-editor-transport {
    flex: 0 0 auto;
    width: min(100%, 560px);
  }

  .clip-editor-timeline-scroll {
    flex: 0 0 auto;
    min-height: 0;
    overflow-x: auto;
    overflow-y: hidden;
  }

  .clip-editor-timeline {
    padding: 6px 8px 8px;
    border-radius: 10px;
  }
  .clip-editor-timeline-head { margin-bottom: 2px; }
  .clip-editor-timeline-head :is(.clip-editor-zoom-label, .clip-editor-zoom-slider) { display: none; }

  .clip-editor-inspector-fields {
    align-items: stretch;
    flex-direction: column;
    gap: 14px;
    overflow-x: hidden;
    overflow-y: visible;
  }

  .clip-editor-inspector-fields > *,
  .clip-editor-transform-group {
    width: 100%;
  }

  .clip-editor-transform-group {
    align-items: stretch;
    flex-direction: column;
    padding: 14px 0 0;
    border-left: 0;
    border-top: 1px solid var(--border-light, #3a3a3a);
  }

  .clip-editor-transform-field,
  .clip-editor-transform-field input[type="range"] {
    width: 100%;
  }
}

.clip-editor-transport {
  position: relative;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 640px;
  padding: 8px 12px;
  background: var(--bg-tertiary, #1a1a1a);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  flex-wrap: wrap;
}
.clip-editor-play-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: none;
  background: var(--ce-accent);
  color: #fff;
  cursor: pointer;
  font-size: 0.95rem;
  transition: transform 0.1s ease, filter 0.18s ease;
}
.clip-editor-play-btn:hover { filter: brightness(1.1); }
.clip-editor-play-btn:active { transform: scale(0.94); }
.clip-editor-play-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.clip-editor-play-icon { line-height: 1; transform: translateX(1px); }
.clip-editor-play-btn.playing .clip-editor-play-icon { transform: none; }

.clip-editor-time {
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
  color: var(--text-primary);
  letter-spacing: 0.02em;
}
.clip-editor-approx-hint {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted, #666);
  border: 1px solid var(--border-light, #3a3a3a);
  border-radius: 6px;
  padding: 1px 6px;
  cursor: help;
}
.clip-editor-transport-spacer { flex: 1 1 auto; }
.clip-editor-preset-control {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  color: var(--text-secondary);
}
.clip-editor-preset-control select,
.clip-editor-field select,
.clip-editor-field input[type="number"] {
  background: var(--bg-input, #0a0a0a);
  color: var(--text-primary);
  border: 1px solid var(--border-light, #3a3a3a);
  border-radius: 6px;
  padding: 6px 8px;
  min-height: 34px;
  font-size: 0.85rem;
}
.clip-editor-preset-control select:focus-visible,
.clip-editor-field select:focus-visible,
.clip-editor-field input:focus-visible {
  outline: 2px solid var(--ce-accent);
  outline-offset: 1px;
}

/* Timeline */
.clip-editor-timeline {
  position: relative; /* ITEM 4: anchor for the transition popover */
  z-index: 20;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  padding: 10px 12px 14px;
  /* ITEM 1: fixed-height band — never shrinks or grows; the preview pane
     is the elastic element instead. */
  flex: 0 0 auto;
  /* Zoomed content must scroll inside .clip-editor-timeline-scroll, never
     widen this band (flex min-width:auto lets max-content leak out,
     pushing the zoom controls off-page and shifting the preview). */
  min-width: 0;
  max-width: 100%;
}
/* ITEM 2: zoom toolbar pinned to the timeline's top-right corner.
   ITEM 8: a persistent "+ Add" button sits on the LEFT so adding a clip is
   always reachable even when the trailing add-block is scrolled off-screen. */
.clip-editor-timeline-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.clip-editor-add-actions {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}
/* ITEM 8: persistent header add button — comfortable 32px target. */
.clip-editor-head-add {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 32px;
  padding: 6px 12px;
  border-radius: 8px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 600;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.clip-editor-head-add:hover { border-color: var(--ce-accent); color: var(--ce-accent); background: var(--bg-hover, #2a2a2a); }
.clip-editor-head-add:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }
.clip-editor-head-add:disabled { opacity: 0.45; cursor: not-allowed; }
.clip-editor-head-add-glyph { font-size: 1em; line-height: 1; }
.clip-editor-workspace-import-status {
  margin: -1px 0 6px;
  padding-inline: 2px;
}
.clip-editor-zoom {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.clip-editor-zoom-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted, #666);
}
.clip-editor-zoom-btn {
  /* ITEM 3 (ergonomics): 32×32 comfortable pointer target. */
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 1.05rem;
  line-height: 1;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.clip-editor-zoom-btn:hover:not(:disabled) { border-color: var(--ce-accent); background: var(--bg-hover, #2a2a2a); }
.clip-editor-zoom-btn:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }
.clip-editor-zoom-btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* ITEM 3/5 (ergonomics): shared range-input styling — 6px track, 16px accent
   thumb with a hover ring, and vertical padding that lifts the interactive
   height to ≥28px. Applied to the zoom slider + inspector/transport sliders. */
.clip-editor-zoom-slider,
.clip-editor-range {
  -webkit-appearance: none;
  appearance: none;
  width: 96px;
  /* content-box so the 6px track height + 2×11px padding sum to a 28px
     interactive box (border-box would fold the padding into the 6px). */
  box-sizing: content-box;
  height: 6px;
  padding: 11px 0; /* 6px track + 2×11px → 28px interactive height */
  background: transparent;
  cursor: pointer;
}
.clip-editor-zoom-slider::-webkit-slider-runnable-track,
.clip-editor-range::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: var(--border-light, #3a3a3a);
}
.clip-editor-zoom-slider::-moz-range-track,
.clip-editor-range::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: var(--border-light, #3a3a3a);
}
.clip-editor-zoom-slider::-webkit-slider-thumb,
.clip-editor-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px; /* centre the 16px thumb on the 6px track */
  border-radius: 50%;
  background: var(--ce-accent);
  border: 2px solid var(--bg-secondary, #151515);
  box-shadow: 0 0 0 0 var(--ce-accent-soft);
  transition: box-shadow 0.15s ease;
}
.clip-editor-zoom-slider::-moz-range-thumb,
.clip-editor-range::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--ce-accent);
  border: 2px solid var(--bg-secondary, #151515);
  box-shadow: 0 0 0 0 var(--ce-accent-soft);
  transition: box-shadow 0.15s ease;
}
.clip-editor-zoom-slider:hover::-webkit-slider-thumb,
.clip-editor-range:hover::-webkit-slider-thumb { box-shadow: 0 0 0 5px var(--ce-accent-soft); }
.clip-editor-zoom-slider:hover::-moz-range-thumb,
.clip-editor-range:hover::-moz-range-thumb { box-shadow: 0 0 0 5px var(--ce-accent-soft); }
.clip-editor-zoom-slider:focus-visible,
.clip-editor-range:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }
.clip-editor-zoom-slider:focus-visible::-webkit-slider-thumb,
.clip-editor-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 5px var(--ce-accent-soft); }
.clip-editor-zoom-slider:focus-visible::-moz-range-thumb,
.clip-editor-range:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 5px var(--ce-accent-soft); }
.clip-editor-timeline-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  padding-bottom: 4px;
}
.clip-editor-timeline-inner {
  position: relative;
  min-width: 100%;
  width: max-content;
  user-select: none;
  touch-action: pan-y;
}

/* Ruler */
.clip-editor-ruler {
  position: relative;
  height: var(--ce-ruler-h);
  cursor: pointer;
  border-bottom: 1px solid var(--border-color);
  margin-bottom: 8px;
}
.clip-editor-tick {
  position: absolute;
  top: 0;
  bottom: 0;
  /* ITEM 6: the tick line spans the full ruler height while its label is
     vertically centred within the taller ruler band. */
  display: flex;
  align-items: center;
  border-left: 1px solid var(--border-light, #3a3a3a);
  padding-left: 3px;
  font-size: 0.62rem;
  color: var(--text-muted, #666);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.clip-editor-tick.minor { opacity: 0.5; }
.clip-editor-tick.minor::after { content: ''; }

/* Video track */
/* ISSUE 2 (one mapping to rule them all): blocks are absolutely positioned
   from the output-time segment table (left = outStart*pps, width =
   outDur*pps) instead of laid out adjacent in flex flow. A flex row with a
   gap made every block drift right of the ruler ticks, and — worse — kept
   full uncompressed widths while the ruler/playhead/total used COMPRESSED
   time, so a transition's overlap misaligned the playhead from the block
   edges by the overlap sum. Absolute positioning makes a junction overlap
   render as an actual visual overlap of the two blocks, and pins the last
   block's right edge at exactly total*pps. */
.clip-editor-track {
  position: relative;
  height: var(--ce-track-h);
}
.clip-editor-block {
  position: absolute;
  top: 0;
  bottom: 0;
  min-width: 44px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--ed-block-bg) center/cover no-repeat;
  border: 2px solid transparent;
  cursor: grab;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* A selected/dragging block lifts above its neighbours so an overlapping
   junction still shows the block the user is working with on top. */
.clip-editor-block.selected { z-index: 4; }
.clip-editor-block::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.05) 0%, rgba(0,0,0,0.55) 100%);
  pointer-events: none;
}
.clip-editor-block.selected {
  border-color: var(--ce-accent);
  box-shadow: 0 0 0 2px var(--ce-accent-soft), 0 4px 14px rgba(0,0,0,0.4);
}
.clip-editor-block.dragging {
  cursor: grabbing;
  opacity: 0.85;
  z-index: 6;
}
.clip-editor-block-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  background: var(--ed-block-bg);
}
/* FILMSTRIP: a row of frame thumbnails sampled across the clip's trimmed
   source range. Sits directly above the single first-frame <video> fallback
   (z 0) but below the index/badges/handles/junctions (z 3-6) so all the
   affordances stay legible. Tiles are absolutely positioned by PERCENT of
   the block so a zoom (which only changes block width) scales them for free;
   we only re-tile when the tile-duration ladder bucket changes. */
.clip-editor-filmstrip {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
}
.clip-editor-film-tile {
  position: absolute;
  top: 0;
  bottom: 0;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  /* Placeholder look before a frame arrives: a dim block-colored panel,
     never a broken-image glyph. Filled tiles set their own background. */
  background: var(--ed-film-bg);
  display: block;
}
.clip-editor-film-tile.is-placeholder {
  background: repeating-linear-gradient(
    90deg,
    var(--ed-film-stripe-a) 0, var(--ed-film-stripe-a) 6px,
    var(--ed-film-stripe-b) 6px, var(--ed-film-stripe-b) 12px);
  opacity: 0.7;
}
.clip-editor-block-meta {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  padding: 3px 6px;
  pointer-events: none;
}
.clip-editor-block-dur {
  font-size: 0.68rem;
  color: #fff;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px rgba(0,0,0,0.9);
}
.clip-editor-block-speed {
  font-size: 0.62rem;
  font-weight: 700;
  color: #fff;
  background: var(--ce-accent);
  border-radius: 5px;
  padding: 0 5px;
  line-height: 1.5;
}
.clip-editor-block-index {
  position: absolute;
  top: 4px;
  left: 5px;
  font-size: 0.6rem;
  color: rgba(255,255,255,0.85);
  background: var(--ed-badge-bg);
  border-radius: 4px;
  padding: 0 5px;
  pointer-events: none;
}
/* FEATURE 1: muted badge on a clip whose own audio volume is 0. */
.clip-editor-block-muted {
  position: absolute;
  top: 4px;
  right: 5px;
  font-size: 0.72rem;
  line-height: 1;
  background: var(--ed-badge-strong-bg);
  border-radius: 4px;
  padding: 1px 3px;
  pointer-events: none;
  z-index: 4;
}

/* REWRITE (Item 3): loading / broken status affordances on a timeline block */
.clip-editor-block.is-pending { opacity: 0.75; }
.clip-editor-block.is-broken { outline: 1px solid var(--error, #ff4d4f); outline-offset: -1px; }
.clip-editor-block-status {
  position: absolute;
  top: 4px;
  left: 22px;
  font-size: 0.66rem;
  line-height: 1;
  background: rgba(0,0,0,0.62);
  border-radius: 4px;
  padding: 2px 4px;
  pointer-events: none;
  z-index: 5;
  white-space: nowrap;
}
.clip-editor-block-status.broken { background: rgba(255,77,79,0.85); color: #fff; }
.clip-editor-block-broken-actions {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: rgba(0,0,0,0.55);
  z-index: 6;
}
.clip-editor-block-retry,
.clip-editor-block-remove {
  font-size: 0.68rem;
  padding: 3px 8px;
  border-radius: 5px;
  border: 1px solid rgba(255,255,255,0.35);
  background: rgba(0,0,0,0.5);
  color: #fff;
  cursor: pointer;
}
.clip-editor-block-retry:hover { border-color: var(--ce-accent); color: var(--ce-accent); }
.clip-editor-block-remove:hover { border-color: var(--error, #ff4d4f); color: var(--error, #ff4d4f); }

/* Trim handles */
.clip-editor-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  /* ITEM 2 (ergonomics): the handle NODE is 24px wide — the full effective
     pointer target — so the drag grabs even when the pointer is several px
     off the block edge. The block clips overflow, so the hit area lives
     INSIDE the block (extending inward) rather than as an outside overhang.
     The VISIBLE bracket is a slim 14px-wide accent painted only on the outer
     edge via ::before, leaving the inner 10px transparent but still hittable.
     The two handles sit at opposite ends so they never overlap; toward the
     junction the dot's higher z-index (7 > 3) wins the shared hit. */
  width: 24px;
  display: none;
  align-items: center;
  justify-content: center;
  background: transparent;
  cursor: ew-resize;
  z-index: 3;
  touch-action: none;
}
/* Visible accent bracket: 14px slab pinned to the handle's outer edge. */
.clip-editor-handle::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 14px;
  background: var(--ce-accent);
}
.clip-editor-handle.left::before  { left: 0;  border-radius: 6px 0 0 6px; }
.clip-editor-handle.right::before { right: 0; border-radius: 0 6px 6px 0; }
.clip-editor-handle::after {
  content: '';
  position: relative;
  width: 2px;
  height: 40%;
  background: rgba(255,255,255,0.85);
  border-radius: 2px;
  z-index: 1;
}
/* Centre the white grip inside the VISIBLE 14px bracket, not the 24px node. */
.clip-editor-handle.left  { left: 0;  justify-content: flex-start; padding-left: 6px; }
.clip-editor-handle.right { right: 0; justify-content: flex-end;   padding-right: 6px; }
.clip-editor-block.selected .clip-editor-handle {
  display: flex;
  /* ITEM 2: the SELECTED block's handles ride above the junction's hit shield
     (z 7) so, at tight zooms where a min-width block sits under the junction,
     the handles the user is actively trimming stay grabbable. The junction
     core is still reachable everywhere the two thin brackets are not. */
  z-index: 8;
}

.clip-editor-trim-tip {
  position: absolute;
  top: -26px;
  transform: translateX(-50%);
  background: #000;
  color: #fff;
  font-size: 0.68rem;
  padding: 2px 6px;
  border-radius: 5px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 8;
  display: none;
}

/* Add-clip ghost block — ISSUE 2: absolutely placed just after the end of
   the sequence (left = total*pps + gap), so it rides the compressed timeline
   rather than flex flow. */
.clip-editor-add-block {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 60px;
  border: 2px dashed var(--border-light, #3a3a3a);
  border-radius: 8px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 1.5rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.clip-editor-add-block:hover {
  border-color: var(--ce-accent);
  color: var(--ce-accent);
  background: var(--ce-accent-soft);
}
.clip-editor-add-block:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }

/* Audio lane */
.clip-editor-audio-lane {
  position: relative;
  margin-top: 8px;
  height: var(--ce-audio-h);
}
.clip-editor-audio-add {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 100%;
  padding: 0 12px;
  border: 1.5px dashed var(--border-light, #3a3a3a);
  border-radius: 8px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.8rem;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.clip-editor-audio-add:hover { border-color: var(--accent-secondary, #00b2ff); color: var(--accent-secondary, #00b2ff); }
.clip-editor-audio-add:focus-visible { outline: 2px solid var(--accent-secondary, #00b2ff); outline-offset: 2px; }

.clip-editor-audio-strip {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 100%;
  padding: 0 10px;
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(0,178,255,0.28), rgba(0,178,255,0.16));
  border: 1px solid rgba(0,178,255,0.5);
  color: #fff;
  overflow: hidden;
  min-width: 120px;
}
.clip-editor-audio-icon { font-size: 0.9rem; }
.clip-editor-audio-name {
  font-size: 0.76rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
}
/* Audio-lane volume: shares the .clip-editor-range 6px/16px treatment (added
   on the element) but keeps its narrower 74px width + blue accent thumb. */
.clip-editor-audio-vol { width: 74px; flex: 0 0 auto; }
.clip-editor-audio-vol.clip-editor-range::-webkit-slider-thumb { background: var(--accent-secondary, #00b2ff); }
.clip-editor-audio-vol.clip-editor-range::-moz-range-thumb { background: var(--accent-secondary, #00b2ff); }
.clip-editor-audio-remove {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,0.35);
  color: #fff;
  cursor: pointer;
  font-size: 0.85rem;
  line-height: 1;
}
.clip-editor-audio-remove:hover { background: rgba(0,0,0,0.6); }
.clip-editor-audio-remove:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }
.clip-editor-audio-status {
  font-size: 0.75rem;
  color: var(--text-secondary);
  margin-top: 4px;
}
.clip-editor-audio-status:empty { display: none; }

/* FEATURE 2: audio-strip trim handles (reuse the clip-handle look/feel). */
.clip-editor-audio-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 12px;
  background: var(--accent-secondary, #00b2ff);
  cursor: ew-resize;
  z-index: 3;
  touch-action: none;
  opacity: 0.85;
}
.clip-editor-audio-handle.left  { left: 0;  border-radius: 8px 0 0 8px; }
.clip-editor-audio-handle.right { right: 0; border-radius: 0 8px 8px 0; }
.clip-editor-audio-handle:hover { opacity: 1; }
.clip-editor-audio-trim-fields {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 6px;
}

/* FEATURE 1: per-clip volume row + mute toggle in the inspector. */
.clip-editor-field-volume { min-width: 160px; }
.clip-editor-volume-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* ITEM 5: the inspector volume slider uses .clip-editor-range for the shared
   6px-track / 16px-thumb / ≥28px-hit treatment; only its flex sizing lives
   here so the width still fills the row. */
.clip-editor-volume-row input[type="range"] {
  flex: 1 1 auto;
  min-width: 90px;
  width: auto;
}
.clip-editor-mute-btn {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border: 1px solid var(--border-light, #3a3a3a);
  border-radius: 6px;
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.9rem;
  line-height: 1;
}
.clip-editor-mute-btn.muted { border-color: var(--warning, #ffaa00); }
.clip-editor-mute-btn:focus-visible { outline: 2px solid var(--ce-accent, #ff2ebb); outline-offset: 1px; }

/* Playhead */
.clip-editor-playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--ce-accent);
  pointer-events: none;
  z-index: 5;
}
.clip-editor-playhead::before {
  content: '';
  position: absolute;
  top: -3px;
  left: 50%;
  transform: translateX(-50%);
  width: 10px;
  height: 10px;
  background: var(--ce-accent);
  border-radius: 50%;
}

/* ITEM 4: transition junction between adjacent clips (CapCut-style). */
/* ISSUE 2: the junction badge is absolutely centered over the cut between
   two blocks (positioned in JS at the boundary output time) and sits above
   the blocks so it stays visible even when a transition makes the two blocks
   overlap. transform:translate(-50%,-50%) centers it on its computed left. */
.clip-editor-junction {
  position: absolute;
  /* Ride the TOP edge of the seam, not the vertical center: the trim
     brackets own the middle band of the block edges, and a centered dot
     sat exactly on top of them (verified by staging click-probes). Half
     above the track, half overlapping — CapCut-style transition marker. */
  top: 0;
  transform: translate(-50%, -55%);
  /* ITEM 1 (ergonomics): ~26px visual dot, but a transparent ::before
     extends the EFFECTIVE pointer target so near-misses still register. */
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.72rem;
  line-height: 1;
  z-index: 7;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
}
/* Invisible hit-area extender: 36×36 min target centred on the dot (26px dot
   + 2×5px). It is transparent and inherits the button's pointer behaviour, so
   a click a few px outside the visible circle still activates the junction.
   Capped at 6px so the effective target clears 36px while, at tight zooms,
   each adjacent block's trim handle still peeks past the extender and stays
   independently grabbable on its outer edge. */
.clip-editor-junction::before {
  content: '';
  position: absolute;
  /* Generous hit zone vertically (empty track space above/below), but
     only +2px horizontally — the trim handles live immediately left and
     right, and a wider extender steals clicks aimed at their brackets. */
  inset: -7px -2px;
  border-radius: 14px;
}
.clip-editor-junction:hover { border-color: var(--ce-accent); color: var(--ce-accent); transform: translate(-50%, -55%) scale(1.1); }
.clip-editor-junction:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }
.clip-editor-junction.active {
  background: var(--ce-accent);
  border-color: var(--ce-accent);
  color: #fff;
  box-shadow: 0 0 0 2px var(--ce-accent-soft);
}
/* Popover for choosing transition type + duration. */
.clip-editor-transition-popover {
  position: absolute;
  z-index: 40;
  min-width: 176px;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-secondary, #151515);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.clip-editor-transition-popover[hidden] { display: none; }
.clip-editor-transition-popover-title {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-secondary);
  margin-bottom: 2px;
}
.clip-editor-transition-opt {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.82rem;
  text-align: left;
  width: 100%;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.clip-editor-transition-opt:hover { background: var(--bg-hover, #2a2a2a); }
.clip-editor-transition-opt.selected { border-color: var(--ce-accent); background: var(--ce-accent-soft); }
.clip-editor-transition-opt:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 1px; }
.clip-editor-transition-dur {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: 0.78rem;
  color: var(--text-secondary);
}
.clip-editor-transition-dur select {
  flex: 1 1 auto;
  background: var(--bg-input, #0a0a0a);
  color: var(--text-primary);
  border: 1px solid var(--border-light, #3a3a3a);
  border-radius: 6px;
  padding: 5px 7px;
  font-size: 0.82rem;
}
.clip-editor-transition-dur select:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 1px; }

/* ITEM 3: split button in the transport bar. */
.clip-editor-split-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 7px 12px;
  min-height: 34px;
  border-radius: 8px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-tertiary, #1a1a1a);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 600;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.clip-editor-split-btn:hover:not(:disabled) { border-color: var(--ce-accent); background: var(--bg-hover, #2a2a2a); }
.clip-editor-split-btn:active:not(:disabled) { transform: translateY(1px); }
.clip-editor-split-btn:focus-visible { outline: 2px solid var(--ce-accent); outline-offset: 2px; }
.clip-editor-split-btn:disabled { opacity: 0.45; cursor: not-allowed; }
/* ITEM 9: subtle keyboard-shortcut chip inside labelled buttons. */
.clip-editor-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 15px;
  height: 15px;
  padding: 0 4px;
  border-radius: 4px;
  border: 1px solid var(--border-light, #3a3a3a);
  background: var(--bg-secondary, #151515);
  color: var(--text-muted, #999);
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1;
  font-family: inherit;
}

/* Inspector */
.clip-editor-inspector {
  position: relative;
  z-index: 20;
  background: var(--bg-tertiary, #1a1a1a);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  padding: 12px 14px;
  /* ITEM 1: fixed-height band, always visible when a clip is selected. */
  flex: 0 0 auto;
}
.clip-editor-inspector-title {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  margin-bottom: 10px;
}
.clip-editor-inspector-fields {
  display: flex;
  align-items: center;
  gap: 18px;
  /* Selected-clip inspector sits on one line; if the window is genuinely
     too narrow the row scrolls horizontally rather than wrapping. */
  flex-wrap: nowrap;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding-bottom: 2px;
}
.clip-editor-inspector-fields > * { flex: 0 0 auto; }
.clip-editor-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--text-secondary);
}
.clip-editor-field input[type="number"] { width: 74px; }
.clip-editor-field-unit { color: var(--text-muted, #666); }
.clip-editor-transform-group {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding-left: 16px;
  border-left: 1px solid var(--border-light, #3a3a3a);
}
.clip-editor-transform-heading {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  min-width: 72px;
  color: var(--text-primary);
  font-size: 0.8rem;
  font-weight: 700;
}
.clip-editor-transform-heading small {
  color: var(--text-muted, #777);
  font-size: 0.65rem;
  font-weight: 500;
  white-space: nowrap;
}
.clip-editor-transform-field {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  min-width: 112px;
  color: var(--text-secondary);
  font-size: 0.72rem;
}
.clip-editor-transform-field > span {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  white-space: nowrap;
}
.clip-editor-transform-field output {
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.clip-editor-transform-field input[type="range"] {
  width: 112px;
  accent-color: var(--ce-accent);
}
.clip-editor-transform-reset {
  min-height: 32px;
  padding: 5px 10px;
  border: 1px solid var(--border-light, #3a3a3a);
  border-radius: 7px;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.75rem;
}
.clip-editor-transform-reset:hover { border-color: var(--ce-accent); color: var(--text-primary); }
.clip-editor-delete-btn {
  margin-left: auto;
  min-height: 34px;
  padding: 6px 14px;
  border-radius: 8px;
  border: 1px solid var(--error, #ff4444);
  background: transparent;
  color: var(--error, #ff4444);
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 600;
  transition: background 0.15s ease, color 0.15s ease;
}
.clip-editor-delete-btn:hover { background: var(--error, #ff4444); color: #fff; }
.clip-editor-delete-btn:focus-visible { outline: 2px solid var(--error, #ff4444); outline-offset: 2px; }

.clip-editor-export-status {
  font-size: 0.85rem;
  color: var(--text-secondary);
}
.clip-editor-export-status:empty { display: none; }

/* ITEM 1: export progress overlay pinned to the bottom of the preview
   stage — a slim bar + status line, unmistakably "working". */
.clip-editor-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 10px 14px 12px;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.72) 42%);
  display: flex;
  flex-direction: column;
  gap: 7px;
  z-index: 6;
  pointer-events: none;
}
.clip-editor-progress[hidden] { display: none; }
.clip-editor-progress-status {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,0.8);
}
.clip-editor-progress-spinner {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.35);
  border-top-color: #fff;
  animation: clip-editor-spin 0.7s linear infinite;
}
.clip-editor-progress-pct {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}
.clip-editor-progress-track {
  height: 5px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  overflow: hidden;
}
.clip-editor-progress-fill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--accent-gradient, linear-gradient(90deg, #ff2ebb, #00b2ff));
  transition: width 0.35s ease;
}

@keyframes clip-editor-spin { to { transform: rotate(360deg); } }

/* Button spinner state while exporting. */
.clip-editor-btn-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 6px;
  vertical-align: -2px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.4);
  border-top-color: #fff;
  animation: clip-editor-spin 0.7s linear infinite;
}

/* ITEM 1: block editing on the timeline while an export runs. */
.clip-editor-timeline.is-exporting,
.clip-editor-inspector.is-exporting {
  pointer-events: none;
  opacity: 0.5;
  filter: grayscale(0.25);
  transition: opacity 0.2s ease;
}

/* ITEM 2: finished-render overlay shown IN the preview stage. */
.clip-editor-result-overlay {
  position: absolute;
  inset: 0;
  z-index: 7;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  padding: 16px;
  background: linear-gradient(180deg, rgba(0,0,0,0) 45%, rgba(0,0,0,0.62) 100%);
}
.clip-editor-result-overlay[hidden] { display: none; }
.clip-editor-saved-chip {
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(0, 200, 120, 0.16);
  border: 1px solid rgba(0, 255, 136, 0.5);
  color: var(--success, #00ff88);
  font-size: 0.82rem;
  font-weight: 600;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
  backdrop-filter: blur(4px);
}
.clip-editor-result-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

@media (prefers-reduced-motion: reduce) {
  .clip-editor-btn,
  .clip-editor-play-btn,
  .clip-editor-block,
  .clip-editor-add-block,
  .clip-editor-audio-add,
  .clip-editor-delete-btn { transition: none; }
  .clip-editor-progress-spinner,
  .clip-editor-btn-spinner { animation-duration: 1.4s; }
  .clip-editor-progress-fill { transition: none; }
}

.clip-editor-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(3px);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.clip-editor-modal-content {
  background: var(--bg-tertiary, #1a1a1a);
  border: 1px solid var(--border-color);
  border-radius: 14px;
  padding: 18px;
  max-width: 680px;
  width: 100%;
  max-height: 82vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0,0,0,0.55);
}

.clip-editor-modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 14px;
}
.clip-editor-modal-header h3 { margin: 0; font-size: 1.05rem; }

.clip-editor-modal-close {
  background: transparent;
  border: none;
  color: var(--text-secondary);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  transition: background 0.15s ease, color 0.15s ease;
}
.clip-editor-modal-close:hover { background: var(--bg-hover, #2a2a2a); color: var(--text-primary); }
.clip-editor-modal-close:focus-visible { outline: 2px solid var(--accent-primary, #ff2ebb); outline-offset: 2px; }

.clip-editor-library-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
  gap: 12px;
}

.clip-editor-library-item {
  cursor: pointer;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
  border: 2px solid transparent;
  transition: border-color 0.15s ease, transform 0.12s ease;
}
.clip-editor-library-item:hover { border-color: var(--accent-primary, #ff2ebb); transform: translateY(-2px); }
.clip-editor-library-item:focus-visible { outline: 2px solid var(--accent-primary, #ff2ebb); outline-offset: 2px; }

.clip-editor-library-item {
  position: relative;
}
.clip-editor-library-item video {
  width: 100%;
  height: 92px;
  object-fit: cover;
  display: block;
}

/* ITEM 4: "Edited" badge — marks clips that are themselves prior editor
   outputs (model === 'clip-editor'), so a user doesn't unknowingly
   re-import an export as a source clip. */
.clip-editor-edited-badge {
  position: absolute;
  top: 5px;
  left: 5px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 7px;
  border-radius: 6px;
  background: var(--ed-chip-strong-bg);
  border: 1px solid rgba(255, 46, 187, 0.55);
  color: #fff;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  pointer-events: none;
  backdrop-filter: blur(3px);
}

.clip-editor-library-loading,
.clip-editor-library-empty,
.clip-editor-library-error {
  grid-column: 1 / -1;
  text-align: center;
  padding: 32px 12px;
  color: var(--text-secondary);
  font-size: 0.88rem;
}
.clip-editor-library-error { color: var(--error, #ff4444); }

/* Live brush ring that follows the cursor at the exact paint size */
.inpaint-brush-cursor {
  position: absolute;
  display: none;
  pointer-events: none;
  border: 1.5px solid rgba(255, 46, 187, 0.95);
  background: rgba(255, 46, 187, 0.15);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.35);
  z-index: 4;
}

.inpaint-zoom-controls {
  position: absolute;
  top: 12px;
  right: 12px;
  display: none;
  align-items: center;
  gap: 2px;
  background: rgba(10, 10, 17, 0.85);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 2px;
  z-index: 5;
  backdrop-filter: blur(4px);
}

.inpaint-zoom-controls button {
  background: none;
  border: none;
  color: var(--text-primary);
  min-width: 30px;
  height: 28px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0 6px;
}

.inpaint-zoom-controls button:hover {
  background: rgba(255, 46, 187, 0.15);
}

.inpaint-zoom-controls .inpaint-zoom-level {
  font-size: 0.78rem;
  color: var(--text-secondary);
  min-width: 48px;
}

.inpaint-control-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

#inpaintToolSection .inpaint-control-section {
  gap: 12px;
}

#inpaintToolSection .inpaint-control-section + .inpaint-control-section {
  margin-top: 8px;
}

#inpaintToolSection .inpaint-divider {
  margin: 14px 0 4px;
}

#inpaintToolSection .inpaint-slider-group {
  margin-top: 12px;
  padding-top: 4px;
}

#inpaintToolSection .inpaint-slider-label,
#inpaintToolSection .value-slider-label {
  align-items: center;
  margin: 0 0 8px;
  color: var(--text-secondary);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.2;
  text-transform: none;
}

#inpaintToolSection .inpaint-select {
  margin-top: 2px;
}

.inpaint-control-label {
  color: var(--text-secondary);
  font-size: 0.9rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
}

.inpaint-brush-size-container {
  display: flex;
  align-items: center;
  gap: 12px;
}

.inpaint-brush-size-container input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  background: var(--bg-hover);
  height: 6px;
  border-radius: 3px;
  outline: none;
}

.inpaint-brush-size-container input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: linear-gradient(135deg, #ff2ebb, #00b2ff);
  cursor: pointer;
}

.inpaint-brush-size-value {
  color: var(--text-primary);
  font-size: 0.85rem;
  min-width: 40px;
}

.brush-hotkey-hint {
  color: var(--text-muted);
  font-size: 0.7rem;
  font-weight: 500;
}

.brush-mode-toggle {
  display: flex;
  gap: 6px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 4px;
}

.brush-mode-btn {
  flex: 1;
  padding: 8px 10px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.8rem;
  font-weight: 600;
  transition: all 0.2s;
}

.brush-mode-btn:hover {
  color: var(--text-primary);
  background: rgba(255, 255, 255, 0.05);
}

.brush-mode-btn.active {
  background: linear-gradient(135deg, #ff2ebb, #00b2ff);
  color: var(--text-primary);
}

/* .inpaint-brush-preview removed — the live brush ring on the canvas
   shows the exact paint size at the cursor instead. */

/* .inpaint-intensity-slider / .inpaint-intensity-labels removed —
   replaced by the global .value-slider-* pattern defined near the Advanced
   Settings markup, beside the pointer to css/lora-combobox.css. */

.inpaint-button-row {
  display: flex;
  gap: 10px;
}

.inpaint-btn {
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
  border: none;
}

.inpaint-btn.secondary {
  flex: 1;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-color);
  color: var(--text-light);
}

.inpaint-btn.secondary:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.inpaint-btn.primary {
  background: linear-gradient(135deg, #ff2ebb, #00b2ff);
  color: var(--text-primary);
}

.inpaint-btn.primary:hover {
  opacity: 0.9;
}

.inpaint-divider {
  height: 1px;
  background: var(--bg-hover);
  margin: 4px 0;
}

.inpaint-textarea {
  width: 100%;
  min-height: 100px;
  padding: 12px;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: 0.9rem;
  resize: vertical;
  font-family: inherit;
}

.inpaint-textarea:focus {
  outline: none;
  border-color: #ff2ebb;
}

.inpaint-select {
  width: 100%;
  padding: 12px;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: 0.9rem;
  cursor: pointer;
}

.inpaint-select:focus {
  outline: none;
  border-color: #ff2ebb;
}

.inpaint-mode-toggle {
  display: flex;
  gap: 8px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 4px;
}

.inpaint-mode-btn {
  flex: 1;
  padding: 10px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
}

.inpaint-mode-btn:hover {
  color: var(--text-primary);
}

.inpaint-mode-btn.active {
  background: linear-gradient(135deg, #ff2ebb, #00b2ff);
  color: var(--text-primary);
}

.inpaint-generate-icon {
  font-size: 1.2rem;
}
