/* AiCut default theme + structural styles.
 *
 * Theme variables intentionally share names with iqvise's globals.css
 * (--color-brand, --color-secondary, --color-card, --color-surface,
 *  --color-dark, --color-muted, etc.). Two consequences:
 *   1. Hosting pages that already define those variables (e.g. via
 *      Tailwind v4 @theme, a global :root block, or a `.dark` class
 *      toggle) get the editor styled in their palette for free.
 *   2. We use `var(--color-foo, <fallback>)` everywhere so the
 *      library still works standalone — the fallback IS the default
 *      brand palette.
 *
 * Editor-chrome-specific variables (`--aicut-controls-*`) keep the
 * `aicut-` prefix because they have no analogue in the host theme.
 * They derive from `--color-*` by default so they auto-follow
 * light/dark when the host flips its palette. */

.aicut-root {
  /* Brand tokens — same names as iqvise's globals.css. */
  --color-brand: var(--color-brand, #9a31f4);
  --color-secondary: var(--color-secondary, #9a31f4);
  --color-surface: var(--color-surface, #f8f7fa);
  --color-dark: var(--color-dark, #1a1a1a);
  --color-muted: var(--color-muted, #999999);
  --color-card: var(--color-card, #ffffff);
  --color-success: var(--color-success, #00d95e);
  --color-warning: var(--color-warning, #faa700);
  --color-info: var(--color-info, #1077ff);
  --color-error: var(--color-error, #ff0909);

  /* Editor chrome — derived from the brand palette. Defaults pick a
     pro-NLE charcoal so the editor reads as a tool regardless of the
     surrounding page; hosts that explicitly want it to follow their
     light-mode card colour can pass a `theme` prop or set the
     `--aicut-controls-*` vars themselves. */
  --aicut-controls-bg: var(--aicut-controls-bg, #1f1f22);
  --aicut-controls-border: var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
  --aicut-controls-text: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  --aicut-controls-hover: var(--aicut-controls-hover, rgba(255, 255, 255, 0.08));
  --aicut-controls-active: var(--aicut-controls-active, rgba(255, 255, 255, 0.12));

  --aicut-radius-sm: var(--aicut-radius-sm, 8px);
  --aicut-radius-md: var(--aicut-radius-md, 12px);
  --aicut-radius-lg: var(--aicut-radius-lg, 16px);

  --aicut-clip-bg: linear-gradient(
    180deg,
    color-mix(in srgb, var(--color-brand) 80%, transparent),
    color-mix(in srgb, var(--color-secondary) 70%, transparent)
  );
  --aicut-track-bg: color-mix(in srgb, var(--aicut-controls-text) 6%, transparent);
  --aicut-playhead-color: var(--color-brand);

  display: grid;
  /* Four explicit rows: header / preview / toolbar / timeline. When
     the header is hidden (empty slots → display:none below), browsers
     would otherwise auto-reflow the remaining three children into
     rows 1/2/3 — which would put the preview in the `auto` row and
     toolbar in the `1fr` row, causing the preview to collapse and a
     big gap between toolbar and timeline. The explicit grid-row
     assignments on the children pin each surface to its intended
     row regardless of which siblings are present. */
  grid-template-rows: auto 1fr auto auto;
  width: 100%;
  height: 100%;
  min-height: 480px;
  background: var(--aicut-controls-bg);
  color: var(--aicut-controls-text);
  font-family:
    system-ui,
    -apple-system,
    "Segoe UI",
    Roboto,
    "PingFang SC",
    "Microsoft YaHei",
    sans-serif;
  outline: none;
  box-sizing: border-box;
  overflow: hidden;
}

.aicut-root *,
.aicut-root *::before,
.aicut-root *::after {
  box-sizing: border-box;
}

/* ===== Main row (preview + optional side panels) ===== */

/* Wrapper around the preview area. In the default `fullWidth` layout
   it stretches edge-to-edge so legacy hosts see the same preview-
   spanning-the-row behavior they always had. When the host sets
   `previewLayout="centered"` it becomes a 3-column grid that pins the
   preview to the middle third, mirroring CapCut-desktop's source/
   media-bin → preview → effects/properties layout.
   Each main-row child is explicitly grid-placed by column so toggling
   a panel's display doesn't shift the preview into the wrong track. */
.aicut-main {
  display: grid;
  grid-template-columns: 0 1fr 0;
  min-height: 0;
  overflow: hidden;
}

.aicut-main > .aicut-panel-left   { grid-column: 1; }
.aicut-main > .aicut-preview-card { grid-column: 2; }
.aicut-main > .aicut-panel-right  { grid-column: 3; }

.aicut-root[data-preview-layout="centered"] .aicut-main {
  /* 1fr | 1fr | 1fr → preview gets exactly one third of the width.
     Side panels share the remaining two thirds equally. */
  grid-template-columns: 1fr 1fr 1fr;
}

.aicut-panel {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  background: var(--aicut-controls-bg);
  color: var(--aicut-controls-text);
}

.aicut-panel-left,
.aicut-panel-right {
  /* No borders — the card and the panels read as separate "islands"
     floating on the editor background. CapCut-desktop convention. */
  padding: 16px;
}

/* In the default fullWidth layout the side columns collapse to 0
   width — we keep the panels in the layout (visibility:hidden) so
   grid-track-auto-placement isn't surprised when a panel is empty,
   and React/Vue Teleports stay attached to a stable DOM node even
   when the host toggles between layouts at runtime. */
.aicut-root:not([data-preview-layout="centered"]) .aicut-panel {
  visibility: hidden;
  pointer-events: none;
}

/* ===== Preview card ===== */

/* The preview lives inside a "card" so the viewport (video + canvas
   guide + keyframe overlays) and the playback chrome (time / play /
   duration / fullscreen) are visually paired but never overlap. Width
   is capped to keep the viewport compact in wide editors; height is
   driven by the host's aspect ratio so the dashed frame, the video,
   and the footer all line up regardless of viewport size. */
.aicut-preview-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Tasteful upper bound — the card stops growing past this even when
     the main row is much wider. Narrower than the full row so the
     side-panel slots have room to breathe (CapCut-desktop convention:
     viewport in the middle, source/properties on either side). Hosts
     can override `--aicut-preview-max-width` to shrink/grow. */
  max-width: var(--aicut-preview-max-width, 560px);
  /* Stretch to the available row height (minus a thin breathing
     margin top + bottom). Inside, the host absorbs the extra height
     via `flex: 1 1 auto` so the card reads as a single tall island
     instead of hugging the canvas-guide rectangle. */
  height: calc(100% - 16px);
  margin: 8px auto;
  align-self: stretch;
  border-radius: var(--aicut-radius-md, 12px);
  overflow: hidden;
  background: var(--aicut-preview-bg, #000);
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);
  min-height: 0;
}

.aicut-preview-host {
  position: relative;
  background: var(--aicut-preview-bg, #000);
  /* Width fills the card column. Height stretches to fill the rest
     of the card so the surface reads as a single tall panel even when
     the chosen output aspect is narrower — the canvas guide drawn by
     the playback engine inside still shows the actual output ratio
     centered with letterbox. */
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

/* Footer playback strip — sits beneath the viewport inside the card.
   Subtle separator + matching surface so the strip reads as part of
   the card, not a stand-alone toolbar. */
.aicut-preview-controls {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  /* Lock the footer's height so flex-shrink doesn't squash it when
     the card has to fit a short row — the host above absorbs the
     space pressure via its `flex: 1 1 auto` instead. */
  flex: 0 0 40px;
  padding: 0 14px;
  background: var(--aicut-controls-bg, #1f1f22);
  border-top: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
}

/* Pull the fullscreen button OUT of the centered flex group so the
   time / play / duration trio stays perfectly centered. Absolute-
   positioned to the right edge; everything else (icon size, hover,
   color) inherits from the .aicut-fullscreen rules below. */
.aicut-preview-controls .aicut-fullscreen {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
}

.aicut-preview-controls .aicut-time-current,
.aicut-preview-controls .aicut-time-total {
  min-width: 48px;
  font-variant-numeric: tabular-nums;
}

.aicut-preview-controls .aicut-play-btn {
  width: 28px;
  height: 28px;
  background: transparent;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
}

.aicut-preview-controls .aicut-play-btn:not([data-state="playing"]):hover {
  background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.08));
}

.aicut-preview-controls .aicut-play-btn[data-state="playing"] {
  background: var(--color-brand, #9a31f4);
  color: #fff;
}

.aicut-preview-controls .aicut-fullscreen {
  width: 28px;
  height: 28px;
}

.aicut-preview-controls .aicut-fullscreen:hover:not(:disabled) {
  background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.08));
}

/* Keyframe transform panel — mounts into the editor's left panel
   column (visible when keyframe mode is on AND a keyframe is
   selected). Adapts to the editor theme via the same
   `--aicut-controls-*` tokens the rest of the chrome uses, so dark /
   light / custom themes get a coherent look without a separate
   "floating panel" palette. */
.aicut-keyframe-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  padding: 12px 14px 10px;
  border-radius: 10px;
  background: var(--aicut-controls-bg, #1f1f22);
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  font: 12px system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.22);
}

.aicut-keyframe-panel__title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* Slightly muted variant of controls-text — same hue, less weight. */
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  opacity: 0.75;
}

.aicut-keyframe-panel__time {
  font: 10px ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  opacity: 0.55;
}

.aicut-keyframe-panel__row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.aicut-keyframe-panel__row label {
  flex: 0 0 44px;
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  opacity: 0.7;
}

.aicut-keyframe-panel__row input {
  flex: 1;
  width: 84px;
  min-width: 0;
  padding: 5px 8px;
  font: 12px ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.92));
  background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.06));
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.12));
  border-radius: 6px;
  -moz-appearance: textfield;
}

.aicut-keyframe-panel__row input::-webkit-outer-spin-button,
.aicut-keyframe-panel__row input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.aicut-keyframe-panel__row input:hover {
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.1));
}

.aicut-keyframe-panel__row input:focus {
  outline: none;
  border-color: var(--color-brand, #9a31f4);
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.1));
  box-shadow: 0 0 0 2px rgba(154, 49, 244, 0.22);
}

/* Small dot to the right of each input — filled = this prop pins
   THIS moment, outlined = doesn't (display shows the interpolated
   value; editing will create a kf at this time). */
.aicut-keyframe-panel__badge {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 2px;
  border-radius: 50%;
  border: 1.5px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.36));
  background: transparent;
  flex: 0 0 8px;
  transition:
    background-color 100ms ease-out,
    border-color 100ms ease-out;
}
.aicut-keyframe-panel__badge--on {
  background: var(--color-brand, #9a31f4);
  border-color: var(--color-brand, #9a31f4);
  box-shadow: 0 0 6px rgba(154, 49, 244, 0.5);
}

/* Custom easing dropdown — themed to match the rest of the panel.
   Trigger acts like a button, the floating menu is brand-aware and
   uses a subtle gradient + box-shadow for elevation. */
.aicut-keyframe-panel__dropdown {
  flex: 1;
  position: relative;
  min-width: 0;
}

.aicut-keyframe-panel__dropdown-trigger {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding: 5px 8px 5px 10px;
  font: 12px ui-monospace, SFMono-Regular, Menlo, monospace;
  text-align: left;
  cursor: pointer;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.92));
  background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.06));
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.12));
  border-radius: 6px;
  transition:
    border-color 120ms ease-out,
    background-color 120ms ease-out,
    box-shadow 120ms ease-out;
}
.aicut-keyframe-panel__dropdown-trigger:hover {
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.1));
  border-color: var(--color-brand, #9a31f4);
}
.aicut-keyframe-panel__dropdown-trigger:focus-visible {
  outline: none;
  border-color: var(--color-brand, #9a31f4);
  box-shadow: 0 0 0 2px rgba(154, 49, 244, 0.22);
}
.aicut-keyframe-panel__dropdown-trigger--open {
  border-color: var(--color-brand, #9a31f4);
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.1));
  box-shadow: 0 0 0 2px rgba(154, 49, 244, 0.22);
}
.aicut-keyframe-panel__dropdown-trigger--disabled,
.aicut-keyframe-panel__dropdown-trigger:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.aicut-keyframe-panel__dropdown-trigger-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Chevron — pure CSS triangle, rotates when the menu opens. */
.aicut-keyframe-panel__dropdown-chevron {
  flex: 0 0 6px;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.75;
  transition:
    transform 140ms ease-out,
    opacity 120ms ease-out;
  transform-origin: 50% 35%;
}
.aicut-keyframe-panel__dropdown-trigger--open
  .aicut-keyframe-panel__dropdown-chevron {
  transform: rotate(180deg);
  opacity: 1;
  color: var(--color-brand, #9a31f4);
}

/* Floating menu. Positioned right under the trigger; the panel
   uses `position: relative` on `.dropdown` so absolute-positioning
   here means "anchored to the trigger". */
.aicut-keyframe-panel__dropdown-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 50;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--aicut-controls-bg, rgba(20, 20, 22, 0.96));
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.12));
  border-radius: 8px;
  box-shadow:
    0 8px 24px rgba(0, 0, 0, 0.32),
    0 0 0 1px rgba(154, 49, 244, 0.06);
  backdrop-filter: blur(8px);
  animation: aicut-keyframe-dropdown-in 120ms ease-out;
}
@keyframes aicut-keyframe-dropdown-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.aicut-keyframe-panel__dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px 7px 26px;
  position: relative;
  font: 12px ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.92));
  border-radius: 5px;
  cursor: pointer;
  user-select: none;
  outline: none;
  transition: background-color 80ms ease-out;
}
.aicut-keyframe-panel__dropdown-item:hover,
.aicut-keyframe-panel__dropdown-item:focus {
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.1));
}
.aicut-keyframe-panel__dropdown-item--selected {
  color: var(--color-brand, #9a31f4);
}
/* Checkmark for the selected item — drawn with two CSS borders. */
.aicut-keyframe-panel__dropdown-item--selected::before {
  content: "";
  position: absolute;
  left: 10px;
  top: 50%;
  width: 4px;
  height: 8px;
  margin-top: -5px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

.aicut-keyframe-panel__actions {
  display: flex;
  gap: 6px;
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
}

.aicut-keyframe-panel__reset {
  flex: 1;
  padding: 6px 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.06));
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.14));
  border-radius: 6px;
  cursor: pointer;
  transition:
    background-color 80ms ease-out,
    border-color 80ms ease-out,
    color 80ms ease-out;
}

.aicut-keyframe-panel__reset:hover:not(:disabled) {
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.1));
  border-color: var(--color-brand, #9a31f4);
}

.aicut-keyframe-panel__reset:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Direct-manipulation overlay on top of the preview — frame border
   + corner handles. Hidden when keyframes are off (display:none from
   the controlling class). Pointer events: the overlay itself passes
   through; only the frame body + handles capture clicks. */
.aicut-keyframe-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
}

.aicut-keyframe-overlay__canvas-guide {
  position: absolute;
  border: 1.5px dashed
    color-mix(in srgb, var(--color-brand, #9a31f4) 65%, transparent);
  background: transparent;
  /* Always passive — the canvas guide is purely informational. The
     selection frame below is what captures pan / scale drags. */
  pointer-events: none;
  cursor: default;
  box-sizing: border-box;
}

.aicut-keyframe-overlay__frame {
  position: absolute;
  border: 1.5px dashed var(--color-brand, #9a31f4);
  background: transparent;
  /* Passive by default — selecting a clip outlines it but doesn't
     necessarily mean "drag-to-edit". Keyframes mode flips this on. */
  pointer-events: none;
  cursor: default;
  box-sizing: border-box;
  transition:
    border-color 100ms ease-out,
    border-style 100ms ease-out,
    box-shadow 120ms ease-out;
}

.aicut-keyframe-overlay--interactive .aicut-keyframe-overlay__frame {
  pointer-events: auto;
  cursor: move;
}

/* Warn state — content doesn't fully cover the output frame, i.e.
   letterbox is exposed. Strong visual distinction from the brand
   pink: a solid 2px red border + soft red glow, so even on dark
   themes where brand and warning hues read similar it's obvious. */
.aicut-keyframe-overlay__frame--warn {
  border-style: solid;
  border-width: 2px;
  border-color: #ff3b30;
  box-shadow:
    0 0 0 1px rgba(255, 59, 48, 0.35),
    0 0 14px rgba(255, 59, 48, 0.55);
}

.aicut-keyframe-overlay__handle {
  position: absolute;
  width: 12px;
  height: 12px;
  background: var(--aicut-controls-bg, #1f1f22);
  border: 1.5px solid var(--color-brand, #9a31f4);
  border-radius: 2px;
  pointer-events: auto;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  transition: transform 80ms ease-out;
  /* Handles belong to keyframe editing. Hide them when the overlay
     is in passive (outline-only) mode. */
  display: none;
}

.aicut-keyframe-overlay--interactive .aicut-keyframe-overlay__handle {
  display: block;
}

.aicut-keyframe-overlay__handle:hover {
  transform: scale(1.3);
}

.aicut-keyframe-overlay__handle--tl,
.aicut-keyframe-overlay__handle--br {
  cursor: nwse-resize;
}

.aicut-keyframe-overlay__handle--tr,
.aicut-keyframe-overlay__handle--bl {
  cursor: nesw-resize;
}

/* Edge midpoint handles — slimmer rectangles so they read as "edge
   grip" instead of "corner grip", and so they don't visually fight
   the corner handles when they sit close together on a small PiP. */
.aicut-keyframe-overlay__handle--edge {
  width: 18px;
  height: 6px;
  border-radius: 4px;
}

.aicut-keyframe-overlay__handle--l,
.aicut-keyframe-overlay__handle--r {
  width: 6px;
  height: 18px;
}

.aicut-keyframe-overlay__handle--t,
.aicut-keyframe-overlay__handle--b {
  cursor: ns-resize;
}

.aicut-keyframe-overlay__handle--l,
.aicut-keyframe-overlay__handle--r {
  cursor: ew-resize;
}

.aicut-fullscreen-exit {
  position: absolute;
  top: 16px;
  right: 16px;
  display: none;
  padding: 6px 12px;
  font-size: 12px;
  color: #fff;
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 8px;
  cursor: pointer;
  backdrop-filter: blur(8px);
  z-index: 2;
}

.aicut-fullscreen-exit:hover {
  background: rgba(0, 0, 0, 0.7);
}

/* ===== In-tab fullscreen ===== */

.aicut-root.aicut-fullscreen {
  /* The root itself stays in flow so its parent layout doesn't jump;
     we lift just the preview to viewport-cover. */
}

.aicut-root.aicut-fullscreen .aicut-preview-card {
  position: fixed;
  inset: 0;
  z-index: 9999;
  max-width: none;
  margin: 0;
  border-radius: 0;
  border: 0;
  box-shadow: none;
  background: #000;
}

.aicut-root.aicut-fullscreen .aicut-preview-host {
  flex: 1 1 auto;
  aspect-ratio: auto;
  background: #000;
}

.aicut-root.aicut-fullscreen .aicut-fullscreen-exit {
  display: inline-flex;
}

/* ===== Header (opt-in via slots) ===== */

/* Slim bar above the preview. Bookend left/right slots are host-
   filled via the React wrapper's headerLeft/headerRight props or the
   Vue named slots. Collapsed entirely when both slots are empty so
   the default editor layout is byte-for-byte the same as before the
   header existed. */
.aicut-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  height: 44px;
  padding: 0 12px;
  background: var(--aicut-controls-bg);
  border-bottom: 1px solid var(--aicut-controls-border);
  color: var(--aicut-controls-text);
  font-size: 13px;
  /* Sit above the preview so dropdowns/popovers from header buttons
     can overflow naturally without z-index plumbing. */
  position: relative;
  z-index: 1;
}

/* Auto-hide when both slots are empty — keep today's default layout
   exactly as it was for callers that don't use the header. With the
   per-child grid-row assignments below, display:none here cleanly
   removes the header without reflowing preview/toolbar/timeline. */
.aicut-root:has(.aicut-header-left:empty):has(.aicut-header-right:empty)
  .aicut-header {
  display: none;
}

/* Pin each editor surface to its intended row. Required so the four
   children can't auto-reflow when one (e.g. the header) is hidden. */
.aicut-root > .aicut-header        { grid-row: 1; }
.aicut-root > .aicut-main          { grid-row: 2; }
.aicut-root > .aicut-toolbar       { grid-row: 3; }
.aicut-root > .aicut-timeline      { grid-row: 4; }

.aicut-header-slot {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.aicut-header-right {
  margin-left: auto;
}

/* ===== Toolbar ===== */

.aicut-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 44px;
  padding: 0 12px;
  border-top: 1px solid var(--aicut-controls-border);
  border-bottom: 1px solid var(--aicut-controls-border);
  background: var(--aicut-controls-bg);
  /* Single-row layout — horizontal scroll fallback only when the
     editor is too narrow for the toolbar's natural content width.
     Without overflow-x, the editor root's `overflow: hidden` would
     silently clip the right cluster (looks like the sidebar covers
     the editor). With it, the user can scroll to reach hidden
     controls instead of having the chrome reflow to two rows. */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}

.aicut-toolbar::-webkit-scrollbar {
  height: 6px;
  background: transparent;
}

.aicut-toolbar::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--aicut-controls-text) 28%, transparent);
  border-radius: 999px;
}

.aicut-toolbar::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--aicut-controls-text) 45%, transparent);
}

.aicut-toolbar-left,
.aicut-toolbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 0;
  /* Default flex `min-width: auto` resolves to the content's
     min-content — i.e. the group can shrink down to the slider's
     min-width but no further. Without this, the group collapsed
     past its content, the toolbar never saw overflow, and the right
     cluster got silently clipped by the editor root's
     `overflow: hidden`. Now the toolbar's `overflow-x: auto`
     correctly engages when the viewport is too narrow. */
}

.aicut-toolbar-right {
  justify-content: flex-end;
}

.aicut-toolbar-center {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Host-supplied bookend slots — empty until populated. The library
   paints nothing into either; we only reserve the layout box and add
   a subtle separator once the host puts something in. */
.aicut-toolbar-extras {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  min-width: 0;
}

.aicut-toolbar-extras-left:not(:empty) {
  padding-right: 8px;
  margin-right: 4px;
  border-right: 1px solid var(--aicut-controls-border);
}

.aicut-toolbar-extras-right:not(:empty) {
  padding-left: 8px;
  margin-left: 4px;
  border-left: 1px solid var(--aicut-controls-border);
}

.aicut-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--aicut-controls-text);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
  /* Without this, the flex parent will horizontally squash the
     icon-btns when the row gets crowded (e.g. both extras slots
     populated). Keeping shrink at 0 means the zoom slider takes
     the pressure instead, which is the right call — it has
     legitimate flex range; icons are atomic. */
  flex-shrink: 0;
}

.aicut-icon-btn:hover:not(:disabled) {
  background: var(--aicut-controls-hover);
}

.aicut-icon-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.aicut-icon-btn.aicut-toggle-on {
  background: var(--aicut-controls-active);
  color: var(--color-brand);
}

/* Toggle-on hover keeps the brand-state visible — without this, the
   generic icon-btn :hover rule above overrides toggle-on's background
   back to controls-hover, which reads as the toggle *dimming* on
   hover (opposite direction from the non-toggled trim/zoom buttons,
   which lighten on hover). Brand-tinted bg makes both feel
   consistently "lights up on hover". */
.aicut-icon-btn.aicut-toggle-on:hover:not(:disabled) {
  background: color-mix(in srgb, var(--color-brand) 18%, transparent);
}

.aicut-play-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  border: none;
  background: var(--aicut-controls-active);
  color: var(--aicut-controls-text);
  cursor: pointer;
  transition: background-color 120ms ease;
  flex-shrink: 0;
}

/* The play button wraps its SVG in a <span> (so play↔pause swaps can
   re-set innerHTML without losing the click target identity). A bare
   span is inline-flow → the SVG inside aligns to font baseline,
   which leaves a couple of px of font-descender space below the
   icon and shifts it visually up-and-right inside the circle. Make
   the span its own flex centring box so the SVG sits at geometric
   center of the button regardless of inherited font metrics. */
.aicut-play-btn > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 0;
}

/* Hover ONLY in the paused state. Restricting by attribute means
   the playing state has no competing background-on-hover rule at
   equal specificity — eliminates any cascade-order surprises that
   could leak `controls-hover` (near-white in light themes) over the
   white pause icon. */
.aicut-play-btn:not([data-state="playing"]):hover {
  background: var(--aicut-controls-hover);
}

.aicut-play-btn[data-state="playing"] {
  background: var(--color-brand, #9a31f4);
  color: #fff;
}

.aicut-play-btn[data-state="playing"]:hover {
  background: color-mix(in srgb, var(--color-brand, #9a31f4) 88%, black);
}

.aicut-time-current,
.aicut-time-total {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  min-width: 44px;
  text-align: center;
  color: var(--aicut-controls-text);
  flex-shrink: 0;
}

.aicut-time-total {
  color: color-mix(in srgb, var(--aicut-controls-text) 60%, transparent);
}

/* Slider track. Two solid stops in one gradient — brand color for
   the filled portion, a dedicated `--aicut-track-unfilled` for the
   rest. The unfilled tone derives from `--aicut-controls-text` (the
   chrome text color, which is light-on-dark or dark-on-light), so
   the rail auto-contrasts against any host theme without a brittle
   "is the theme light?" attribute selector. Hosts can still override
   `--aicut-track-unfilled` directly for full control. */
.aicut-zoom-slider {
  --aicut-track-unfilled: color-mix(
    in srgb,
    var(--aicut-controls-text) 22%,
    transparent
  );
  appearance: none;
  -webkit-appearance: none;
  width: 96px;
  /* Allow the slider to absorb horizontal pressure when extras
     populate the toolbar — it's the only element here with
     legitimate flex-stretch semantics. Hard floor at 60px keeps
     the thumb grabbable. */
  min-width: 60px;
  flex-shrink: 1;
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(
    to right,
    var(--color-brand) 0 var(--aicut-zoom-fill, 50%),
    var(--aicut-track-unfilled) var(--aicut-zoom-fill, 50%) 100%
  );
  box-shadow: inset 0 0 0 1px
    color-mix(in srgb, var(--aicut-controls-text) 10%, transparent);
  border: none;
  cursor: pointer;
  outline: none;
}

/* Hide the chromium default track since we paint via background. */
.aicut-zoom-slider::-webkit-slider-runnable-track {
  background: transparent;
  height: 6px;
  border-radius: 999px;
}

.aicut-zoom-slider::-moz-range-track {
  background: transparent;
  height: 6px;
  border-radius: 999px;
}

.aicut-zoom-slider::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -4px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.2);
  cursor: grab;
}

.aicut-zoom-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: none;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* ===== Timeline ===== */

/* The timeline is now a single <canvas> — this rule is the host
   element that the canvas sizes itself to. Ruler, tracks, clips,
   thumbnails, playhead, headers, and snap guide are ALL painted on
   that canvas (see packages/core/src/timeline/). */
.aicut-timeline {
  position: relative;
  flex: 0 0 auto;
  background: var(--aicut-controls-bg);
  /* Override via EditorOptions.timelineHeight (sets the custom property
     on the root container). Default 240 matches historical behavior;
     small-viewport hosts often want 140–180. min-height is intentionally
     a hair below the smallest sensible default so the option can dip
     into the compact range without the min winning. */
  height: var(--aicut-timeline-height, 240px);
  min-height: 120px;
  overflow: hidden;
}

.aicut-timeline-canvas canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* ===== Timeline toolbar (opt-in slot for host-supplied controls) ===== */

.aicut-timeline-toolbar {
  flex: 0 0 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px;
  gap: 12px;
  background: var(--aicut-controls-bg);
  border-bottom: 1px solid var(--aicut-controls-border);
  color: var(--aicut-controls-text);
  font-size: 13px;
  /* Sit above the canvas in stacking so popovers/dropdowns spawned
     from buttons can render over the timeline area instead of behind it. */
  position: relative;
  z-index: 1;
}

.aicut-timeline-toolbar-left,
.aicut-timeline-toolbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.aicut-timeline-toolbar-right {
  margin-left: auto;
}

/* ===== Lighting editor (opt-in component) ===== */

/* IMPORTANT: every `var(--aicut-controls-*)` reference below carries
   an explicit fallback (the same value the .aicut-root rule would
   compute via its self-reference pattern). Chrome treats the
   self-reference `--foo: var(--foo, x)` on .aicut-root as a cycle
   and skips it when no parent + no inline override defines `--foo`
   — which means the lighting component must NOT depend on those
   inherited custom properties succeeding. The video editor sidesteps
   the issue because applyTheme() always writes the values inline.
   Hosts that pass a `theme` prop or set the --aicut-controls-* vars
   themselves still override these fallbacks; it's pure belt-and-
   braces. */

.aicut-lighting-editor {
  --aicut-lighting-canvas-bg: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 4%, transparent);
  --aicut-lighting-section-gap: 18px;
  --aicut-lighting-control-w: 220px;
  display: block;
}

.aicut-lighting-body {
  display: grid;
  /* Just two columns: scene 240 + controls 220. Hosts that want to
     render an adjacent panel (AI smart mode, prompt, presets, …) put
     their own DOM beside <LightingEditor> in their own layout. */
  grid-template-columns: 240px 220px;
  gap: 28px;
  align-items: start;
  padding: 24px;
  background: var(--aicut-controls-bg, #1f1f22);
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  border-radius: var(--aicut-radius-md, 12px);
}

/* --- Scene column --- */
.aicut-lighting-scene-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  /* Self-center vertically so the sphere stays at the visual midpoint
     of the row even when an adjacent host panel makes the row taller
     than the scene column's own content. */
  align-self: center;
}

.aicut-lighting-view-toggle {
  display: inline-flex;
  padding: 2px;
  border-radius: 999px;
  background: var(--aicut-controls-active, rgba(255, 255, 255, 0.12));
  position: relative;
}
.aicut-lighting-view-opt {
  height: 24px;
  padding: 0 12px;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 12px;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  opacity: 0.6;
  border-radius: 999px;
  cursor: pointer;
  transition: opacity 120ms ease, background-color 120ms ease;
}
.aicut-lighting-view-opt.active {
  background: var(--aicut-controls-bg, #1f1f22);
  opacity: 1;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}

.aicut-lighting-scene-viewport {
  width: 100%;
  max-width: 240px;
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  background: var(--aicut-lighting-canvas-bg);
  position: relative;
  /* Keep the canvas filling the viewport even before ResizeObserver
     fires the first measurement. */
  display: flex;
  align-items: center;
  justify-content: center;
}

/* --- Controls column --- */
.aicut-lighting-controls {
  display: flex;
  flex-direction: column;
  gap: var(--aicut-lighting-section-gap);
  min-width: 0;
}

.aicut-lighting-controls-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.aicut-lighting-controls-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
}

.aicut-lighting-controls-header-slot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.aicut-lighting-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.aicut-lighting-section-row {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}

.aicut-lighting-label {
  font-size: 12px;
  color: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 70%, transparent);
}

.aicut-lighting-range {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 4px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 18%, transparent);
  outline: none;
}
.aicut-lighting-range::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  cursor: pointer;
}
.aicut-lighting-range::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: 0;
  border-radius: 50%;
  background: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  cursor: pointer;
}

.aicut-lighting-color {
  width: 44px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
  border-radius: 6px;
  background: transparent;
  cursor: pointer;
}

.aicut-lighting-dir-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.aicut-lighting-dir-btn {
  height: 28px;
  padding: 0 4px;
  border: 1px solid var(--aicut-controls-border, rgba(255, 255, 255, 0.08));
  border-radius: 6px;
  background: transparent;
  color: var(--aicut-controls-text, rgba(255, 255, 255, 0.85));
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.aicut-lighting-dir-btn:hover {
  background: var(--aicut-controls-hover, rgba(255, 255, 255, 0.08));
}
.aicut-lighting-dir-btn.active {
  background: color-mix(in srgb, var(--color-brand, #9a31f4) 18%, transparent);
  border-color: var(--color-brand, #9a31f4);
  color: var(--color-brand, #9a31f4);
}

.aicut-lighting-toggle {
  width: 32px;
  height: 18px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--aicut-controls-text, rgba(255, 255, 255, 0.85)) 18%, transparent);
  position: relative;
  cursor: pointer;
  transition: background-color 120ms ease;
}
.aicut-lighting-toggle.active {
  background: var(--color-brand, #9a31f4);
}
.aicut-lighting-toggle-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  position: absolute;
  top: 2px;
  left: 2px;
  transition: left 120ms ease;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.aicut-lighting-toggle.active .aicut-lighting-toggle-thumb {
  left: 16px;
}

/* Host-controlled footer area where Reset / Generate / preset-save
   buttons go. Library renders this empty div; the React wrapper's
   `controlsFooter` prop / Vue's <slot name="controlsFooter"> portals
   the host content in. */
.aicut-lighting-controls-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
  min-height: 0;
  margin-top: 4px;
}
.aicut-lighting-controls-footer:empty {
  display: none;
}


/* ===== Aspect-ratio picker (built-in, opt-in via aspect.enabled) ===== */

.aicut-aspect-picker {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

.aicut-aspect-trigger {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 28px;
  padding: 0 6px;
  border-radius: 6px;
  border: 1px solid var(--aicut-controls-border);
  background: transparent;
  color: var(--aicut-controls-text);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.aicut-aspect-trigger:hover {
  background: var(--aicut-controls-hover);
}

.aicut-aspect-trigger[aria-expanded="true"] {
  background: var(--aicut-controls-active);
  border-color: color-mix(in srgb, var(--color-brand, #9a31f4) 60%, transparent);
}

.aicut-aspect-trigger-label {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  min-width: 22px;
  text-align: center;
}

.aicut-aspect-trigger-caret {
  display: inline-flex;
  align-items: center;
  opacity: 0.55;
  line-height: 0;
}

/* Popover lives on document.body (escapes overflow clipping) — give
   it its own surface tokens rather than inheriting whatever the
   toolbar's parent owns. */
.aicut-aspect-menu {
  z-index: 9999;
  min-width: 240px;
  padding: 10px;
  border-radius: 10px;
  background: var(--aicut-controls-bg);
  color: var(--aicut-controls-text);
  border: 1px solid var(--aicut-controls-border);
  box-shadow:
    0 6px 24px rgba(0, 0, 0, 0.18),
    0 2px 6px rgba(0, 0, 0, 0.08);
  font-size: 12px;
}

.aicut-aspect-menu-header {
  padding: 4px 6px 8px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.65;
}

.aicut-aspect-menu-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}

.aicut-aspect-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  padding: 8px 4px 8px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.aicut-aspect-option:hover {
  background: var(--aicut-controls-hover);
}

.aicut-aspect-option-active {
  border-color: color-mix(in srgb, var(--color-brand, #9a31f4) 70%, transparent);
  background: color-mix(in srgb, var(--color-brand, #9a31f4) 12%, transparent);
}

.aicut-aspect-option-tile-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 24px;
}

.aicut-aspect-option-tile {
  display: block;
  border-radius: 2px;
  border: 1.4px solid currentColor;
  opacity: 0.85;
  max-width: 26px;
  max-height: 22px;
}

.aicut-aspect-option-active .aicut-aspect-option-tile {
  border-color: var(--color-brand, #9a31f4);
  background: color-mix(in srgb, var(--color-brand, #9a31f4) 18%, transparent);
  opacity: 1;
}

.aicut-aspect-option-label {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}
