Files
olivv-cs-ComfyUI-FunPack/movie_editor/frontend/styles.css
T
digital-garbageandClaude Opus 5 94f82cfab4 feat(editor): the timeline strip waits for intent, and the swap animates
Crossing the strip on the way to the Dock opened the timeline for a frame. It
now waits 220ms with the pointer still on it before opening, and leaving
CANCELS a pending open rather than queueing a close — so a pass-through costs
nothing at all. A drag skips the wait entirely: dragging a file onto the
timeline is not an accident.

The swap animates. That meant giving up display:none for the closed state,
since display cannot be transitioned: closed is height 0 with overflow hidden,
which looks identical at rest — no sliver of lane, no cut-off clip — and on the
way open the same clipping is simply what a reveal looks like. The strip and
the timeline animate against each other so the zone's height stays continuous
rather than jumping. Reduced motion drops the slide and keeps the behaviour.

Verified in the browser: a touch-and-leave does not open it, staying does and
only after the delay, leaving closes it, and the transition is on the body.
Nine unit tests cover the intent timer with injected timers, including the two
that would bite — a drag cancelling a pending hover, and moving around inside
an already-open timeline not re-arming the delay.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 16:22:28 +03:00

2826 lines
178 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ════════════════════════════════════════════════════════════════════
FunPack · Cutting Room — cinematic dark editing suite
════════════════════════════════════════════════════════════════════ */
/* ── theme tokens ──────────────────────────────────────────────────────
Two palettes, one vocabulary. The stylesheet below never names a colour;
it only names a role. `data-theme` is stamped on <html> at boot by
theme.js — "auto" is resolved there, so CSS only ever sees dark|light.
───────────────────────────────────────────────────────────────────── */
:root, :root[data-theme="dark"] {
color-scheme: dark;
--shadow-ink: rgba(0,0,0,.85);
--ink-0: #0c0b09; /* app bg */
--ink-1: #131210; /* zones */
--ink-2: #1a1814; /* heads / raised */
--ink-3: #221f19; /* hover */
--line: #2a261e;
--line-2: #37322833;
--line-hi: #4a4334; /* clip hover border */
--text: #ece7db;
--muted: #918a7a;
--faint: #645e51;
--surface-deep: #110f0c; /* deepest chrome / gradient floor */
--surface-deep-2: #12100c;
--surface-deep-3: #12100d;
--surface-deep-4: #121009; /* settings sidebar */
--surface-deep-5: #14110d;
--surface-deep-6: #14120d; /* menu rail */
--surface-modal: #16140f; /* modal / popover body */
--surface-pop: #1b1813; /* menu popover */
--surface-pop-2: #161410; /* popover gradient floor */
--surface-raised: #1e1b16; /* raised gradient top */
--surface-raised-2: #1f1c16;
--surface-raised-3: #211d16; /* clip body top */
--surface-raised-4: #19160f; /* clip body floor */
--surface-raised-5: #1a1711; /* audio track */
--surface-raised-6: #1a1712;
--surface-raised-7: #1b1812; /* timeline drop card */
--surface-raised-8: #1d1a14; /* context menu */
--surface-raised-9: #17140f;
--surface-log: #0c0b09f2; /* log panel */
--scroll-thumb: #2f2b22;
--scroll-thumb-hi: #3d382c;
--ink-void: #060606; /* media letterbox */
--black: #000; /* true black behind media */
--overlay-1: #ffffff08;
--overlay-2: #ffffff10;
--overlay-3: #ffffff18;
--overlay-4: #ffffff22;
--hi: #fff; /* on-media white */
--hi-soft: #fff8;
--scrim-1: #0006;
--scrim-2: #0009;
--scrim-3: #000a;
--scrim-4: #000c;
--scrim-slate: #080808ee; /* preview slate */
--fade-black: #00000088; /* transition tail */
--accent: #f3a93c;
--accent-hi: #ffc36b;
--accent-lo: #e0972a; /* gradient floor */
--accent-soft: rgba(243,169,60,.14);
--on-accent: #1a1206; /* text on a filled accent */
--on-accent-2: #241503;
--accent-dim: #2a2418; /* accent-tinted surface */
--accent-dim-2: #3d3420;
--accent-dim-3: #2a2218; /* tour chip */
--warn: #e8a040;
--teal: #57d0c6;
--teal-2: #3ab3a8;
--teal-3: #2d9a90;
--teal-4: #2a6a62;
--teal-hi: #c8fff4; /* text on teal-tinted chrome */
--teal-soft: rgba(87,208,198,.14);
--on-teal: #0a1a18;
--sel: rgb(45,212,191); /* clip selection ring */
--danger: #e8607a;
--danger-2: #e06c75;
--danger-hi: #fecaca;
--good: #79c479;
--good-2: #57c98e;
--pink: rgb(255,120,180); /* rating heart */
--pink-hi: #ffb3d4;
--violet: #c084fc;
--violet-2: #d8b4fe;
--violet-3: #e9d5ff;
--violet-4: #f3e8ff;
--violet-5: #c79bf2; /* refinement key badge */
--violet-6: #b8a0ff; /* audio placeholder */
--violet-7: #c4b0ff;
--indigo: #7c6cf0; /* v2v source stripe */
--blue: #60a5fa;
--blue-2: #93c5fd;
--blue-3: #7eb0ff;
--blue-4: #5b8def;
--blue-line: #2a4468;
--blue-dim: #3a5a8a;
--blue-dim-2: #1a2840;
--blue-dim-3: #121c2e;
--blue-dim-4: #141c28;
--blue-dim-5: #0f141c;
--blue-macro: rgb(88,166,214); /* shortcut macro box */
--audio-dim: #1e3a2f;
--audio-dim-2: #152820;
--audio-line: #2d5a45;
--audio-dim-3: #1a3530;
--audio-dim-4: #122820;
--audio-line-2: #2d6a58;
--stripe: #1a1a1a; /* pending hatch */
--carry: #1e2a28;
--carry-2: #243532;
--ov-preview-1: #2a2430; /* overlay text preview bg */
--ov-preview-2: #121018;
--grip: #8a8f98; /* splitter grip */
--grip-2: #5b6068;
--popup: rgba(24,26,30,0.99); /* rating popup */
--popup-line: rgba(180,190,200,0.3);
--backdrop: rgba(6,5,4,.66); /* modal scrim */
--backdrop-2: rgba(8,7,6,.92); /* welcome scrim */
--backdrop-3: rgba(8,7,5,.88); /* tour scrim */
--backdrop-4: rgba(6,5,4,.78);
--backdrop-5: rgba(19,18,16,.94); /* tour card */
--scrim-media: rgba(0,0,0,.55);
--scrim-media-2: rgba(0,0,0,.45);
--scrim-media-3: rgba(0,0,0,.85);
--surface-pop-3: #1a1813;
}
:root[data-theme="light"] {
color-scheme: light;
--shadow-ink: rgba(24,34,48,.30);
--ink-0: #f5f7fa; /* app bg */
--ink-1: #ffffff; /* zones */
--ink-2: #eef1f6; /* heads / raised */
--ink-3: #e1e7ef; /* hover */
--line: #d3dae3;
--line-2: #8a97a833;
--line-hi: #b9c3cf; /* clip hover border */
--text: #16202c;
--muted: #59677a;
--faint: #8d9aab;
--surface-deep: #e7ebf1; /* deepest chrome / gradient floor */
--surface-deep-2: #e9edf3;
--surface-deep-3: #e9edf3;
--surface-deep-4: #e9edf3; /* settings sidebar */
--surface-deep-5: #eceff4;
--surface-deep-6: #eceff4; /* menu rail */
--surface-modal: #ffffff; /* modal / popover body */
--surface-pop: #ffffff; /* menu popover */
--surface-pop-2: #f2f5f9; /* popover gradient floor */
--surface-raised: #f4f7fa; /* raised gradient top */
--surface-raised-2: #f4f7fa;
--surface-raised-3: #f4f7fa; /* clip body top */
--surface-raised-4: #e9edf3; /* clip body floor */
--surface-raised-5: #f2f5f9; /* audio track */
--surface-raised-6: #f2f5f9;
--surface-raised-7: #ffffff; /* timeline drop card */
--surface-raised-8: #ffffff; /* context menu */
--surface-raised-9: #eceff4;
--surface-log: #ffffffee; /* log panel */
--scroll-thumb: #c3ccd8;
--scroll-thumb-hi: #a9b5c4;
--ink-void: #0a0c0f; /* media letterbox */
--black: #000; /* true black behind media */
--overlay-1: #0f1a2a08;
--overlay-2: #0f1a2a10;
--overlay-3: #0f1a2a18;
--overlay-4: #0f1a2a22;
--hi: #ffffff; /* on-media white */
--hi-soft: #ffffffcc;
--scrim-1: #0006;
--scrim-2: #0009;
--scrim-3: #000a;
--scrim-4: #000c;
--scrim-slate: #0a0c0fee; /* preview slate */
--fade-black: #00000088; /* transition tail */
--accent: #2f7fd4;
--accent-hi: #5aa4ec;
--accent-lo: #2668b0; /* gradient floor */
--accent-soft: rgba(47,127,212,.13);
--on-accent: #ffffff; /* text on a filled accent */
--on-accent-2: #ffffff;
--accent-dim: #dbe7f6; /* accent-tinted surface */
--accent-dim-2: #c4d8f0;
--accent-dim-3: #dbe7f6; /* tour chip */
--warn: #b26a00;
--teal: #12857c;
--teal-2: #0f6f68;
--teal-3: #0c5c56;
--teal-4: #0a4a45;
--teal-hi: #0a4a45; /* text on teal-tinted chrome */
--teal-soft: rgba(18,133,124,.15);
--on-teal: #ffffff;
--sel: rgb(15,111,104); /* clip selection ring */
--danger: #c62a48;
--danger-2: #c0392f;
--danger-hi: #7f1d1d;
--good: #2f8f4e;
--good-2: #127a45;
--pink: rgb(197,45,116); /* rating heart */
--pink-hi: #a01a5c;
--violet: #7c3aed;
--violet-2: #6d28d9;
--violet-3: #5b21b6;
--violet-4: #4c1d95;
--violet-5: #6d28d9; /* refinement key badge */
--violet-6: #6d28d9; /* audio placeholder */
--violet-7: #5b21b6;
--indigo: #4f46e5; /* v2v source stripe */
--blue: #1d6fd0;
--blue-2: #1a5fb4;
--blue-3: #1a5fb4;
--blue-4: #2563eb;
--blue-line: #a8c4e8;
--blue-dim: #7ba7dd;
--blue-dim-2: #dbe8f8;
--blue-dim-3: #cbdcf2;
--blue-dim-4: #dbe8f8;
--blue-dim-5: #cbdcf2;
--blue-macro: rgb(29,111,208); /* shortcut macro box */
--audio-dim: #dcf0e4;
--audio-dim-2: #c6e6d3;
--audio-line: #8fcaa9;
--audio-dim-3: #d8f0e8;
--audio-dim-4: #c2e6d8;
--audio-line-2: #83c7b1;
--stripe: #cbd3dd; /* pending hatch */
--carry: #dde9e7;
--carry-2: #cadedb;
--ov-preview-1: #efeaf6; /* overlay text preview bg */
--ov-preview-2: #dcd6e8;
--grip: #8a8f98; /* splitter grip */
--grip-2: #b6bdc7;
--popup: rgba(255,255,255,0.99); /* rating popup */
--popup-line: rgba(80,95,115,0.28);
--backdrop: rgba(24,34,48,.34); /* modal scrim */
--backdrop-2: rgba(232,237,243,.94); /* welcome scrim */
--backdrop-3: rgba(24,34,48,.6); /* tour scrim */
--backdrop-4: rgba(24,34,48,.5);
--backdrop-5: rgba(255,255,255,.96); /* tour card */
--scrim-media: rgba(0,0,0,.55);
--scrim-media-2: rgba(0,0,0,.45);
--scrim-media-3: rgba(0,0,0,.85);
--surface-pop-3: #ffffff;
}
:root {
--media-w: 280px;
--properties-w: 340px;
--inspector-h: 340px;
--timeline-h: 320px;
--menubar-h: 34px;
/* Inter is the open Helvetica/SF-alike — Apple ships SF free, but its licence covers
work FOR Apple platforms only, so it can't be bundled here. system-ui sits right
behind it, which IS San Francisco on a Mac. */
--font-display: "Inter Tight", "Inter", system-ui, -apple-system, sans-serif;
--font-ui: "Inter", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
--radius: 9px;
/* Type scale — the macOS text styles from Apple's HIG. Every size in this file is a
step on it; nothing is 11.5px any more. Body is 13, the macOS default. */
--fs-title-1: 22px; --lh-title-1: 26px;
--fs-title-2: 17px; --lh-title-2: 22px;
--fs-title-3: 15px; --lh-title-3: 20px;
--fs-body: 13px; --lh-body: 16px;
--fs-callout: 12px; --lh-callout: 15px;
--fs-subhead: 11px; --lh-subhead: 14px;
--fs-footnote: 10px; --lh-footnote: 13px;
/* 4pt grid. */
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px;
/* Control metrics. One height for anything clickable, so a row of mixed controls
lines up without per-component padding guesses. */
--ctl-h: 26px; /* buttons, selects */
--ctl-h-sm: 22px; /* compact / in-row */
--ctl-h-lg: 30px; /* text fields, primary actions */
--ctl-r: 6px;
--ctl-pad-x: 10px;
--shadow: 0 10px 30px -12px color-mix(in srgb, var(--shadow-ink) 82.4%, transparent);
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
background:
radial-gradient(1200px 600px at 80% -10%, var(--surface-pop) 0%, transparent 60%),
var(--ink-0);
color: var(--text);
font: var(--fs-body)/1.45 var(--font-ui);
overflow: hidden;
-webkit-font-smoothing: antialiased;
}
body.dragging { cursor: col-resize; user-select: none; }
/* film grain overlay */
.grain {
position: fixed; inset: 0; pointer-events: none; z-index: 9000; opacity: .035;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
mix-blend-mode: overlay;
}
button, input, select, textarea { font-family: inherit; color: var(--text); }
::selection { background: var(--accent-soft); }
/* scrollbars */
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: 8px; border: 2px solid var(--ink-1); }
*::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hi); }
*::-webkit-scrollbar-track { background: transparent; }
/* ───────────────────────── MENU BAR ───────────────────────── */
.menubar {
height: var(--menubar-h); display: flex; align-items: center; gap: 18px;
padding: 0 14px; background: linear-gradient(var(--surface-modal), var(--surface-deep));
border-bottom: 1px solid var(--line); position: relative; z-index: 200;
}
.brand { font-family: var(--font-display); font-weight: 800; letter-spacing: .2px; font-size: var(--fs-title-3); display: flex; align-items: center; gap: 8px; }
.brand-mark { color: var(--accent); font-size: 12px; transform: translateY(-1px); filter: drop-shadow(0 0 6px var(--accent-soft)); }
.brand-sub { color: var(--faint); font-weight: 500; font-size: var(--fs-callout); }
/* The brand is a link back to the hub in both frontends. */
a.brand { text-decoration: none; color: inherit; }
a.brand:hover .brand-sub { color: var(--accent-hi); }
.menus { display: flex; gap: 2px; }
/* ── Simple ⇄ Editor ──────────────────────────────────────────────────────
One app, two faces. The switch sits beside the wordmark because it changes
what the whole window is, not what one panel shows. */
.mode-switch {
display: inline-flex; flex: 0 0 auto; padding: 2px; gap: 2px;
border: 1px solid var(--line); border-radius: 7px; background: var(--ink-1);
}
.mode-btn {
border: 0; border-radius: 5px; background: transparent; color: var(--muted);
height: 22px; padding: 0 var(--sp-2); cursor: pointer;
font-family: inherit; font-size: var(--fs-subhead); line-height: var(--lh-subhead);
transition: background .12s, color .12s;
}
.mode-btn:hover { color: var(--text); }
.mode-btn.on { background: var(--accent-soft); color: var(--accent-hi); }
/* Where the transport bar lands when the timeline is hidden. */
.mode-actions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.mode-actions:empty { display: none; }
/* Simple mode: everything that needs explaining is gone. Nothing is disabled and no
state is dropped — the timeline, ratings and advanced panes are still there, and
switching back shows them exactly as they were. */
:root[data-ui-mode="simple"] .zone.timeline,
:root[data-ui-mode="simple"] #split-bottom,
:root[data-ui-mode="simple"] #split-left,
:root[data-ui-mode="simple"] #split-right,
:root[data-ui-mode="simple"] .dock-tabs,
:root[data-ui-mode="simple"] .composer-btn,
:root[data-ui-mode="simple"] .insp-engine-strip,
:root[data-ui-mode="simple"] .rating-bar,
:root[data-ui-mode="simple"] .insp-fold,
:root[data-ui-mode="simple"] .mode-full-only { display: none !important; }
.menu { position: relative; }
.menu-btn {
background: transparent; border: 0; height: var(--ctl-h); padding: 0 var(--sp-2);
border-radius: var(--ctl-r);
font-size: var(--fs-callout); color: var(--text); cursor: pointer; letter-spacing: .2px;
}
.menu.open .menu-btn, .menu-btn:hover { background: var(--ink-3); }
.menu-pop {
position: absolute; top: calc(100% + 6px); left: 0; min-width: 230px;
background: var(--surface-pop); border: 1px solid var(--line); border-radius: 10px;
box-shadow: var(--shadow); padding: 6px; z-index: 300;
animation: pop .12s ease; transform-origin: top left;
}
@keyframes pop { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
.menu-item {
display: flex; align-items: center; justify-content: space-between; gap: 16px;
padding: 7px 10px; border-radius: 7px; cursor: pointer; font-size: 13px; white-space: nowrap;
}
.menu-item:hover { background: var(--accent-soft); color: var(--accent-hi); }
.menu-item.disabled { color: var(--faint); pointer-events: none; }
.menu-item .hint { color: var(--faint); font-size: var(--fs-subhead); }
.menu-item:hover .hint { color: var(--accent); }
.menu-sep { height: 1px; background: var(--line); margin: 5px 6px; }
.menu-label { padding: 4px 10px 3px; font-size: 11px; color: var(--faint); font-weight: 600;}
.menu-veil { position: fixed; inset: 0; z-index: 150; }
.menubar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.health-chip, .save-chip {
font-size: var(--fs-subhead); line-height: var(--lh-subhead); color: var(--muted);
display: flex; align-items: center; gap: 6px; padding: 3px var(--sp-2);
border: 1px solid var(--line); border-radius: 20px;
}
.health-chip .led { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); }
.health-chip.ok .led { background: var(--good); box-shadow: 0 0 8px var(--good); }
.health-chip.bad .led { background: var(--danger); box-shadow: 0 0 8px var(--danger); }
.save-chip { border-color: transparent; color: var(--faint); }
.save-chip.dirty { color: var(--accent); }
/* backend log viewer */
.log-btn { background: var(--ink-2); border: 1px solid var(--line); border-radius: 20px; color: var(--muted);
font-size: 11px; padding: 3px 11px; cursor: pointer; }
.log-btn:hover { color: var(--accent-hi); background: var(--ink-3); }
.log-btn.active { color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.log-panel { position: fixed; z-index: 9000; right: 14px; top: 48px; width: min(720px, 88vw); height: min(420px, 60vh);
background: var(--surface-log); border: 1px solid var(--line); border-radius: 10px; display: flex; flex-direction: column;
box-shadow: 0 16px 40px -12px var(--black); overflow: hidden; }
.log-panel[hidden] { display: none; } /* explicit display:flex above would otherwise beat the hidden attribute */
.log-head { display: flex; align-items: center; justify-content: space-between; padding: 7px 10px; border-bottom: 1px solid var(--line);
font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--accent); }
.log-actions { display: flex; gap: 6px; align-items: center; }
.log-freeze-indicator { font-family: var(--font-mono); font-size: 10px; color: var(--faint); white-space: nowrap; }
.log-body { flex: 1; margin: 0; padding: 8px 10px; overflow: auto; white-space: pre-wrap; word-break: break-word;
font-family: var(--font-mono); font-size: 11px; line-height: 1.45; color: var(--muted); background: var(--ink-void); }
/* ──────────── WORKSPACE — OpenCut-style NLE: Assets | Preview | Properties / Timeline ──────────── */
/* (layout borrowed from OpenCut: three resizable columns over a full-width timeline) */
.workspace { height: calc(100% - var(--menubar-h)); display: flex; flex-direction: column; min-height: 0; }
.main-row { flex: 1; display: flex; min-height: 0; min-width: 0; }
.zone { background: var(--ink-1); display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.dock-panel[hidden] { display: none !important; }
.media { width: var(--media-w); flex: 0 0 auto; border-right: 1px solid var(--line); container-type: inline-size; container-name: media-zone; }
.preview { flex: 1; min-width: 120px; }
.inspector { width: var(--properties-w); flex: 0 0 auto; border-left: 1px solid var(--line); }
.timeline { height: var(--timeline-h); min-height: 200px; border-top: 1px solid var(--line); }
/* Timeline peek (Settings > Appearance): the timeline sits as a strip showing only its
header — title, transport, Composer — and opens to its full height when pointed at.
It grows UPWARD because it is the last row of a column, so the strip stays under the
cursor as it opens and the pointer never falls out of what it just opened.
.peek-drag-open is held by timeline_peek.js for the length of a drag: during one the
pointer is in drag mode and a strip that stays shut is a target you cannot hit. */
:root[data-timeline-peek="1"] .zone.timeline {
/* Sizes to its contents: the header, plus the strip or the timeline. flex: 0 0 auto is
load-bearing — .zone is a shrinkable column child, and a fixed height with min-height: 0
let the workspace squeeze it to 1px. */
height: auto;
min-height: 0;
flex: 0 0 auto;
}
/* CLOSED is height 0, not display:none — display cannot be transitioned, and the swap has to
animate. overflow: hidden is what keeps the resting state clean: at height 0 there is no
sliver of lane or cut-off clip to read as a broken timeline, and on the way open the same
clipping is simply what a reveal looks like. */
:root[data-timeline-peek="1"] .zone.timeline .zone-body {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 0;
height: 0;
min-height: 0;
overflow: hidden;
transition: height .18s cubic-bezier(.22,.61,.36,1),
flex-basis .18s cubic-bezier(.22,.61,.36,1);
}
:root[data-timeline-peek="1"] .zone.timeline.peek-open .zone-body,
:root[data-timeline-peek="1"] .zone.timeline.peek-drag-open .zone-body {
flex-basis: var(--timeline-h);
height: var(--timeline-h);
overflow: auto;
}
/* The strip. It IS the closed state, so it collapses as the timeline arrives — the two
animate against each other and the zone's total height stays continuous. */
.tl-peek-strip { display: none; }
:root[data-timeline-peek="1"] .tl-peek-strip {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
height: 26px;
overflow: hidden;
border-top: 1px solid var(--line);
font-size: var(--fs-subhead);
color: var(--faint);
letter-spacing: .02em;
white-space: nowrap;
cursor: default;
user-select: none;
transition: height .18s cubic-bezier(.22,.61,.36,1),
opacity .12s ease, color .12s ease;
}
:root[data-timeline-peek="1"] .tl-peek-strip:hover { color: var(--text); }
:root[data-timeline-peek="1"] .zone.timeline.peek-open .tl-peek-strip,
:root[data-timeline-peek="1"] .zone.timeline.peek-drag-open .tl-peek-strip {
height: 0;
opacity: 0;
border-top-color: transparent;
}
/* Dragging the splitter would fight the strip for the height, so it goes with it. The
preference IS the height decision while it is on. */
:root[data-timeline-peek="1"] #split-bottom { display: none; }
/* Anything anchored to the timeline's height reads the CLOSED size: measured header + strip. */
:root[data-timeline-peek="1"] {
--timeline-anchor: calc(var(--timeline-peek-h, 34px) + 26px);
}
/* Reduced motion: it still opens and closes, just without the slide. */
@media (prefers-reduced-motion: reduce) {
:root[data-timeline-peek="1"] .zone.timeline .zone-body,
:root[data-timeline-peek="1"] .tl-peek-strip { transition: none; }
}
}
}
}
/* degrade gracefully as columns are toggled off — preview takes the slack, else properties, else media */
.main-row[data-preview="0"][data-settings="1"] .inspector { flex: 1; width: auto; }
.main-row[data-preview="0"][data-settings="0"] .media,
.main-row[data-media="0"][data-preview="0"] .inspector { flex: 1; width: auto; }
/* hide a splitter when one of its two neighbours is hidden */
.main-row[data-media="0"] #split-left,
.main-row[data-preview="0"][data-settings="0"] #split-left { display: none; }
.main-row[data-preview="0"] #split-right,
.main-row[data-settings="0"] #split-right { display: none; }
/* panel toggle tabs (timeline header, top-right) */
.dock-tabs { display: flex; gap: 4px; margin-left: 12px; flex: 0 0 auto; }
.dock-tab {
background: var(--ink-2); border: 1px solid var(--line); border-radius: 6px;
color: var(--faint); font-size: 11px; padding: 4px 10px; cursor: pointer; transition: background .12s, color .12s, border-color .12s;
}
.dock-tab:hover { color: var(--muted); border-color: var(--muted); }
.dock-tab.on { background: var(--accent-soft); color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.dock-tab:only-child { cursor: default; }
/* Pinned shortcuts: same chip shape as the panel toggles so the row reads as one strip,
with a leading dot marking them as "goes somewhere" rather than "shows a panel". */
.pinned-tabs { margin-left: 0; margin-right: 4px; }
.pinned-tab { color: var(--muted); border-style: dashed; cursor: pointer; }
.pinned-tab::before { content: "◆"; margin-right: 5px; color: var(--accent); font-size: 9px; }
.pinned-tab:hover { color: var(--text); border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
/* A lone pin is still a button — the panel-toggle rule that disables the last visible
panel must not reach into this nav. */
.pinned-tab:only-child { cursor: pointer; }
.pin-modal { max-width: 460px; }
.pin-lead { font-size: 13px; color: var(--text); margin-bottom: 4px; }
.pin-hint { font-size: 11px; color: var(--faint); line-height: 1.45; margin-bottom: 10px; }
.pin-slots { display: flex; flex-direction: column; gap: 6px; }
.pin-slot {
display: flex; align-items: center; justify-content: space-between; gap: 10px;
width: 100%; text-align: left; cursor: pointer;
padding: 9px 11px; border-radius: 8px;
background: var(--ink-2); border: 1px solid var(--line);
transition: border-color .12s, background .12s;
}
.pin-slot:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); background: var(--ink-3); }
.pin-slot.occupied { border-style: solid; border-color: color-mix(in srgb, var(--accent) 30%, var(--line)); }
.pin-slot-name { font-size: 12px; font-weight: 600; color: var(--text); }
.pin-slot-sub { font-size: 11px; color: var(--faint); margin-top: 2px; }
.pin-slot-pos { font-size: 10px; color: var(--faint); font-family: var(--font-mono); flex-shrink: 0; }
.pin-clear-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px;
padding-top: 10px; border-top: 1px solid var(--line); }
.zone-head {
/* min-height, not height: the right-hand status block wraps when the zone is narrow,
and a fixed height let it spill over the zone above AND the toolbar below. */
min-height: 34px; flex: 0 0 auto; display: flex; align-items: center;
gap: var(--sp-2) var(--sp-3); flex-wrap: wrap;
padding: var(--sp-1) var(--sp-3); background: linear-gradient(var(--surface-pop-3), var(--surface-pop-2));
border-bottom: 1px solid var(--line);
}
.zone-title {
font-size: var(--fs-callout); line-height: var(--lh-callout); color: var(--text); font-weight: 600;
}
.zone-title::before { content: ""; display: inline-block; width: 5px; height: 5px; margin-right: var(--sp-2); border-radius: 50%; background: var(--accent); transform: translateY(-1px); }
.transport-actions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.transport-actions .btn.compact { min-height: var(--ctl-h-sm); padding: 0 var(--sp-2); font-size: var(--fs-subhead); }
.transport-actions .btn:disabled { opacity: 0.42; pointer-events: none; cursor: default; }
.transport-actions .btn.render {
background: linear-gradient(var(--teal-2), var(--teal-3)); color: var(--on-teal); border-color: var(--teal-2);
font-weight: 600; box-shadow: 0 4px 14px -6px color-mix(in srgb, var(--teal) 55%, transparent);
}
.transport-actions .btn.render:hover { filter: brightness(1.08); }
.zone-head-right { margin-left: auto; font-family: var(--font-mono); font-size: var(--fs-subhead);
color: var(--faint); display: flex; gap: var(--sp-1) var(--sp-2); align-items: center;
flex-wrap: wrap; justify-content: flex-end; min-width: 0; }
.zone-body { flex: 1; overflow: auto; padding: var(--sp-4); min-height: 0; }
/* splitters */
.splitter { background: transparent; position: relative; flex: 0 0 auto; }
.splitter::after { content: ""; position: absolute; background: var(--line); transition: background .15s; }
.splitter:hover::after { background: var(--accent); }
.splitter-v { width: 7px; cursor: col-resize; }
.splitter-v::after { inset: 0 3px; }
.splitter-h { height: 7px; cursor: row-resize; }
.splitter-h::after { inset: 3px 0; }
/* ───────────────────────── BUTTONS / FIELDS ───────────────────────── */
.btn { background: var(--ink-2); border: 1px solid var(--line); border-radius: var(--ctl-r);
min-height: var(--ctl-h); padding: 0 var(--ctl-pad-x); cursor: pointer;
font-size: var(--fs-callout); line-height: var(--lh-callout);
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
white-space: nowrap; /* a toolbar label wrapping inside a 22px chip reads as broken */
transition: border-color .12s, background .12s; }
.btn:hover { border-color: var(--accent); }
.btn.primary { background: linear-gradient(var(--accent), var(--accent-lo)); color: var(--on-accent); border-color: var(--accent); font-weight: 700; box-shadow: 0 4px 14px -6px var(--accent); }
.btn.primary:hover { filter: brightness(1.08); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--muted); padding: 0 var(--sp-2); }
.btn.ghost:hover { color: var(--accent-hi); background: var(--ink-3); }
.btn.ghost.on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
/* "This is switched on but cannot do anything" chip, shown beside Generate. */
.btn.action-warn { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.btn.action-warn:hover { color: var(--accent-hi); border-color: var(--accent); }
.btn.danger:hover { border-color: var(--danger); color: var(--danger); }
/* Live elapsed counter on a transport button. Tabular figures keep the label from twitching
as the digits change; the seconds are zero-padded in JS so the string only ever grows at
the minute boundary, not once a second. */
.btn.btn-timer { font-variant-numeric: tabular-nums; }
.btn.tiny { min-height: var(--ctl-h-sm); padding: 0 var(--sp-2); font-size: var(--fs-subhead); }
label.field { display: block; margin-bottom: 12px; }
label.field > span { display: block; font-size: var(--fs-subhead); line-height: var(--lh-subhead);
color: var(--muted); margin-bottom: var(--sp-1); font-weight: 500; }
/* Field label with an inline enable toggle (e.g. Postfix). Matches the field-label look. */
.field-toggle { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; cursor: pointer; }
.field-toggle > input { width: auto; margin: 0; }
.field-toggle > span { font-size: 11px; color: var(--faint); font-weight: 600;}
.field > textarea:disabled { opacity: .45; cursor: not-allowed; }
input, select, textarea {
width: 100%; background: var(--ink-0); border: 1px solid var(--line); border-radius: var(--ctl-r);
min-height: var(--ctl-h-lg); padding: 5px var(--sp-2);
font-size: var(--fs-body); line-height: var(--lh-body);
outline: none; transition: border-color .12s, box-shadow .12s;
}
textarea { min-height: 0; }
input:focus, select:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
textarea { resize: vertical; line-height: 1.5; }
.fields-row { display: flex; gap: 10px; }
.fields-row > label.field { flex: 1; }
input[type=number] { font-family: var(--font-mono); }
/* ───────────────────────── MEDIA BROWSER ───────────────────────── */
.mb-section { margin-bottom: 18px; }
.mb-section-title { display: flex; align-items: center; justify-content: space-between;
font-size: var(--fs-subhead); line-height: var(--lh-subhead); color: var(--muted);
margin-bottom: var(--sp-2); font-weight: 600; }
.project-row { display: flex; align-items: center; gap: var(--sp-2); padding: 6px var(--sp-2); border-radius: var(--ctl-r); cursor: pointer; border: 1px solid transparent; }
.project-row:hover { background: var(--ink-2); }
.project-row.active { background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 27%, transparent); }
.project-row .pj-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-row .pj-meta { font-family: var(--font-mono); font-size: 11px; color: var(--faint); }
.mediabin {
border: 1.5px dashed var(--line); border-radius: var(--radius); padding: 26px 14px; text-align: center;
color: var(--faint); font-size: 12px; transition: border-color .15s, background .15s;
}
.mediabin.drag { border-color: var(--teal); background: var(--teal-soft); color: var(--teal); }
.mediabin .big { font-size: 26px; opacity: .5; margin-bottom: 8px; }
.mediabin { cursor: pointer; padding: 18px 14px; }
.soon { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px; color: var(--faint); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; }
/* bin tabs (Media / Shortcuts / Transitions) */
.mb-bin-shell { display: flex; flex-direction: column; min-height: 0; }
.mb-bin-scroll { display: flex; flex-direction: column; gap: 10px; }
.bin-tabs { display: flex; gap: 2px; margin-bottom: 10px; border-bottom: 1px solid var(--line);
overflow-x: auto; flex-wrap: nowrap; scrollbar-width: thin; -webkit-overflow-scrolling: touch; }
.bin-tabs-sticky {
position: sticky; top: 0; z-index: 3; margin-bottom: 10px;
background: color-mix(in srgb, var(--ink-0) 92%, transparent);
backdrop-filter: blur(6px);
padding-top: 2px;
}
.bin-tab { background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--faint);
font-family: var(--font-mono); font-size: 10px; letter-spacing: .4px; padding: 6px 7px; cursor: pointer;
flex: 0 0 auto; white-space: nowrap; }
.bin-tab:hover { color: var(--muted); }
.bin-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.bin { display: flex; flex-direction: column; gap: 10px; }
/* media grid — default compact (pickers, modals); media browser scales with panel width */
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 8px; }
#media-zone .media-grid {
gap: clamp(8px, 2.5cqw, 14px);
}
#media-zone .media-grid[data-cols="0"] {
--mb-cell: clamp(96px, 46cqw, 240px);
grid-template-columns: repeat(auto-fill, minmax(var(--mb-cell), 1fr));
}
#media-zone .media-grid[data-cols="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); --mb-cell: 92cqw; }
#media-zone .media-grid[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); --mb-cell: 44cqw; }
#media-zone .media-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); --mb-cell: 29cqw; }
#media-zone .media-grid[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); --mb-cell: 21cqw; }
#media-zone .media-thumb {
height: auto;
aspect-ratio: 16 / 10;
min-height: 64px;
}
#media-zone .media-icon { font-size: clamp(22px, calc(var(--mb-cell) * 0.32), 36px); }
#media-zone .media-kind-badge {
font-size: clamp(8px, calc(var(--mb-cell) * 0.08), 10px);
padding: 3px 5px;
}
#media-zone .media-name-row { min-height: 30px; padding: 4px 6px 6px; align-items: flex-start; }
#media-zone .media-name {
font-size: clamp(11.5px, calc(var(--mb-cell) * 0.115), 13.5px);
line-height: 1.3;
white-space: normal;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
#media-zone .media-act { width: 18px; height: 18px; font-size: 11px; }
#media-zone .media-name-edit { font-size: clamp(11.5px, calc(var(--mb-cell) * 0.115), 13.5px); }
.media-card { position: relative; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; cursor: pointer; background: var(--ink-0); }
.media-card:hover { border-color: var(--muted); }
.media-card.previewing { border-color: var(--teal); box-shadow: 0 0 0 1px color-mix(in srgb, var(--teal) 35%, transparent); }
.media-thumb { height: 56px; display: flex; align-items: center; justify-content: center; background: var(--ink-void); position: relative; }
.media-thumb img { width: 100%; height: 100%; object-fit: cover; }
.media-vid-thumb { width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
.media-icon { font-size: 20px; color: var(--faint); }
.media-vid-ph { color: color-mix(in srgb, var(--accent-hi) 70%, var(--faint)); }
.media-aud-ph { color: color-mix(in srgb, var(--violet-6) 75%, var(--faint)); }
.media-kind-badge {
position: absolute; left: 3px; top: 3px; z-index: 2;
display: inline-flex; align-items: center; gap: 2px;
font-size: 9px; font-family: var(--font-mono); font-weight: 600; letter-spacing: .04em;
line-height: 1; padding: 2px 4px; border-radius: 4px;
background: var(--scrim-4); border: 1px solid var(--overlay-3); pointer-events: none;
}
.media-kind-ico { font-size: 9px; line-height: 1; }
.media-kind-lbl { opacity: .92; }
.media-kind-badge.kind-image { color: var(--teal-soft); border-color: color-mix(in srgb, var(--teal) 35%, transparent); }
.media-kind-badge.kind-video { color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent-hi) 35%, transparent); }
.media-kind-badge.kind-audio { color: var(--violet-7); border-color: color-mix(in srgb, var(--violet-6) 35%, transparent); }
.media-kind-badge.kind-other { color: var(--muted); }
.media-name-row { display: flex; align-items: center; gap: 2px; padding: 2px 3px 3px; min-height: 22px; }
.media-name { flex: 1; min-width: 0; font-size: 10px; color: var(--muted); padding: 1px 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.media-name-actions { display: flex; flex-shrink: 0; gap: 1px; opacity: 0; transition: opacity .12s; }
.media-card:hover .media-name-actions,
.media-card:focus-within .media-name-actions { opacity: 1; }
.media-act {
width: 16px; height: 16px; padding: 0; font-size: 10px; line-height: 1; flex-shrink: 0;
border: none; border-radius: 3px; background: var(--ink-2); color: var(--muted); cursor: pointer;
}
.media-act:hover { color: var(--accent-hi); background: var(--ink-3); }
.media-act.media-del:hover { color: var(--danger); }
.media-act.media-pin { filter: grayscale(1); }
.media-act.media-pin:hover { filter: none; }
.media-act.media-pin.active { filter: none; background: var(--accent-soft); }
.media-pin-badge { position: absolute; top: 3px; left: 3px; font-size: 10px; line-height: 1;
padding: 2px 3px; border-radius: 4px; background: var(--scrim-media); pointer-events: none; }
/* Reference mark. Reads as a letter, not an icon, so it sits beside the pin without
competing with it — and the badge carries the index, which is the load-bearing part. */
.media-act.media-ref { font-weight: 700; }
.media-act.media-ref.active { color: var(--ink-0); background: var(--accent); }
.media-ref-badge { position: absolute; top: 3px; right: 3px; font-size: 9px; font-weight: 700;
line-height: 1; padding: 2px 4px; border-radius: 4px; color: var(--ink-0);
background: var(--accent); pointer-events: none; }
.media-name-edit {
flex: 1; min-width: 0; box-sizing: border-box; margin: 0; padding: 2px 4px; font-size: 10px;
background: var(--ink-0); border: 1px solid var(--accent); border-radius: 4px; color: var(--text);
}
.media-card.picked { border-color: var(--accent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent); }
.media-bin-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.media-bin-footer { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; align-items: center; }
.media-bin-controls { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 2px; }
.media-bin-type { margin: 0; }
.media-bin-sort { display: flex; align-items: center; gap: 8px; }
.media-bin-cols { display: flex; align-items: center; gap: 8px; }
.media-bin-cols-switch { flex: 1; min-width: 0; }
.media-bin-cols-switch .insp-seg { flex: 1; min-width: 0; padding-left: 4px; padding-right: 4px; }
.media-bin-sort-lbl { flex: 0 0 auto; font-size: 11px; color: var(--faint); font-weight: 600;}
.media-bin-sort-sel { flex: 1; min-width: 0; padding: 5px 7px; font-size: 12px; }
.media-bin-count { margin: 0; }
.media-grid-empty { grid-column: 1 / -1; padding: 4px 2px; }
.media-group-hdr {
grid-column: 1 / -1;
font-family: var(--font-mono); font-size: 9px; letter-spacing: .8px; text-transform: uppercase;
color: var(--faint); padding: 6px 2px 2px; margin-top: 2px;
}
.media-group-hdr:first-child { margin-top: 0; padding-top: 2px; }
.media-select-btn.active { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); background: color-mix(in srgb, var(--accent) 8%, var(--ink-0)); }
.media-select-mode .media-card { cursor: default; }
.media-select-mode .media-card:not(.picked):hover { border-color: var(--accent-hi); }
/* media picker (replaces image <select>s) */
.media-picker { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.media-picker.compact .mpk-sel { padding: 6px 8px; }
.media-picker.disabled { opacity: .55; pointer-events: none; }
.mpk-sel { display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; background: var(--ink-0); }
.mpk-thumb { width: 44px; height: 44px; flex: 0 0 44px; border-radius: 6px; overflow: hidden; background: var(--ink-void); display: flex; align-items: center; justify-content: center; }
.mpk-thumb img { width: 100%; height: 100%; object-fit: cover; }
.mpk-meta { flex: 1; min-width: 0; }
.mpk-name { font-size: 12px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mpk-actions { display: flex; gap: 4px; flex-shrink: 0; }
.mpk-grid-wrap { display: none; max-height: 220px; overflow: auto; border: 1px solid var(--line); border-radius: 8px; padding: 8px; background: var(--ink-1); }
.mpk-grid-wrap.open { display: block; }
.mpk-grid { grid-template-columns: repeat(auto-fill, minmax(68px, 1fr)); }
.mpk-empty { grid-column: 1 / -1; padding: 8px 4px; }
.mpk-none .media-thumb { color: var(--faint); }
/* library lists (shortcuts / transitions) */
.bin-toolbar { display: flex; gap: 5px; flex-wrap: wrap; }
.bin-toolbar .btn { flex-shrink: 0; }
.lib-search { width: 100%; }
/* library add/edit form */
.lib-form { border: 1px solid var(--accent); border-radius: 8px; background: var(--ink-2); padding: 10px; margin: 8px 0; display: flex; flex-direction: column; gap: 8px; }
.lib-form.lib-form-modal { border: none; background: transparent; padding: 0; margin: 0; }
.lib-form-title { font-size: 11px; color: var(--accent); font-weight: 600;}
.lib-field { display: flex; flex-direction: column; gap: 3px; }
.lib-field > span { font-size: 11px; color: var(--faint); font-weight: 600;}
.lib-in { width: 100%; background: var(--ink-0); border: 1px solid var(--line); border-radius: 6px; color: var(--text); font-size: 12px; padding: 5px 7px; font-family: var(--font-mono); resize: vertical; }
.lib-form-actions { display: flex; gap: 6px; }
.lib-list { display: flex; flex-direction: column; gap: 5px; }
.lib-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center; gap: 6px;
padding: 6px 8px; border: 1px solid var(--line); border-radius: 7px; background: var(--ink-0); }
.lib-row.lib-row-nle { grid-template-columns: minmax(0, 1fr) auto; }
.lib-row:hover { border-color: var(--muted); }
.lib-main { flex: 1; min-width: 0; }
.lib-name { font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-sub { font-size: 10px; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Composer ▸ Files — on-disk file manager */
.files-group { margin-top: 12px; }
.files-group:first-of-type { margin-top: 6px; }
.files-group-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.files-group-title { font-size: 12px; font-weight: 700; color: var(--text); }
.files-dir { font-family: var(--font-mono); font-size: 10px; color: var(--faint); margin: 2px 0 6px; word-break: break-all; }
.files-list { display: flex; flex-direction: column; gap: 4px; }
.files-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px;
padding: 5px 8px; border: 1px solid var(--line); border-radius: 7px; background: var(--ink-0); }
.files-row:hover { border-color: var(--muted); }
.files-main { min-width: 0; }
.files-name { font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.files-meta { font-size: 10px; color: var(--faint); }
/* media drop onto a clip */
.clip.drop-target { border-color: var(--teal); box-shadow: inset 0 0 0 2px var(--teal-soft); }
.clip-thumb { position: absolute; inset: 0; z-index: 0; opacity: .22; overflow: hidden; border-radius: 8px; }
.clip.src-mixed .clip-thumb { opacity: .32; }
.clip.src-image .clip-thumb { opacity: .28; }
.clip-thumb-guide { position: absolute; right: 0; bottom: 0; z-index: 2; display: flex; align-items: center; gap: 3px;
padding: 2px 5px 2px 6px; font-size: 9px; font-family: var(--font-mono); letter-spacing: .02em;
color: var(--teal-hi); background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--teal-4) 92%, transparent) 28%);
border-top-left-radius: 6px; pointer-events: none; }
.clip-thumb-guide-icon { color: var(--teal-soft); font-weight: 700; }
.clip-thumb-guide-txt { text-transform: uppercase; font-size: 9px; opacity: .9; }
.clip-thumb img { width: 100%; height: 100%; object-fit: cover; }
.clip-thumb > span { position: absolute; right: 6px; bottom: 4px; font-size: 13px; color: var(--hi-soft); }
.clip.has-media .clip-head, .clip.has-media .clip-text { position: relative; z-index: 1; }
/* inspector image-source preview */
.img-src { display: flex; gap: 10px; align-items: center; }
.img-src-prev { width: 64px; height: 44px; flex: 0 0 auto; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; background: var(--ink-void); display: flex; align-items: center; justify-content: center; }
.img-src-prev img { width: 100%; height: 100%; object-fit: cover; }
.img-src-info { min-width: 0; }
.img-src-name { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; }
/* link source row */
.link-source { margin: 8px 0 0; }
.link-bound { font-size: 11px; color: var(--teal); margin-top: 6px; }
/* ───────────────────────── PREVIEW / PROGRAM MONITOR ───────────────────────── */
.program { padding: 0; background: var(--ink-void); display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; position: relative; }
/* video canvas — fills the zone above transport */
.pm-canvas { flex: 1; position: relative; display: flex; align-items: center; justify-content: center; overflow: hidden; min-height: 0; background: var(--ink-void); }
.pm-canvas::after { content: ""; position: absolute; inset: 0; pointer-events: none; box-shadow: inset 0 0 140px 10px color-mix(in srgb, var(--shadow-ink) 76.5%, transparent); z-index: 1; }
/* The letterbox stays black behind real video in both themes. An EMPTY stage is just a
panel, and a black rectangle with a vignette reads as a broken player in the light one. */
.pm-canvas:has(> .program-empty), .pm-canvas:has(> .pm-gen-splash) { background: var(--ink-1); }
.pm-canvas:has(> .program-empty)::after, .pm-canvas:has(> .pm-gen-splash)::after { box-shadow: none; }
.pm-canvas.media-previewing .pm-stage,
.pm-canvas.media-previewing .pm-slate,
.pm-canvas.media-previewing .pm-segment-badge,
.pm-canvas.media-previewing .pm-segment-badge { visibility: hidden; }
.pm-media-preview { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; justify-content: center; cursor: default; }
.pm-media-preview-img { max-width: 100%; max-height: 100%; object-fit: contain; position: relative; z-index: 1; cursor: default; }
.pm-media-preview-label { position: absolute; top: 10px; left: 10px; z-index: 2; font-size: 10px; font-family: var(--font-mono); color: var(--teal); background: var(--scrim-3); border: 1px solid color-mix(in srgb, var(--teal) 35%, var(--line)); border-radius: 12px; padding: 3px 9px; pointer-events: none; }
.pm-media-preview-aud { width: min(92%, 420px); position: relative; z-index: 1; }
.pm-media-preview-vid { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; position: relative; z-index: 1; cursor: default; background: var(--black); }
.pm-media-preview-label-vid { color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent-hi) 35%, var(--line)); }
.pm-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 0; }
.pm-fx-viewport { position: absolute; inset: 0; display: none; overflow: hidden; }
.pm-fx-viewport.active { display: block; }
.pm-fx-zoom { width: 100%; height: 100%; transform-origin: center center; will-change: transform; }
.pm-video { width: 100%; height: 100%; display: block; object-fit: contain; position: relative; z-index: 0; }
.pm-blank-frame { max-width: 100%; max-height: 100%; width: auto; height: auto; flex: 0 1 auto; background: var(--black); }
.program-empty { text-align: center; color: var(--faint); }
.program-empty .reel { font-size: 40px; opacity: .35; margin-bottom: 10px; }
.pm-gen-splash { display: flex; flex-direction: column; align-items: center; gap: 12px; color: var(--muted); }
.pm-gen-icon { font-size: 36px; animation: pm-spin 3s linear infinite; }
@keyframes pm-spin { to { transform: rotate(360deg); } }
.pm-gen-label { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--muted); }
.gen-readout { position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%); font-family: var(--font-mono); font-size: 12px; color: var(--accent-hi); background: var(--scrim-2); border: 1px solid var(--line); padding: 5px 12px; border-radius: 20px; display: flex; align-items: center; gap: 8px; z-index: 2; white-space: nowrap; }
.gen-readout .pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); animation: pulse 1s infinite; flex: 0 0 auto; }
/* An error is a paragraph, not a status word. The busy readout stays a compact nowrap pill
because it updates every second and must not reflow the canvas; the error state gets to
wrap, scroll and be selected, because it is the thing the user has to read and act on. */
.gen-readout.error {
color: var(--danger);
white-space: pre-wrap;
overflow-wrap: anywhere;
text-align: left;
align-items: flex-start;
max-width: min(760px, 92%);
max-height: 40vh;
overflow-y: auto;
border-radius: 12px;
padding: 9px 14px;
line-height: 1.5;
user-select: text;
cursor: text;
}
.gen-readout.error .pulse { margin-top: 5px; }
.gen-readout .gen-copy { flex: 0 0 auto; align-self: flex-start; margin-top: 1px; }
.gen-readout.error .pulse { background: var(--danger); animation: none; }
.gen-bar { width: 90px; height: 5px; background: var(--overlay-4); border-radius: 3px; overflow: hidden; flex: 0 0 auto; }
.gen-bar-fill { height: 100%; background: var(--accent); border-radius: 3px; transition: width .2s; }
.gen-interrupt { font-family: var(--font-mono); font-size: 11px; color: var(--danger); background: transparent; border: 1px solid color-mix(in srgb, var(--danger) 50%, var(--line)); border-radius: 12px; padding: 2px 9px; cursor: pointer; flex: 0 0 auto; }
.gen-interrupt:hover { background: color-mix(in srgb, var(--danger) 18%, transparent); }
@keyframes pulse { 50% { opacity: .25; } }
/* minibar: rendered-segment overview strip + scrub */
.pm-minibar { height: 14px; flex: 0 0 auto; display: flex; position: relative; background: var(--ink-2); border-top: 1px solid var(--line); cursor: col-resize; user-select: none; }
.pm-chip { height: 100%; flex-shrink: 0; background: var(--ink-3); border-right: 1px solid var(--ink-2); transition: opacity .1s; }
.pm-chip.rendered { background: linear-gradient(180deg, var(--teal), var(--teal-2)); opacity: .55; }
.pm-chip.rendered.stale { background: linear-gradient(180deg, var(--accent-hi), var(--teal-2)); opacity: .62; }
.pm-chip.pending { background: repeating-linear-gradient(-45deg, var(--ink-3), var(--ink-3) 4px, var(--stripe) 4px, var(--stripe) 8px); opacity: .45; }
.pm-chip.ghost { background: repeating-linear-gradient(-45deg, var(--accent-dim), var(--accent-dim) 4px, var(--accent-dim-2) 4px, var(--accent-dim-2) 8px); opacity: .65; }
.pm-chip.gap { background: repeating-linear-gradient(-45deg, var(--ink-2), var(--ink-2) 4px, var(--ink-1) 4px, var(--ink-1) 8px); opacity: .35; border-right-style: dashed; }
.pm-chip.mixed { background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 55%, var(--teal-2)), var(--teal-4)); opacity: .72; }
.pm-chip.carry { background: repeating-linear-gradient(-45deg, var(--carry), var(--carry) 3px, var(--carry-2) 3px, var(--carry-2) 6px); opacity: .5; }
.pm-chip.video { background: linear-gradient(180deg, var(--blue-dim), var(--blue-line)); opacity: .7; }
.pm-chip:hover { opacity: 1 !important; }
.pm-slate { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; background: var(--scrim-slate); color: var(--muted); pointer-events: none; text-align: center; padding: 16px; }
.pm-slate-title { font-size: 13px; color: var(--accent-hi); font-family: var(--font-mono); }
.pm-slate-sub { font-size: 11px; color: var(--faint); max-width: 280px; }
.pm-segment-badge { position: absolute; top: 10px; left: 10px; z-index: 3; font-size: 10px; font-family: var(--font-mono); color: var(--accent-hi); background: var(--scrim-3); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line)); border-radius: 12px; padding: 3px 9px; pointer-events: none; }
.pm-needle { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--hi); opacity: .85; transform: translateX(-50%); pointer-events: none; z-index: 2; }
/* transport bar */
.pm-transport { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; padding: 4px 10px; border-top: 1px solid var(--line); background: var(--ink-1); flex-wrap: wrap; }
.pm-tc { font-family: var(--font-mono); font-size: 11px; color: var(--muted); letter-spacing: .4px; margin-left: 4px; }
.pm-sep { width: 1px; height: 18px; background: var(--line); margin: 0 4px; flex: 0 0 auto; }
.pm-anchor-sel { font-size: 12px; padding: 2px 6px; background: var(--ink-3); border: 1px solid var(--line); border-radius: 6px; max-width: 160px; }
.pm-anchor-btn { font-size: 12px; white-space: nowrap; }
/* ───────────────────────── INSPECTOR ───────────────────────── */
.insp-tag { font-size: var(--fs-subhead); line-height: var(--lh-subhead); color: var(--muted); font-weight: 600; }
.insp-hint { font-size: 11px; color: var(--faint); margin: -4px 0 12px; }
.insp-hint.warn { color: var(--accent-hi, var(--accent)); }
.insp-hint .btn { margin-left: 6px; vertical-align: baseline; }
.insp-block { margin-bottom: 16px; }
/* global prompt — first entry in the inspector list (scrolls with content) */
.insp-global { margin: 0 0 14px; padding: 10px 10px 8px;
background: var(--ink-2); border: 1px solid var(--line); border-radius: 9px; }
.insp-global-title { font-size: 11px; color: var(--accent); margin-bottom: 6px; font-weight: 600;}
.insp-global-ta { width: 100%; background: var(--ink-0); border: 1px solid var(--line); border-radius: 7px;
color: var(--text); font-size: 12px; padding: 7px 8px; resize: vertical; font-family: var(--font-mono); line-height: 1.45; }
.insp-global .insp-hint { margin: 6px 0 0; }
/* project / scene switch */
.insp-switch { display: flex; gap: 0; margin-bottom: 14px; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.insp-seg { flex: 1; background: var(--ink-1); border: none; color: var(--muted); padding: 7px 0; cursor: pointer;
font-size: 11px; transition: background .12s, color .12s; }
.insp-seg + .insp-seg { border-left: 1px solid var(--line); }
.insp-seg:hover:not(:disabled) { background: var(--ink-3); color: var(--accent-hi); }
.insp-seg.active { background: var(--accent-soft); color: var(--accent-hi); }
.insp-seg:disabled { opacity: .4; cursor: default; }
/* engine context strip (scene view → jump to project engine settings) */
.insp-engine-strip { display: flex; align-items: center; justify-content: space-between; gap: 8px;
margin-bottom: 12px; padding: 7px 10px; background: var(--ink-2); border: 1px solid var(--line); border-radius: 8px; }
.insp-engine-strip-txt { font-size: 11px; color: var(--muted); }
/* collapsible Studio / Chain cards */
.insp-engine { margin: 10px 0 14px; border: 1px solid var(--line); border-radius: 9px; background: var(--ink-2); overflow: hidden; }
.insp-engine-head { width: 100%; display: flex; align-items: center; gap: 8px; padding: 9px 10px;
background: linear-gradient(var(--ink-3), var(--ink-2)); border: none; cursor: pointer;
font-family: var(--font-mono); font-size: 10px; letter-spacing: .8px; text-transform: uppercase; color: var(--accent); text-align: left; }
.insp-engine-head:hover { color: var(--accent-hi); }
.insp-engine-chev { font-size: 11px; color: var(--faint); flex: 0 0 auto; }
.insp-engine-title { flex: 1 1 auto; }
.insp-engine-badge { flex: 0 0 auto; font-size: 9px; letter-spacing: .4px; color: var(--teal);
border: 1px solid var(--teal-soft); border-radius: 4px; padding: 1px 6px; text-transform: none; }
.insp-engine-body { padding: 4px 10px 10px; }
.insp-engine-pickers { margin-bottom: 4px; }
.insp-fold { margin: 6px 0; border: 1px solid var(--line-2); border-radius: 7px; background: var(--ink-0); }
.insp-fold > summary.insp-fold-sum { cursor: pointer; padding: 6px 9px; font-family: var(--font-mono);
font-size: 10px; letter-spacing: .6px; text-transform: uppercase; color: var(--muted); list-style: none; user-select: none; }
.insp-fold > summary.insp-fold-sum::-webkit-details-marker { display: none; }
.insp-fold > summary.insp-fold-sum::before { content: "▸ "; color: var(--faint); }
.insp-fold[open] > summary.insp-fold-sum::before { content: "▾ "; }
.insp-fold-body { padding: 2px 9px 8px; }
.insp-fold-body .insp-hint { margin: 4px 0 0; }
/* read-only length/fps value when inheriting */
.len-readout { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--muted); padding: 6px 8px;
background: var(--ink-0); border: 1px dashed var(--line); border-radius: 7px; }
/* locked trim handle (scene length is Custom) */
.clip-trim.locked { cursor: not-allowed; }
.clip-trim.locked::after { opacity: 1; background: var(--accent); height: 14px; }
.chk { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--muted); cursor: pointer; }
.chk input { width: auto; }
.split-pv { background: var(--ink-0); border: 1px solid var(--line); border-radius: 8px; padding: 10px; }
.pv-line { display: flex; gap: 8px; align-items: baseline; padding: 3px 0; font-size: 12px; }
.pv-badge { font-family: var(--font-mono); font-size: 9px; letter-spacing: .5px; text-transform: uppercase; color: var(--teal); border: 1px solid color-mix(in srgb, var(--teal) 33%, transparent); border-radius: 4px; padding: 1px 5px; flex: 0 0 auto; }
.pv-badge.anchor { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 33%, transparent); }
.pv-badge.postfix { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 33%, transparent); }
.pv-badge.trans { color: var(--faint); border-color: transparent; font-size: 9px; }
.pv-badge.rkey { color: var(--violet-5); border-color: color-mix(in srgb, var(--violet-5) 33%, transparent); text-transform: none; letter-spacing: 0; }
.pv-badge.rkey.default { color: var(--faint); border-color: var(--overlay-4); }
.sync-preview-btn { margin-top: 8px; width: 100%; }
/* Sampler panel (sp-*) */
.insp-tag.sp-sub { font-size: 9px; margin-top: 8px; background: var(--ink-2); }
.sp-macro { border: 1px solid color-mix(in srgb, var(--blue-macro) 25%, transparent); border-radius: 6px; background: color-mix(in srgb, var(--blue-macro) 6%, transparent); padding: 8px; margin: 6px 0; }
.sp-macro-title { font-weight: 600; font-size: 11px; margin-bottom: 6px; color: var(--teal); }
.sp-macro-presets { display: flex; gap: 6px; margin-bottom: 6px; }
.sp-macro-slider { display: flex; align-items: center; gap: 8px; }
.sp-macro-slider input[type=range] { flex: 1; }
.sp-macro-val { font-family: var(--font-mono); font-size: 11px; color: var(--muted); min-width: 32px; }
.pv-warn { color: var(--accent-hi); font-size: 12px; display: flex; gap: 7px; margin-bottom: 8px; }
.pv-raw { margin-top: 8px; }
.pv-raw summary { cursor: pointer; color: var(--faint); font-size: 11px; font-family: var(--font-mono); }
.pv-raw pre { white-space: pre-wrap; background: var(--ink-2); border-radius: 6px; padding: 8px; font-size: 11px; font-family: var(--font-mono); color: var(--muted); margin: 6px 0 0; }
/* ───────────────────────── TIMELINE (NLE) ───────────────────────── */
.timeline .zone-body { padding: 0; display: flex; flex-direction: column; }
/* Buttons no longer wrap their own labels, so the ROW wraps instead when it runs out
of width — the toolbar gets a second line rather than a row of ragged chips. */
.tl-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2);
padding: var(--sp-1) var(--sp-2); border-bottom: 1px solid var(--line); flex: 0 0 auto; }
.tl-toolbar .btn:disabled { opacity: 0.42; pointer-events: none; cursor: default; }
.tl-toolbar .btn.ghost:disabled:hover { color: var(--muted); background: transparent; border-color: transparent; }
.tl-toolbar .tl-spacer { flex: 1; }
.tl-tc { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.tl-zlabel { font-size: 11px; color: var(--faint); font-weight: 600;}
.tl-keys { font-size: 11px; color: var(--faint); margin-right: 10px; opacity: .8; }
.tl-notice { margin-left: 12px; font-size: 11px; color: var(--accent-hi); display: inline-flex; align-items: center; gap: 6px; }
.tl-notice-dismiss { border: none; background: transparent; color: var(--faint); cursor: pointer; font-size: 11px; padding: 0 2px; }
.tl-notice-dismiss:hover { color: var(--text); }
.slot-picker-input { width: 100%; box-sizing: border-box; margin: 8px 0 12px; padding: 8px 10px; background: var(--ink-2); border: 1px solid var(--line); border-radius: 6px; color: var(--text); font-size: 13px; }
.slot-picker-actions { display: flex; gap: 8px; justify-content: flex-end; }
.tl-rating-block { display: inline-flex; align-items: center; gap: 8px; margin-left: 4px; padding-left: 8px; border-left: 1px solid var(--line); }
.tl-rate-btn { color: var(--accent-hi); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-rate-btn.has-rating { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); background: color-mix(in srgb, var(--accent-soft) 30%, var(--ink-2)); }
/* Studio-style rating picker (Movie Editor) */
.me-rating-picker {
position: fixed; z-index: 10001; width: 340px;
background: var(--popup); border: 1px solid var(--popup-line);
border-radius: 8px; box-shadow: 0 16px 48px color-mix(in srgb, var(--shadow-ink) 64.7%, transparent);
color: var(--text); font: 12px var(--font-sans); box-sizing: border-box; overflow: hidden;
}
.me-rating-picker * { box-sizing: border-box; }
.me-rating-picker-head {
display: flex; justify-content: space-between; align-items: center;
padding: 9px 12px 8px; border-bottom: 1px solid var(--overlay-2);
font-weight: 700; font-size: 13px;
}
.me-rating-picker-close {
background: none; border: none; color: var(--faint); cursor: pointer;
font-size: 16px; padding: 0 2px; line-height: 1;
}
.me-rating-picker-close:hover { color: var(--text); }
.me-rating-section { padding: 8px 10px 6px; border-bottom: 1px solid var(--overlay-1); }
.me-rating-section-label {
font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.8px;
color: color-mix(in srgb, var(--accent) 90%, transparent); margin-bottom: 6px;
}
.me-rating-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.me-rating-grid-pos { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.me-rating-opt-wrap { display: flex; gap: 3px; align-items: stretch; }
.me-rating-opt-wrap .me-rating-opt { flex: 1; }
.me-rating-opt {
background: var(--overlay-1); border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
border-radius: 6px; padding: 7px 8px; cursor: pointer; text-align: left; color: var(--text);
transition: background 0.1s, border-color 0.1s; display: flex; flex-direction: column; gap: 3px;
}
.me-rating-opt:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: color-mix(in srgb, var(--accent) 55%, transparent); color: var(--hi); }
.me-rating-opt.active { background: color-mix(in srgb, var(--accent) 18%, transparent); border-color: color-mix(in srgb, var(--accent) 70%, transparent); color: var(--hi); }
.me-rating-opt-label { font-size: 11px; font-weight: 600; line-height: 1.2; }
.me-rating-opt-reward { font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums; }
.me-rating-opt-hint { font-size: 9px; color: var(--faint); line-height: 1.3; }
.me-rating-opt:hover .me-rating-opt-hint { color: var(--muted); }
.me-rating-heart {
flex-shrink: 0; width: 26px; padding: 0;
background: var(--overlay-1); border: 1px solid color-mix(in srgb, var(--pink) 20%, transparent);
border-radius: 6px; color: color-mix(in srgb, var(--pink) 50%, transparent); cursor: pointer;
font-size: 13px; transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.me-rating-heart:hover { background: color-mix(in srgb, var(--pink) 12%, transparent); border-color: color-mix(in srgb, var(--pink) 60%, transparent); color: var(--pink-hi); }
.me-rating-heart.active { background: color-mix(in srgb, var(--pink) 20%, transparent); border-color: color-mix(in srgb, var(--pink) 80%, transparent); color: var(--pink-hi); }
.me-rating-nuclear { padding: 8px 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
.tl-scroll { flex: 1; overflow-x: auto; overflow-y: auto; position: relative; }
.tl-stage { display: flex; flex-direction: row; height: 100%; min-height: 100%; }
.tl-gutter { flex: 0 0 auto; position: sticky; left: 0; z-index: 7; display: flex; flex-direction: column;
background: var(--ink-1); border-right: 1px solid var(--line-2); }
.tl-gutter-ruler { flex: 0 0 24px; border-bottom: 1px solid var(--line);
position: sticky; top: 0; z-index: 9; background: var(--ink-1); }
.tl-gutter-tracks { flex: 0 0 auto; display: flex; flex-direction: column; }
.tl-gutter-lane { display: flex; align-items: center; justify-content: center; text-align: center;
padding: 0 4px; font-size: 11px; color: var(--faint); border-bottom: 1px solid var(--line-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
box-sizing: border-box; flex: 0 0 auto; }
.tl-gutter-lane.video { color: var(--faint); }
.tl-gutter-aud { flex: 0 0 auto; border-top: 1px solid var(--line); }
.tl-gutter-aud .tl-gutter-lane:last-child { border-bottom: none; }
.tl-content { position: relative; flex: 1 1 auto; min-height: 100%; }
/* ruler */
.tl-ruler2 { position: sticky; top: 0; z-index: 8; height: 24px; flex: 0 0 24px; border-bottom: 1px solid var(--line); cursor: pointer;
background: var(--ink-0); user-select: none; }
.tl-tick { position: absolute; top: 0; bottom: 0; border-left: 1px solid var(--line-2); }
.tl-tick-label { position: absolute; left: 4px; top: 4px; font-family: var(--font-mono); font-size: 10px; color: var(--faint); white-space: nowrap; }
/* tracks area (video + audio lanes) */
.tl-tracks { position: relative; flex: 0 0 auto; display: flex; flex-direction: column; }
.tl-track2 { position: relative; flex: 0 0 auto; box-sizing: border-box; padding: 12px 0; }
.tl-audio-lanes { flex: 0 0 auto; border-top: 1px solid var(--line); background: var(--ink-0); }
.tl-audio-head { display: flex; align-items: center; gap: 10px; padding: 4px 10px; border-bottom: 1px solid var(--line-2); flex-wrap: wrap; }
.tl-audio-head .chk { font-size: 11px; }
.tl-audio-add { font-size: 12px; padding: 2px 6px; max-width: 200px; }
.tl-audio-lane { position: relative; flex: 0 0 44px; height: 44px; box-sizing: border-box; border-bottom: 1px solid var(--line-2); }
.tl-audio-lane.orig-lane { background: color-mix(in srgb, var(--teal) 4%, var(--ink-0)); }
.tl-audio-lane.overlay-lane { background: color-mix(in srgb, var(--blue) 5%, var(--ink-0)); }
.tl-gutter-lane.orig { color: var(--teal-soft); }
.tl-gutter-lane.overlay { color: var(--blue-2); }
.tl-aud-clip.overlay { border-color: color-mix(in srgb, var(--blue) 35%, var(--line)); }
.tl-aud-clip.overlay .tl-aud-wave canvas { opacity: .95; }
.tl-audio-lane:last-child { border-bottom: none; }
/* overlay graphics lane (text + images) */
.tl-overlay-lanes { flex: 0 0 auto; border-top: 1px solid var(--line); }
.tl-overlay-lane { position: relative; flex: 0 0 40px; height: 40px; box-sizing: border-box; border-top: 1px solid var(--overlay-1); background: color-mix(in srgb, var(--violet) 4%, var(--ink-0)); }
.tl-overlay-lane.top { background: color-mix(in srgb, var(--violet) 7%, var(--ink-0)); }
.tl-overlay-lane.drop-target { background: color-mix(in srgb, var(--violet) 14%, var(--ink-0)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--violet) 33%, transparent); }
.tl-overlay-lane-body { position: absolute; inset: 0; }
.tl-gutter-ov { flex: 0 0 auto; border-top: 1px solid var(--line); }
.tl-gutter-lane.overlay { color: var(--violet-2); font-size: 10px; flex-direction: row; gap: 2px; padding: 0 3px; justify-content: space-between; }
.tl-gutter-lane.overlay.top { color: var(--violet-3); font-weight: 600; }
.tl-gutter-ov-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
.tl-gutter-ov-rm {
flex: 0 0 16px; width: 16px; height: 16px; padding: 0; border: none; border-radius: 3px;
background: transparent; color: var(--violet-2); font-size: 10px; line-height: 1; cursor: pointer; opacity: .75;
}
.tl-gutter-ov-rm:hover { opacity: 1; background: color-mix(in srgb, var(--danger) 25%, transparent); color: var(--danger-hi); }
.insp-layer-actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
.tl-ov-clip {
position: absolute; top: 4px; bottom: 4px; min-width: 40px;
border-radius: 6px; border: 1px solid color-mix(in srgb, var(--violet) 40%, var(--line));
background: color-mix(in srgb, var(--violet) 12%, var(--ink-1));
cursor: grab; overflow: hidden;
}
.tl-ov-clip.selected { border-color: var(--violet); box-shadow: 0 0 0 1px color-mix(in srgb, var(--violet) 45%, transparent); }
.tl-ov-clip.trimming { cursor: ew-resize; }
.tl-ov-clip.text { font-family: var(--font-ui); font-weight: 600; font-size: 11px; color: var(--violet-4); }
.tl-ov-body { position: absolute; inset: 0 8px; display: flex; align-items: center; padding: 0 4px; pointer-events: none; }
.tl-ov-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-ov-trim { position: absolute; top: 0; bottom: 0; width: 8px; cursor: ew-resize; z-index: 2; }
.tl-ov-trim.left { left: 0; }
.tl-ov-trim.right { right: 0; }
.tl-ov-trim::after {
content: ""; position: absolute; top: 50%; transform: translateY(-50%); width: 2px; height: 18px;
background: color-mix(in srgb, var(--violet) 55%, var(--faint)); border-radius: 2px; opacity: 0;
transition: opacity .12s;
}
.tl-ov-trim.left::after { left: 2px; }
.tl-ov-trim.right::after { right: 2px; }
.tl-ov-clip:hover .tl-ov-trim::after, .tl-ov-clip.trimming .tl-ov-trim::after { opacity: 1; }
.tl-ov-rm {
position: absolute; top: 2px; right: 2px; z-index: 3; width: 18px; height: 18px; padding: 0;
border: none; border-radius: 4px; background: var(--scrim-media-2); color: var(--violet-4); font-size: 11px;
line-height: 1; cursor: pointer; opacity: 0; transition: opacity .12s;
}
.tl-ov-clip:hover .tl-ov-rm, .tl-ov-clip.selected .tl-ov-rm { opacity: 1; }
.tl-ov-rm:hover { background: var(--danger); color: var(--hi); }
.pm-overlays { position: absolute; z-index: 4; pointer-events: none; overflow: hidden; box-sizing: border-box; }
.pm-ov-box {
position: absolute; pointer-events: auto; cursor: grab; max-width: 92%; text-align: center;
text-shadow: 0 1px 4px var(--scrim-media-3); white-space: pre-wrap; line-height: 1.15;
border: 1px dashed transparent; border-radius: 4px; padding: 2px 4px;
transform: translate(-50%, -50%); transform-origin: center center;
}
.pm-ov-box.selected { border-color: color-mix(in srgb, var(--violet) 70%, transparent); }
.pm-ov-box.dragging { cursor: grabbing; opacity: .92; }
.pm-ov-box img { display: block; max-height: 70vh; pointer-events: none; }
.pm-ov-handles { position: absolute; inset: -5px; pointer-events: none; }
.pm-ov-handle {
position: absolute; width: 9px; height: 9px; border-radius: 2px; pointer-events: auto;
background: var(--violet); border: 1px solid var(--hi); box-shadow: 0 0 0 1px color-mix(in srgb, var(--shadow-ink) 41.2%, transparent);
}
.pm-ov-handle.nw { top: 0; left: 0; cursor: nwse-resize; }
.pm-ov-handle.ne { top: 0; right: 0; cursor: nesw-resize; }
.pm-ov-handle.sw { bottom: 0; left: 0; cursor: nesw-resize; }
.pm-ov-handle.se { bottom: 0; right: 0; cursor: nwse-resize; }
.pm-ov-flip-bar {
position: absolute; left: 50%; top: -30px; transform: translateX(-50%);
display: flex; gap: 4px; pointer-events: auto;
}
.pm-ov-flip-btn {
width: 24px; height: 22px; padding: 0; border: 1px solid color-mix(in srgb, var(--violet) 40%, var(--line));
border-radius: 5px; background: var(--scrim-media); color: var(--violet-3); font-size: 13px; line-height: 1; cursor: pointer;
}
.pm-ov-flip-btn:hover, .pm-ov-flip-btn.active { background: color-mix(in srgb, var(--violet) 25%, var(--scrim-media)); border-color: var(--violet); }
.ov-keep-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.ov-keep-row input { accent-color: var(--violet); }
.ov-flip-row { display: flex; gap: 8px; flex-wrap: wrap; }
.ov-flip-row .btn.active { border-color: var(--violet); color: var(--violet-3); }
.insp-layer-actions .btn.active { border-color: var(--violet); color: var(--violet-3); }
/* overlay settings modals */
.ov-modal-overlay { align-items: center; padding: 24px 16px; }
.ov-modal { width: min(420px, 94vw); max-height: min(88vh, 720px); border-radius: 16px; border-color: color-mix(in srgb, var(--violet) 18%, var(--line)); box-shadow: 0 24px 64px color-mix(in srgb, var(--shadow-ink) 64.7%, transparent); }
.ov-modal.ov-modal-md { width: min(560px, 94vw); }
.ov-modal-head { display: flex; align-items: flex-start; gap: 12px; padding: 18px 20px 14px; border-bottom: 1px solid var(--line); background: linear-gradient(180deg, color-mix(in srgb, var(--violet) 6%, var(--surface-raised-6)), var(--surface-deep-5)); }
.ov-modal-head-text { flex: 1; min-width: 0; }
.ov-modal-title { font-family: var(--font-display); font-weight: 700; font-size: 18px; letter-spacing: -.01em; }
.ov-modal-sub { margin-top: 4px; font-size: 12px; line-height: 1.45; color: var(--muted); }
.ov-modal-close { flex: 0 0 32px; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--muted); font-size: 22px; line-height: 1; cursor: pointer; }
.ov-modal-close:hover { background: var(--overlay-2); color: var(--text); }
.ov-modal-body { padding: 18px 20px; overflow: auto; display: flex; flex-direction: column; gap: 16px; }
.ov-modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 20px 18px; border-top: 1px solid var(--line); background: var(--surface-deep-2); }
.ov-form { display: flex; flex-direction: column; gap: 12px; }
.ov-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.ov-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ov-field.full { grid-column: 1 / -1; }
.ov-label { font-size: 11px; color: var(--muted); font-weight: 600;}
.ov-input, .ov-textarea { width: 100%; box-sizing: border-box; border: 1px solid var(--line); border-radius: 10px; background: var(--ink-2); color: var(--text); padding: 10px 12px; font: inherit; }
.ov-textarea { min-height: 72px; resize: vertical; line-height: 1.35; }
.ov-input:focus, .ov-textarea:focus, .ov-color:focus { outline: none; border-color: color-mix(in srgb, var(--violet) 45%, var(--line)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--violet) 12%, transparent); }
.ov-color { width: 100%; height: 40px; padding: 4px; cursor: pointer; border-radius: 10px; border: 1px solid var(--line); background: var(--ink-2); }
.ov-range-field { gap: 8px; }
.ov-range-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ov-range-val { font-family: var(--font-mono); font-size: 11px; color: var(--violet-2); }
.ov-range { width: 100%; accent-color: var(--violet); }
.ov-text-preview { border-radius: 12px; border: 1px solid var(--line); background: radial-gradient(ellipse at center, var(--ov-preview-1) 0%, var(--ov-preview-2) 72%); min-height: 96px; display: grid; place-items: center; padding: 20px; }
.ov-text-preview-inner { max-width: 100%; white-space: pre-wrap; word-break: break-word; }
/* Extra text-style controls (bold/italic/align toggles, outline, shadow, box) */
.ov-textstyle { display: flex; flex-direction: column; gap: 12px; margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--line); }
.ov-style-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ov-align-group { display: inline-flex; gap: 4px; margin-left: auto; }
.ov-style-btn { width: 34px; height: 32px; display: grid; place-items: center; border-radius: 8px; border: 1px solid var(--line);
background: var(--ink-2); color: var(--muted); cursor: pointer; font-size: 13px; font-weight: 700; }
.ov-style-btn:hover { border-color: color-mix(in srgb, var(--violet) 40%, var(--line)); color: var(--text); }
.ov-style-btn.active { border-color: var(--violet); color: var(--violet-3); background: color-mix(in srgb, var(--violet) 12%, var(--ink-2)); }
.ov-check { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); height: 40px; }
.ov-check input { accent-color: var(--violet); }
.ov-checklist { display: flex; flex-direction: column; gap: 2px; max-height: 220px; overflow-y: auto; border: 1px solid var(--line); border-radius: 10px; padding: 4px 8px; background: var(--ink-2); }
.ov-modal-wide { width: min(560px, 92vw); }
.ov-image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: 10px; }
.ov-image-card { display: flex; flex-direction: column; gap: 6px; padding: 8px; border-radius: 12px; border: 1px solid var(--line); background: var(--ink-2); cursor: pointer; text-align: left; }
.ov-image-card:hover { border-color: color-mix(in srgb, var(--violet) 35%, var(--line)); background: color-mix(in srgb, var(--violet) 5%, var(--ink-2)); }
.ov-image-card.selected { border-color: var(--violet); box-shadow: 0 0 0 1px color-mix(in srgb, var(--violet) 40%, transparent); }
.ov-image-card img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; border-radius: 8px; background: var(--black); display: block; }
.ov-image-name { font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-empty { font-size: 13px; color: var(--muted); line-height: 1.45; }
.tl-audio-lane-body { position: absolute; inset: 0; }
.tl-aud-clip { position: absolute; top: 4px; bottom: 4px; box-sizing: border-box;
background: linear-gradient(180deg, var(--audio-dim), var(--audio-dim-2)); border: 1px solid var(--audio-line); border-radius: 5px;
min-width: 0; overflow: hidden; }
.tl-aud-wave { position: absolute; inset: 0; pointer-events: none; overflow: hidden; border-radius: inherit; }
.tl-aud-wave canvas { display: block; width: 100%; height: 100%; }
.tl-aud-controls { position: absolute; inset: 0; z-index: 1; display: flex; align-items: center; gap: 6px;
padding: 0 8px; background: linear-gradient(90deg, color-mix(in srgb, var(--audio-dim-2) 92%, transparent) 0%, color-mix(in srgb, var(--audio-dim-2) 55%, transparent) 45%, transparent 100%); }
.tl-aud-clip.scene-aud { cursor: pointer; }
.tl-aud-clip.scene-aud.selected { border-color: var(--teal); box-shadow: inset 0 0 0 1px var(--teal-soft); }
.tl-aud-clip.ins { background: linear-gradient(180deg, var(--blue-dim-2), var(--blue-dim-3)); border-color: var(--blue-line); }
.tl-aud-clip.ins .tl-aud-controls { background: linear-gradient(90deg, color-mix(in srgb, var(--blue-dim-3) 92%, transparent) 0%, color-mix(in srgb, var(--blue-dim-3) 55%, transparent) 45%, transparent 100%); }
.tl-aud-clip.sep { background: linear-gradient(180deg, var(--audio-dim-3), var(--audio-dim-4)); border-color: var(--audio-line-2); }
.tl-aud-clip.sep .tl-aud-controls { background: linear-gradient(90deg, color-mix(in srgb, var(--audio-dim-4) 92%, transparent) 0%, color-mix(in srgb, var(--audio-dim-4) 55%, transparent) 45%, transparent 100%); }
.tl-aud-clip.ins.selected, .tl-aud-clip.sep.selected {
border-color: var(--teal);
box-shadow: inset 0 0 0 1px var(--teal-soft);
}
.tl-aud-trim { position: absolute; top: 0; bottom: 0; width: 8px; cursor: ew-resize; z-index: 3; }
.tl-aud-trim.left { left: 0; }
.tl-aud-trim.right { right: 0; }
.tl-aud-trim::after {
content: ""; position: absolute; top: 50%; transform: translateY(-50%);
width: 2px; height: 18px; background: var(--faint); border-radius: 2px; opacity: 0; transition: opacity .12s;
}
.tl-aud-trim.left::after { left: 2px; }
.tl-aud-trim.right::after { right: 2px; }
.tl-aud-clip.ins:hover .tl-aud-trim::after, .tl-aud-clip.ins.trimming .tl-aud-trim::after,
.tl-aud-clip.sep:hover .tl-aud-trim::after, .tl-aud-clip.sep.trimming .tl-aud-trim::after { opacity: 1; }
.tl-aud-name { font-size: 10px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.tl-aud-vol { width: 56px; max-width: 42%; flex: 0 1 56px; min-width: 0; accent-color: var(--teal); }
.tl-aud-rm { flex: 0 0 auto; opacity: 0.9; min-width: 22px; }
.tl-aud-clip.ins:hover .tl-aud-rm,
.tl-aud-clip.sep:hover .tl-aud-rm { opacity: 1; color: var(--danger); }
.tl-emptyhint { position: absolute; left: 16px; top: 20px; color: var(--faint); font-style: italic; }
.clip { position: absolute; top: 12px; bottom: 12px; box-sizing: border-box;
background: linear-gradient(var(--surface-raised-3), var(--surface-raised-4)); border: 1px solid var(--line); border-radius: 8px;
padding: 6px 9px; cursor: pointer; overflow: hidden; display: flex; flex-direction: column; gap: 4px;
transition: border-color .12s, box-shadow .12s; }
.clip::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--accent); opacity: .55; }
.clip:hover { border-color: var(--line-hi); }
.clip:active { cursor: grabbing; }
.clip.spacing { opacity: .85; z-index: 50; cursor: grabbing; box-shadow: 0 6px 18px color-mix(in srgb, var(--shadow-ink) 58.8%, transparent); transition: none; }
body.tl-spacing { cursor: grabbing; user-select: none; }
.clip:not(.ghost) { cursor: grab; }
.clip:not(.ghost).spacing { cursor: grabbing; }
.tl-dropline { position: absolute; top: 6px; bottom: 6px; width: 2px; background: var(--accent);
box-shadow: 0 0 6px 1px color-mix(in srgb, var(--accent) 80%, transparent); z-index: 60; pointer-events: none; }
.tl-dd { position: relative; display: inline-block; }
.tl-dd-panel { position: absolute; top: calc(100% + 4px); left: 0; z-index: 200; min-width: 200px;
background: var(--surface-raised-7); border: 1px solid var(--line); border-radius: 8px; padding: 8px;
display: flex; flex-direction: column; gap: 7px; box-shadow: 0 8px 22px color-mix(in srgb, var(--shadow-ink) 64.7%, transparent); }
.tl-dd-panel[hidden] { display: none; }
.tl-dd-head { font-size: 11px; color: var(--muted); font-weight: 600;}
.tl-dd-sel { width: 100%; }
.tl-dd-val { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; }
.tl-dd-val[hidden] { display: none; }
.tl-dd-val input { width: 78px; }
.aud-track { border: 1px solid var(--line); border-radius: 8px; padding: 8px; margin: 6px 0; background: var(--surface-raised-5); }
.aud-track-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.aud-track-name { font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clip.selected { border-color: var(--teal-soft); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sel) 35%, transparent); z-index: 2; }
.clip.selected::before { background: var(--teal-soft); opacity: 0.85; }
.clip.selected.focus { border-color: var(--teal); box-shadow: inset 0 0 0 1px var(--teal-soft); z-index: 3; }
.clip.selected.focus::before { background: var(--teal); opacity: 1; }
.tl-aud-clip.scene-aud.selected:not(.focus) { border-color: var(--teal-soft); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sel) 35%, transparent); }
.clip.excluded { opacity: .42; }
.clip.excluded::before { background: var(--faint); }
.clip.clip-video { background: linear-gradient(var(--blue-dim-4), var(--blue-dim-5)); border-color: var(--blue-line); }
.clip.clip-video::before { background: var(--blue-4); opacity: .75; }
.clip.clip-video .clip-no { color: var(--blue-3); font-weight: 600; }
.clip.src-v2v::before { background: var(--indigo); }
.tl-track2.drop-target-track { outline: 1px dashed var(--teal); outline-offset: -2px; background: color-mix(in srgb, var(--sel) 4%, transparent); }
.clip.pending:not(.rendered) { border-style: dashed; border-color: color-mix(in srgb, var(--muted) 55%, var(--line)); }
.clip.ghost { border-style: dashed; border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); opacity: .72; cursor: default; }
.clip.ghost::before { background: var(--accent); opacity: .35; }
.clip.ghost .ghost-label { font-style: italic; color: var(--accent-hi); }
.clip.gen-cut::before { background: color-mix(in srgb, var(--teal) 55%, var(--accent)); }
.clip.subclip { border-left: 2px solid color-mix(in srgb, var(--teal) 70%, transparent); }
/* Mixed = full-strength clip with dual anchor+guide accent (not carry-grayed). */
.clip.src-mixed { border-color: color-mix(in srgb, var(--teal-soft) 42%, var(--line)); }
.clip.src-mixed::before { background: linear-gradient(180deg, var(--accent) 0%, var(--accent) 45%, var(--teal-soft) 100%); opacity: .9; }
.clip.src-carry { border-style: dashed; border-color: color-mix(in srgb, var(--teal-soft) 35%, var(--line)); }
.clip.src-carry::before { background: var(--teal-soft); opacity: .45; }
.clip.src-image::before { background: var(--accent); opacity: .7; }
/* Selection must win over source-type border accents (video/rendered clips included). */
.clip.selected,
.clip.selected.src-mixed,
.clip.selected.src-carry,
.clip.selected.src-image,
.clip.selected.src-v2v,
.clip.selected.clip-video,
.clip.selected.rendered,
.clip.selected.clip-video.rendered,
.clip.selected.ghost,
.clip.selected.pending:not(.rendered) {
border-color: var(--teal-soft);
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sel) 35%, transparent), 0 0 0 2px color-mix(in srgb, var(--sel) 28%, transparent);
z-index: 2;
}
.clip.selected.focus,
.clip.selected.focus.src-mixed,
.clip.selected.focus.src-carry,
.clip.selected.focus.src-image,
.clip.selected.focus.src-v2v,
.clip.selected.focus.clip-video,
.clip.selected.focus.rendered,
.clip.selected.focus.clip-video.rendered,
.clip.selected.focus.ghost {
border-color: var(--teal);
box-shadow: inset 0 0 0 1px var(--teal-soft), 0 0 0 2px color-mix(in srgb, var(--sel) 45%, transparent);
z-index: 3;
}
.clip.selected::before,
.clip.selected.src-carry::before,
.clip.selected.clip-video::before,
.clip.selected.src-v2v::before { background: var(--teal-soft); opacity: 0.85; }
.clip.selected.focus::before,
.clip.selected.focus.src-carry::before,
.clip.selected.focus.clip-video::before,
.clip.selected.focus.src-v2v::before { background: var(--teal); opacity: 1; }
.tl-sel-badge {
font-size: 11px; font-weight: 600; color: var(--teal);
background: color-mix(in srgb, var(--teal) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--teal-soft) 55%, var(--line));
border-radius: 10px; padding: 2px 8px; white-space: nowrap; flex-shrink: 0;
}
.clip-src-stack { display: inline-flex; align-items: center; gap: 1px; line-height: 1; }
.clip-anchor-mark { font-size: 11px; color: var(--accent); }
.clip-guide-mark { font-size: 11px; color: var(--teal-soft); margin-left: -1px; }
.clip-src-label { font-size: 9px; font-family: var(--font-mono); color: var(--teal-soft); letter-spacing: .04em; text-transform: uppercase; }
.clip-src.carry-only { font-size: 12px; color: var(--teal-soft); opacity: .85; }
.pm-segment-badge.mixed-mode { color: var(--teal-hi); border-color: color-mix(in srgb, var(--teal-soft) 45%, var(--line)); }
/* a clip that has a rendered video available (in temp) */
.clip.rendered::after { content: "●"; position: absolute; bottom: 5px; right: 10px; top: auto; font-size: 9px;
color: var(--good-2); text-shadow: 0 0 5px color-mix(in srgb, var(--good-2) 70%, transparent); pointer-events: none; z-index: 1; }
.clip.trimming { border-color: var(--accent); z-index: 5; }
.clip-head { display: flex; align-items: center; gap: 6px; min-width: 0; flex-shrink: 0; position: relative; z-index: 2; }
.clip-head-bar { margin-left: auto; display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.clip-no { font-family: var(--font-mono); font-size: 11px; color: var(--accent); font-weight: 600; flex-shrink: 0; }
.clip-src { font-size: 12px; color: var(--faint); flex-shrink: 0; }
.clip-dur { font-family: var(--font-mono); font-size: 10px; color: var(--faint); white-space: nowrap; }
.clip-rm.btn.tiny { min-height: 18px; padding: 0 6px; font-size: var(--fs-footnote); flex-shrink: 0; }
.clip-move.btn.tiny { min-height: 18px; padding: 0 5px; font-size: 9px; flex-shrink: 0; color: var(--muted); }
.clip-move.btn.tiny:hover { color: var(--accent-hi); }
.clip-move.disabled { opacity: .3; cursor: default; pointer-events: none; }
.clip-text { font-size: 12px; line-height: 1.35; color: var(--text); overflow: hidden;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.clip-text.empty { color: var(--faint); font-style: italic; }
.clip-rated { font-size: 10px; font-family: var(--font-mono); font-weight: 600; color: var(--accent-hi); line-height: 1.2;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex-shrink: 0;
padding: 2px 6px; border-radius: 4px;
background: color-mix(in srgb, var(--accent-soft) 35%, transparent);
border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line)); }
.clip.has-media .clip-rated { position: relative; z-index: 1; }
.clip-fx { font-size: 10px; font-family: var(--font-mono); color: var(--muted); line-height: 1.2;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex-shrink: 0; cursor: pointer;
padding: 2px 6px; border-radius: 4px; border: 1px solid var(--line);
background: color-mix(in srgb, var(--line) 30%, transparent); }
.clip-fx:hover { color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.clip.has-media .clip-fx { position: relative; z-index: 1; }
.clip-gen-prompt {
font-size: 10px; line-height: 1.25; flex-shrink: 0; min-height: 0;
border-top: 1px solid color-mix(in srgb, var(--accent) 25%, var(--line));
padding-top: 3px; margin-top: 1px;
}
.clip-gen-prompt-label {
display: block; font-family: var(--font-mono); font-size: 9px; letter-spacing: .4px;
text-transform: uppercase; color: var(--faint); margin-bottom: 1px;
}
.clip-gen-prompt-text {
color: var(--accent-hi); overflow: hidden;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.clip.has-media .clip-gen-prompt { position: relative; z-index: 1; }
.clip.prompt-mismatch { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.clip.anchor-mismatch { border-color: color-mix(in srgb, var(--teal-soft) 42%, var(--line)); }
.clip.stale-render.rendered::after { color: var(--accent-hi); text-shadow: 0 0 5px color-mix(in srgb, var(--accent) 70%, transparent); }
.clip-gen-anchor .clip-gen-prompt-label { color: var(--teal-soft); }
.clip-gen-anchor .clip-gen-prompt-text { color: var(--teal-hi); }
.ic-btn { width: 18px; height: 18px; padding: 0; font-size: 11px; line-height: 1; border: 1px solid var(--line);
background: var(--ink-1); color: var(--muted); border-radius: 4px; cursor: pointer; }
.ic-btn:hover { color: var(--text); border-color: var(--muted); }
.ic-btn.danger:hover { color: var(--danger); border-color: var(--danger); }
.clip-trim { position: absolute; top: 0; right: 0; bottom: 0; width: 8px; cursor: ew-resize; }
.clip-trim::after { content: ""; position: absolute; right: 2px; top: 50%; transform: translateY(-50%); width: 2px; height: 26px; background: var(--faint); border-radius: 2px; opacity: 0; transition: opacity .12s; }
.clip:hover .clip-trim::after, .clip.trimming .clip-trim::after { opacity: 1; }
.trim-tip { position: absolute; bottom: 4px; right: 4px; background: var(--ink-0); border: 1px solid var(--accent);
color: var(--accent); font-family: var(--font-mono); font-size: 10px; padding: 1px 5px; border-radius: 4px; white-space: nowrap; pointer-events: none; }
/* cut line at clip boundaries; transition overlap is on the outgoing clip tail */
.seam-cut {
position: absolute; top: 6px; bottom: 6px; width: 2px;
transform: translateX(-50%); z-index: 3; pointer-events: none;
background: var(--line-2); border-radius: 1px;
}
.seam-cut.has-vt { background: color-mix(in srgb, var(--teal) 55%, var(--line)); }
.tl-seam-gap-handle {
position: absolute; top: 0; bottom: 0; left: 0; width: 10px;
transform: translateX(-50%); cursor: ew-resize; pointer-events: auto;
}
.tl-seam-gap-handle:hover { background: color-mix(in srgb, var(--accent) 25%, transparent); }
/* editorial pause between clips */
.tl-gap {
position: absolute; top: 10px; bottom: 10px; z-index: 1;
background: repeating-linear-gradient(
-45deg,
color-mix(in srgb, var(--ink-2) 85%, transparent),
color-mix(in srgb, var(--ink-2) 85%, transparent) 4px,
color-mix(in srgb, var(--ink-1) 85%, transparent) 4px,
color-mix(in srgb, var(--ink-1) 85%, transparent) 8px
);
border: 1px dashed color-mix(in srgb, var(--faint) 60%, transparent);
border-radius: 4px; box-sizing: border-box; cursor: pointer;
}
.tl-gap:hover, .tl-gap.resizing { border-color: var(--accent); }
.tl-gap-label {
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
font-size: 9px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint);
pointer-events: none; user-select: none;
}
.tl-gap-handle {
position: absolute; top: 0; right: 0; bottom: 0; width: 8px; cursor: ew-resize; z-index: 2;
}
.tl-gap-handle::after {
content: ""; position: absolute; right: 2px; top: 50%; transform: translateY(-50%);
width: 2px; height: 20px; background: var(--accent); border-radius: 2px; opacity: 0.6;
}
.tl-gap:hover .tl-gap-handle::after, .tl-gap.resizing .tl-gap-handle::after { opacity: 1; }
.tl-gap-tip {
position: absolute; bottom: 2px; right: 2px; background: var(--ink-0); border: 1px solid var(--accent);
color: var(--accent); font-family: var(--font-mono); font-size: 10px; padding: 1px 5px;
border-radius: 4px; white-space: nowrap; pointer-events: none; z-index: 3;
}
/* transition tail on the outgoing clip (NLE-style overlap) */
.clip-vt-tail {
position: absolute; top: 0; right: 0; bottom: 0; pointer-events: auto; z-index: 2;
border-top-right-radius: 7px; border-bottom-right-radius: 7px; cursor: ew-resize;
}
.clip-vt-tail.vt-crossfade { background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--teal) 35%, transparent)); }
.clip-vt-tail.vt-fadeblack { background: linear-gradient(90deg, transparent, var(--fade-black)); }
.clip-vt-tail.vt-wipeleft { background: linear-gradient(90deg, transparent 20%, color-mix(in srgb, var(--accent) 40%, transparent)); }
.clip-vt-tail.vt-wiperight { background: linear-gradient(270deg, transparent 20%, color-mix(in srgb, var(--accent) 40%, transparent)); }
/* playhead */
.tl-playhead { position: absolute; top: -24px; bottom: 0; width: 2px; background: var(--teal); z-index: 6; pointer-events: none; }
.tl-playhead::before { content: ""; position: absolute; top: -24px; left: -5px; border: 6px solid transparent; border-top-color: var(--teal); }
.empty-stage { color: var(--faint); padding: 30px; text-align: center; width: 100%; }
/* ── project-menu buttons (Easy Gen) ──────────────────────────────────────
The Editor's welcome card is gone — the full-screen wizard splash is the only
start screen now. Easy Gen's project menu still uses these button styles. */
.welcome-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.welcome-btn {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
text-align: left;
padding: 14px 15px;
border-radius: 11px;
border: 1px solid var(--line);
background: var(--ink-1);
cursor: pointer;
transition: border-color .12s, background .12s, transform .08s;
}
.welcome-btn:hover:not(.disabled) {
border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
background: var(--ink-2);
transform: translateY(-1px);
}
.welcome-btn.primary {
border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
background: color-mix(in srgb, var(--accent) 10%, var(--ink-1));
}
.welcome-btn.primary:hover:not(.disabled) {
background: color-mix(in srgb, var(--accent) 16%, var(--ink-2));
}
.welcome-btn.ghost { opacity: .88; }
.welcome-btn.disabled {
opacity: .45;
cursor: default;
transform: none;
}
.welcome-btn-label { font-weight: 600; font-size: 13px; color: var(--text); }
.welcome-btn.primary .welcome-btn-label { color: var(--accent-hi); }
.welcome-btn-hint { font-size: 11px; color: var(--faint); line-height: 1.35; }
@media (max-width: 520px) {
.welcome-actions { grid-template-columns: 1fr; }
}
/* ───────────────────────── MODALS (Models settings) ───────────────────────── */
.modal-overlay { position: fixed; inset: 0; z-index: 500; background: var(--backdrop); backdrop-filter: blur(3px); display: flex; align-items: flex-start; justify-content: center; padding: 7vh 16px; animation: fade .15s ease; }
@keyframes fade { from { opacity: 0; } }
.modal { width: min(760px, 96vw); max-height: 82vh; display: flex; flex-direction: column; background: var(--surface-modal); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); overflow: hidden; animation: pop .16s ease; }
.modal.modal-wide { width: min(920px, 96vw); }
.modal.modal-mini { width: min(380px, 92vw); }
.engine-modal-content { padding-bottom: 24px; }
.engine-modal-summary { font-size: 12px; color: var(--muted); font-family: var(--font-mono); margin-bottom: 12px; padding: 8px 10px; background: var(--ink-2); border-radius: 8px; border: 1px solid var(--line); }
.modal-head { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--line); background: linear-gradient(var(--surface-pop), var(--surface-pop-2)); }
.modal-title { font-family: var(--font-display); font-weight: 700; font-size: 17px; }
.modal-head-right { margin-left: auto; display: flex; gap: 8px; align-items: center; }
/* Temp files browser */
.tmp-count { white-space: nowrap; }
.tmp-body { margin-top: 12px; }
.tmp-grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
.tmp-card { cursor: default; padding-bottom: 6px; }
.tmp-card .media-thumb { height: 76px; }
.tmp-card .media-name { font-size: 11px; word-break: break-all; }
.tmp-meta { padding: 0 8px; }
.tmp-card-acts { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 8px 0; }
.tmp-card-acts .btn { flex: 1; white-space: nowrap; }
.modal-content { padding: 16px; overflow: auto; }
.composer { background: var(--ink-0); border: 1px solid var(--line); border-radius: 10px; padding: 14px; margin-bottom: 18px; }
.composer.flash { animation: composer-flash .9s ease; }
@keyframes composer-flash { 0%, 100% { box-shadow: none; border-color: var(--line); } 25% { box-shadow: 0 0 0 2px var(--accent); border-color: var(--accent); } }
.composer-title { font-size: 11px; color: var(--accent); margin-bottom: 10px; font-weight: 600;}
.composer-row { display: flex; gap: 10px; align-items: center; }
.composer-row select { flex: 1; }
.composer-row .composer-search { flex: 1.2; min-width: 0; }
.composer-row .btn { flex: 0 0 auto; }
.composer-preview { margin-top: 12px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; }
.composer-preview:empty { display: none; }
/* Global-prompt templates bar (above the prompt) */
.compose-templates { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.compose-templates .compose-tpl-select { flex: 1; min-width: 0; }
.compose-templates .btn { flex: 0 0 auto; }
/* Variables panel (below the prompt) */
.compose-vars { margin-top: 8px; }
.composer-var-toggle { padding-left: 2px; }
.compose-var-hint { margin-top: 4px; }
.compose-var-hint.compose-var-warn { color: var(--accent); }
.compose-var-list { margin-top: 6px; display: flex; flex-direction: column; gap: 6px; }
.compose-var-row { display: flex; gap: 6px; align-items: flex-start; }
.compose-var-row > .compose-var-dollar, .compose-var-row > .compose-var-eq,
.compose-var-row > .btn { margin-top: 5px; }
.compose-var-dollar { color: var(--accent); font-family: var(--font-mono); opacity: 0.8; }
.compose-var-eq { color: var(--muted); }
.compose-var-row .compose-var-name { flex: 0 0 30%; min-width: 0; }
/* Value is an auto-growing textarea (JS sets the height) — no resize handle, no scrollbar. */
.compose-var-row .compose-var-val { flex: 1; min-width: 0; resize: none; overflow: hidden; }
.compose-var-row .btn { flex: 0 0 auto; }
/* config validation banner */
/* Pipeline requirements panel */
.node-search { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; }
.node-search-input { flex: 1 1 auto; min-width: 0; }
.node-search-count { font-family: var(--font-mono); font-size: 11px; color: var(--faint); flex: 0 0 auto; }
/* Node groups: a heading over the flat grid, never a container. */
.node-group { margin-bottom: 10px; }
.node-group-head { display: flex; align-items: center; gap: 8px; width: 100%;
padding: 6px 2px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.node-group-fold { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0;
background: none; border: 0; cursor: pointer; padding: 0; text-align: left;
color: var(--muted); font-size: 11px; font-weight: 600; letter-spacing: .04em;
text-transform: uppercase; }
.node-group-fold:hover { color: var(--fg); }
.node-group-byp { flex: 0 0 auto; }
.node-group-byp.risky { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.node-group-caret { font-family: var(--font-mono); flex: 0 0 auto; }
.node-group-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.node-group-count { font-family: var(--font-mono); color: var(--faint); text-transform: none; }
.node-group-bad { color: var(--danger); text-transform: none; letter-spacing: 0; }
.node-group-field { margin: 10px 0 4px; }
/* Loaders are pinned above everything else: choosing model files is the one step every
project has, and on a big pipeline they used to be scattered among nodes nobody touches. */
.node-group-pinned { margin-bottom: 18px; }
.node-group-pinned .node-group-head { border-bottom-color: color-mix(in srgb, var(--teal) 45%, var(--line)); }
.node-group-pinned .node-group-name { color: var(--teal); }
.node-group-fold.static { cursor: default; }
.node-group-note { font-size: var(--fs-subhead); color: var(--faint); margin: -2px 0 8px; }
/* list inputs: one string widget holding N rows (text encoders, LoRAs) */
.list-field { display: block; margin-bottom: 12px; min-width: 0; }
.list-field-name { display: block; font-size: var(--fs-subhead); line-height: var(--lh-subhead);
color: var(--faint); margin-bottom: 4px; }
.list-rows { display: flex; flex-direction: column; gap: 4px; }
.list-row { display: flex; align-items: center; gap: 6px; min-width: 0; }
.list-row.list-head { font-size: 10px; color: var(--faint); text-transform: uppercase;
letter-spacing: .04em; padding-bottom: 2px; }
.list-cell { flex: 1 1 0; min-width: 0; }
.list-cell input, .list-cell select { width: 100%; min-width: 0; max-width: 100%; }
.list-cell input[type="checkbox"] { width: auto; }
/* the first column is the file/name picker and deserves the room */
.list-row > .list-cell:first-of-type { flex: 3 1 0; }
/* the two gutters are fixed so the header line sits over the columns it names */
.list-ord { display: flex; flex-direction: column; gap: 1px; flex: 0 0 18px; }
.list-rm-head { flex: 0 0 20px; }
.list-row > .wire-rm { flex: 0 0 20px; padding: 0; }
.list-ord > button { padding: 0 3px; line-height: 1; font-size: 8px; }
.list-ord > button:disabled { opacity: .3; cursor: default; }
.list-empty { font-size: 12px; color: var(--faint); }
/* picker mode: the file is the row's identity, its settings trail behind it */
.list-picker .list-row { gap: 8px; }
.list-pick-name { flex: 3 1 0; min-width: 0; text-align: left; overflow: hidden;
text-overflow: ellipsis; white-space: nowrap; font-family: var(--mono, ui-monospace, monospace);
font-size: 12px; color: var(--text); background: var(--surface-raised-4);
border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px; cursor: pointer; }
.list-pick-name:hover { border-color: var(--teal); }
.list-picker .list-cell { flex: 0 0 96px; }
.mn-pick-pop { min-width: 320px; max-width: min(520px, 90vw); }
.mn-pick-search { width: 100%; margin-bottom: 6px; }
.mn-pick-list { max-height: 46vh; overflow: auto; }
.mn-pick-list .mn-role-item { display: flex; justify-content: space-between; gap: 10px;
font-family: var(--mono, ui-monospace, monospace); }
.mn-pick-used { color: var(--faint); font-size: 10px; text-transform: uppercase;
letter-spacing: .04em; align-self: center; }
.mn-pick-empty { padding: 6px 8px; font-size: 12px; color: var(--faint); }
/* inputs a node calls advanced: present, but not in the way of the normal path */
.wire-advanced { margin-top: 4px; }
.wire-advanced > summary { font-size: 11px; color: var(--faint); cursor: pointer;
padding: 2px 0; list-style: none; }
.wire-advanced > summary::before { content: "▸ "; }
.wire-advanced[open] > summary::before { content: "▾ "; }
.req-panel { margin-bottom: 18px; }
.req-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.req-title { font-size: 11px; color: var(--teal); font-weight: 600; }
.req-dismiss { margin-left: auto; background: none; border: 0; cursor: pointer;
color: var(--faint); font-size: 12px; line-height: 1; padding: 2px 4px; border-radius: 4px; }
.req-dismiss:hover { color: var(--fg); background: var(--line); }
.req-collapsed { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.req-collapsed .req-dot { color: var(--danger); }
.req-fold { margin-top: 6px; }
.req-fold-sum { font-size: 11px; color: var(--faint); cursor: pointer; padding: 4px 0; }
.req-opt-head { font-size: 11px; color: var(--faint); margin: 8px 0 4px; font-weight: 600;}
/* One line, never wrapping: the row is a status, not a paragraph. */
.req-row { display: flex; align-items: center; gap: 8px; padding: 5px 10px; border-radius: 6px; margin-bottom: 3px; font-size: 12px; }
.req-row .req-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.req-row.ok { background: color-mix(in srgb, var(--teal) 8%, transparent); }
.req-row.missing { background: color-mix(in srgb, var(--danger) 8%, transparent); border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent); }
.req-row.opt { background: transparent; opacity: 0.7; }
.req-dot { font-family: var(--font-mono); font-weight: 700; flex: 0 0 auto; width: 14px; }
.req-row.ok .req-dot { color: var(--teal); }
.req-row.missing .req-dot { color: var(--danger); }
.req-label { flex: 1; }
.req-type { font-family: var(--font-mono); font-size: 10px; color: var(--faint); flex: 0 0 auto; padding: 1px 5px; border: 1px solid var(--line); border-radius: 3px; }
.req-hint { width: 100%; margin-top: 3px; margin-left: 22px; font-size: 11px; color: var(--muted); }
/* Square, so it reads as an action on the row rather than a second label. */
.req-add { flex: 0 0 auto; width: 20px; height: 20px; padding: 0; line-height: 1;
display: inline-flex; align-items: center; justify-content: center; font-size: 14px; }
.req-empty { color: var(--faint); font-size: 12px; padding: 8px 0; }
.valid-banner { display: flex; align-items: center; gap: 9px; padding: 9px 12px; border-radius: 8px; margin-bottom: 14px; font-size: 12px; border: 1px solid var(--line); }
.valid-banner .valid-dot { font-family: var(--font-mono); font-weight: 700; }
.valid-banner.ok { color: var(--teal); border-color: color-mix(in srgb, var(--teal) 45%, var(--line)); background: color-mix(in srgb, var(--teal) 9%, transparent); }
.valid-banner.warn { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); background: color-mix(in srgb, var(--accent) 9%, transparent); }
.valid-banner.bad { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, var(--line)); background: color-mix(in srgb, var(--danger) 9%, transparent); }
.slot-list { display: flex; flex-direction: column; gap: 12px; }
.slot-card { background: var(--ink-1); border: 1px solid var(--line); border-radius: 10px; padding: 12px; }
.slot-card { border-left: 3px solid var(--accent); }
.slot-card.slot-warn { border-left-color: var(--accent); }
.slot-card.slot-bad { border-color: var(--danger); border-left-color: var(--danger);
background: color-mix(in srgb, var(--danger) 9%, var(--ink-1));
box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger) 35%, transparent); }
.slot-head { display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.slot-card.open .slot-head { margin-bottom: 10px; }
.slot-chev { color: var(--faint); width: 12px; flex: 0 0 auto; font-size: 11px; }
.slot-role { font-weight: 600; }
.slot-node { font-family: var(--font-mono); font-size: 11px; color: var(--muted); background: var(--ink-0); padding: 2px 7px; border-radius: 5px; border: 1px solid var(--line); }
.slot-badge { font-family: var(--font-mono); font-size: 10px; letter-spacing: .5px; text-transform: uppercase; padding: 2px 7px; border-radius: 5px; border: 1px solid; }
.slot-badge.ok { color: var(--teal); border-color: color-mix(in srgb, var(--teal) 50%, var(--line)); }
.slot-badge.warn { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); }
.slot-badge.bad { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 50%, var(--line)); }
.slot-badge.exposed { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.slot-head .btn { margin-left: auto; }
/* single-column settings everywhere in the Settings window: side-by-side fields
(e.g. Engine's Conditioning/Sampler pickers) stack so tiny screens still fit */
.sw-body .insp-engine-pickers { flex-direction: column; gap: 8px; }
/* node page header: long labels/badges wrap instead of pushing bypass/remove out of reach;
actions live in one right-aligned cluster that wraps as a unit */
.node-page .slot-head { flex-wrap: wrap; cursor: default; row-gap: 6px; }
.node-page .slot-head .slot-role { overflow-wrap: anywhere; }
.node-page .slot-head .slot-node { max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.node-page .slot-head .slot-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.node-page .slot-head .slot-actions .btn { margin-left: 0; }
.issue-box { margin-bottom: 10px; display: flex; flex-direction: column; gap: 4px; }
.issue { display: flex; align-items: flex-start; gap: 7px; font-size: 12px; }
.issue-dot { font-family: var(--font-mono); flex: 0 0 auto; }
.issue-error .issue-dot, .issue-error .issue-msg { color: var(--danger); }
.issue-warn .issue-dot, .issue-warn .issue-msg { color: var(--accent); }
.slot-fields { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px 14px; }
/* selects shrink with their track instead of forcing the row wider than the pane
(a select's intrinsic min width is its longest option — e.g. wire labels) */
.slot-fields > label.field { min-width: 0; }
.slot-fields > label.field input, .slot-fields > label.field select { min-width: 0; max-width: 100%; }
.slot-fields label.field, .composer-preview label.field { margin-bottom: 0; }
/* eye toggle: expose a node input to the main editor window */
label.field.with-eye { position: relative; padding-right: 26px; }
.eye-btn { position: absolute; top: 0; right: 0; width: 22px; height: 18px; padding: 0; line-height: 1;
background: transparent; border: 1px solid var(--line); border-radius: 5px; color: var(--faint);
cursor: pointer; font-size: 11px; }
.eye-btn:hover { color: var(--muted); border-color: var(--muted); }
.eye-btn.on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
.eye-btn.link-pick { color: var(--teal); }
.eye-btn.link-pick.on { color: var(--ink-0); background: var(--teal); border-color: var(--teal); }
label.field.linked input, label.field.linked select { opacity: .6; }
.link-tag { position: absolute; top: 0; right: 0; font-size: 9px; color: var(--teal); font-family: var(--font-mono); }
/* linked-inputs section */
.links-section { background: var(--ink-0); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; margin-bottom: 18px; }
.links-head { display: flex; align-items: center; gap: 10px; }
.links-head .composer-title { margin-bottom: 0; }
.links-head-right { margin-left: auto; display: flex; gap: 6px; }
.links-hint, .links-empty { font-size: 11px; color: var(--faint); margin-top: 8px; }
.link-card { margin-top: 10px; padding: 10px; border: 1px solid var(--line); border-left: 3px solid var(--teal); border-radius: 8px; background: var(--ink-1); }
.link-head { display: flex; align-items: center; gap: 8px; }
.link-ico { color: var(--teal); }
.link-name { flex: 1; font-weight: 600; }
.link-head .danger { margin-left: 4px; }
.link-value { margin: 8px 0 0; }
.link-members { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.link-chip { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 10px;
color: var(--muted); background: var(--ink-0); border: 1px solid var(--line); border-radius: 5px; padding: 2px 4px 2px 7px; }
.chip-x { border: none; background: transparent; color: var(--faint); cursor: pointer; font-size: 10px; padding: 0 2px; }
.chip-x:hover { color: var(--danger); }
.wire-box { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line); }
.wire-title { font-size: 11px; color: var(--teal); margin-bottom: 8px; font-weight: 600;}
.wire-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; min-width: 0; }
.wire-out { font-family: var(--font-mono); font-size: 11px; color: var(--muted); flex: 0 0 auto; min-width: 130px; }
.wire-arrow { color: var(--teal); }
.wire-dest { font-family: var(--font-mono); font-size: 11px; color: var(--muted); min-width: 0; overflow-wrap: anywhere; }
.wire-dest.wire-muted { color: var(--faint); opacity: .7; }
.wire-select { flex: 1; min-width: 0; }
.wire-multi { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.wire-multi-row { display: flex; gap: 5px; align-items: center; min-width: 0; }
.wire-multi-row .wire-select { flex: 1; min-width: 0; }
.wire-rm { padding: 1px 5px; color: var(--danger-2); }
.wire-add { align-self: flex-start; }
/* Input-source arrow points left (← instead of →) */
.wire-row .wire-arrow.src { color: var(--accent); }
/* pipeline missing-nodes setup modal */
.pipe-setup-modal { max-width: 520px; width: min(520px, 96vw); }
.pipe-setup-lead { margin: 0 0 12px; color: var(--muted); font-size: 13px; line-height: 1.5; }
.pipe-setup-list { margin: 0 0 12px; padding-left: 18px; color: var(--text); font-size: 13px; }
.pipe-setup-list li { margin: 6px 0; }
.pipe-setup-sub { display: block; font-size: 11px; color: var(--faint); font-family: var(--font-mono); margin-top: 2px; }
.pipe-setup-warn { margin: 10px 0; padding: 8px 10px; border-radius: 6px; font-size: 12px; line-height: 1.45;
background: color-mix(in srgb, var(--accent) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); color: var(--muted); }
.pipe-setup-manual-title { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.pipe-setup-foot { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 16px 16px; border-top: 1px solid var(--line); }
.pipe-setup-hint { margin: 0 0 10px; font-size: 12px; color: var(--muted); line-height: 1.45; }
/* Model family picker — the first question in setup, since it decides which nodes and
which model files everything after it looks for. */
.pipe-setup-family { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.pipe-setup-family-btn { display: block; width: 100%; text-align: left; padding: 10px 12px;
border-radius: 8px; line-height: 1.4; }
.pipe-setup-family-btn.active { border-color: var(--accent); background: var(--accent-soft); }
.pipe-setup-family-title { font-size: 13px; color: var(--text); display: flex; align-items: baseline;
gap: 8px; flex-wrap: wrap; }
.pipe-setup-family-title .pipe-setup-sub { display: inline; margin-top: 0; font-family: inherit;
text-transform: uppercase; letter-spacing: .04em; font-size: 10px; }
.pipe-setup-family-btn .pipe-setup-sub { font-family: inherit; font-size: 11px; color: var(--muted); }
.pipe-setup-readiness { margin: 0 0 14px; padding: 10px 12px; border-radius: 8px;
border: 1px solid var(--line); background: var(--overlay-1); }
.pipe-setup-link { display: inline-block; margin-bottom: 10px; font-size: 12px; }
.restart-card .restart-cancel { margin-top: 4px; }
/* restart overlay */
.restart-overlay { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
background: color-mix(in srgb, var(--ink-0) 88%, transparent); backdrop-filter: blur(3px); }
.restart-card { display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 30px 40px;
background: var(--ink-1); border: 1px solid var(--line); border-radius: 14px; }
.restart-msg { color: var(--muted); text-align: center; white-space: pre-line; font-size: 13px; line-height: 1.5; }
.restart-spin { width: 30px; height: 30px; border-radius: 50%; border: 3px solid var(--line);
border-top-color: var(--accent); animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* staggered zone reveal on load */
.zone { animation: rise .5s both; }
.media { animation-delay: .02s; }
.preview { animation-delay: .08s; }
.inspector { animation-delay: .12s; }
.timeline { animation-delay: .16s; }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } }
.clip-trim-left { left: 0; right: auto; cursor: ew-resize; }
.clip-trim-left.locked { cursor: not-allowed; opacity: .35; }
.clip-filmstrip { position: absolute; left: 0; right: 0; bottom: 2px; height: 14px; display: flex; gap: 1px;
opacity: .75; pointer-events: none; overflow: hidden; border-radius: 0 0 6px 6px; }
.clip-fs-cell { flex: 1; min-width: 0; overflow: hidden; }
.clip-fs-thumb { width: 100%; height: 100%; object-fit: cover; display: block; }
.tl-dd-panel.inline { position: static; box-shadow: none; border: none; padding: 0; margin-top: 6px; }
.tl-add-panel { min-width: 160px; display: flex; flex-direction: column; gap: 2px; padding: 6px; }
.tl-add-row { display: block; width: 100%; text-align: left; padding: 6px 10px; border: none; border-radius: 6px;
background: transparent; color: var(--text); font-size: 12px; cursor: pointer; }
.tl-add-row:hover:not(:disabled) { background: var(--ink-2); }
.tl-add-row:disabled { opacity: .45; cursor: default; }
.tl-dd-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.insp-fold { margin: 8px 0; border: 1px solid var(--line-2); border-radius: 8px; padding: 0 10px 8px; }
.insp-fold-sum { cursor: pointer; font-size: 12px; color: var(--muted); padding: 8px 0; list-style: none; }
.insp-fold-sum::-webkit-details-marker { display: none; }
.engine-preset-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.engine-preset-label { font-size: 11px; color: var(--faint); font-weight: 600;}
.slot-picker-overlay { z-index: 12000; }
.slot-picker-modal { max-width: 420px; }
.slot-picker-list { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; max-height: 50vh; overflow-y: auto; }
.slot-picker-row { display: flex; justify-content: space-between; align-items: center; width: 100%; text-align: left;
padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--ink-0); color: var(--text); cursor: pointer; }
.slot-picker-row:hover { border-color: var(--teal); }
.slot-picker-hint { font-size: 10px; color: var(--teal); font-family: var(--font-mono); }
.slot-picker-input {
width: 100%; box-sizing: border-box; margin: 12px 0;
padding: 8px 10px; font-size: 13px; border-radius: 8px;
border: 1px solid var(--line); background: var(--ink-0); color: var(--text);
}
.slot-picker-actions { display: flex; gap: 8px; justify-content: flex-end; }
/* workflow import wizard */
.wf-body { display: flex; flex-direction: column; gap: 16px; }
.wf-steps { display: flex; flex-wrap: wrap; gap: 8px; font-size: 11px; font-family: var(--font-mono); color: var(--muted); }
.wf-step { padding: 4px 8px; border-radius: 6px; border: 1px solid var(--line); }
.wf-step.active { color: var(--teal); border-color: var(--teal); background: color-mix(in srgb, var(--teal) 8%, transparent); }
.wf-step.done { color: var(--muted); opacity: .7; }
.wf-panel { display: flex; flex-direction: column; gap: 12px; }
.wf-lead { font-size: 13px; color: var(--muted); margin: 0; line-height: 1.45; }
.wf-h3 { margin: 0; font-size: 16px; font-family: var(--font-display); }
.wf-h4 { margin: 8px 0 0; font-size: 13px; color: var(--muted); }
.wf-meta { font-size: 11px; color: var(--muted); font-family: var(--font-mono); }
.wf-warn { font-size: 12px; color: var(--warn); padding: 8px 10px; background: color-mix(in srgb, var(--warn) 8%, transparent); border-radius: 8px; border: 1px solid color-mix(in srgb, var(--warn) 25%, transparent); }
.wf-hint { font-size: 12px; color: var(--muted); padding: 8px 10px; background: var(--ink-2); border-radius: 8px; border: 1px solid var(--line); }
.wf-drop { border: 2px dashed var(--line); border-radius: 12px; padding: 28px; text-align: center; color: var(--muted); cursor: pointer; transition: border-color .15s, background .15s; }
.wf-drop.hover, .wf-drop:hover { border-color: var(--teal); background: color-mix(in srgb, var(--teal) 5%, transparent); }
.wf-paste { width: 100%; box-sizing: border-box; font-family: var(--font-mono); font-size: 11px; padding: 8px; border-radius: 8px; border: 1px solid var(--line); background: var(--ink-0); color: var(--text); resize: vertical; }
.wf-node-list { max-height: 220px; overflow: auto; border: 1px solid var(--line); border-radius: 8px; }
.wf-node-row { display: flex; gap: 10px; padding: 6px 10px; border-bottom: 1px solid var(--line); font-size: 12px; }
.wf-node-row:last-child { border-bottom: none; }
.wf-node-cls { font-family: var(--font-mono); color: var(--teal); min-width: 140px; }
.wf-node-lbl { color: var(--text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wf-link-list { max-height: 120px; overflow: auto; font-size: 11px; font-family: var(--font-mono); color: var(--muted); }
.wf-link-row { padding: 3px 0; }
.wf-bind-list { display: flex; flex-direction: column; gap: 10px; }
.wf-bind-row { display: grid; grid-template-columns: minmax(140px, 1fr) 2fr; gap: 10px; align-items: center; }
.wf-bind-label { font-size: 13px; }
.wf-bind-sel { width: 100%; padding: 6px 8px; border-radius: 8px; border: 1px solid var(--line); background: var(--ink-0); color: var(--text); }
.wf-nav { display: flex; gap: 8px; justify-content: flex-end; margin-top: 8px; }
.wf-summary { margin: 0; padding-left: 18px; font-size: 13px; line-height: 1.6; }
.wf-import-banner { font-size: 12px; color: var(--teal); padding: 8px 10px; background: color-mix(in srgb, var(--teal) 6%, transparent); border: 1px solid color-mix(in srgb, var(--teal) 20%, transparent); border-radius: 8px; margin-bottom: 12px; }
.guided-hint { font-size: 11px; color: var(--muted); margin-bottom: 10px; line-height: 1.45; }
.wire-locked { font-size: 11px; color: var(--faint); font-style: italic; padding: 4px 8px; background: var(--ink-2); border-radius: 6px; border: 1px solid var(--line); }
/* welcome tour (?mode=tour) */
body.tour-mode { overflow: hidden; }
.tour-root { position: fixed; inset: 0; z-index: 200000; pointer-events: none; }
.tour-backdrop { position: absolute; inset: 0; pointer-events: auto; }
.tour-backdrop.faq-mode { background: var(--backdrop-3); }
.tour-spotlight {
position: fixed; border-radius: 10px; pointer-events: none;
box-shadow: 0 0 0 9999px var(--backdrop-4);
border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
transition: top .18s ease, left .18s ease, width .18s ease, height .18s ease;
}
.tour-card {
position: fixed; z-index: 2; pointer-events: auto;
width: min(420px, calc(100vw - 32px));
padding: 16px 18px 14px;
background: linear-gradient(180deg, var(--surface-raised) 0%, var(--surface-pop-2) 100%);
border: 1px solid var(--line);
border-radius: 12px;
box-shadow: var(--shadow);
}
.tour-card.centered { z-index: 3; }
.tour-card-head { margin-bottom: 8px; }
.tour-step-no { font: 10px/1 var(--font-mono); color: var(--faint); text-transform: uppercase; letter-spacing: .06em; }
.tour-card-title { margin: 6px 0 0; font: 700 18px/1.25 var(--font-display); }
.tour-card-body { margin: 0 0 12px; color: var(--muted); font-size: 13px; line-height: 1.55; }
.tour-chapters { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.tour-chapter {
font: 10px/1 var(--font-mono); padding: 4px 8px; border-radius: 999px;
border: 1px solid var(--line); background: var(--ink-0); color: var(--muted); cursor: pointer;
}
.tour-chapter.active { color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent) 35%, transparent); background: var(--accent-soft); }
.tour-nav { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
.tour-banner {
position: fixed; top: calc(var(--menubar-h) + 8px); left: 50%; transform: translateX(-50%);
z-index: 4; pointer-events: auto;
display: flex; align-items: center; gap: 10px;
padding: 6px 10px 6px 14px; border-radius: 999px;
background: var(--backdrop-5); border: 1px solid var(--line);
font-size: 12px; box-shadow: var(--shadow);
}
.tour-banner-label { font-family: var(--font-display); font-weight: 700; color: var(--accent-hi); }
.tour-banner-note { color: var(--muted); font-size: 11px; }
.tour-toast {
position: fixed; bottom: calc(var(--timeline-anchor, var(--timeline-h)) + 20px); left: 50%; transform: translateX(-50%) translateY(8px);
z-index: 200001; pointer-events: none; opacity: 0; transition: opacity .2s, transform .2s;
padding: 10px 14px; border-radius: 10px; max-width: min(480px, 92vw);
background: var(--accent-dim-3); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); color: var(--text); font-size: 12px;
}
.tour-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.tour-faq-card { max-height: min(78vh, 720px); overflow: auto; }
.tour-faq-search {
width: 100%; box-sizing: border-box; margin-bottom: 10px;
padding: 8px 10px; border-radius: 8px; border: 1px solid var(--line);
background: var(--ink-0); color: var(--text);
}
.tour-faq-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.tour-faq-cat { font: 600 11px/1 var(--font-mono); color: var(--teal); text-transform: uppercase; margin-top: 8px; }
.tour-faq-item { border: 1px solid var(--line); border-radius: 8px; background: var(--ink-0); padding: 8px 10px; }
.tour-faq-item summary { cursor: pointer; font-size: 13px; font-weight: 600; }
.tour-faq-item p { margin: 8px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5; }
.tour-faq-empty { color: var(--muted); font-size: 12px; margin: 0; }
/* ───────────────────────── PLAN (legacy) ───────────────────────── */
/* The plan-strip UI is gone; only the off-plan clip marker survives. */
.clip.off-plan { outline: 1px dashed color-mix(in srgb, var(--teal) 45%, transparent); outline-offset: -2px; }
/* ───────────────────────── COMPOSER BUTTON (header) ───────────────────────── */
/* Matches the neighbouring .dock-tab panel toggles (shape, size, typography); the
teal ◆ dot keeps it identifiable as the Composer action. */
.composer-btn {
display: inline-flex; align-items: center; gap: 6px;
background: var(--ink-2); border: 1px solid var(--line); border-radius: 6px;
color: var(--faint); font-size: var(--fs-subhead); line-height: var(--lh-subhead);
padding: 4px var(--sp-2); cursor: pointer; transition: background .12s, color .12s, border-color .12s;
}
.composer-btn:hover { color: var(--muted); border-color: var(--muted); }
.composer-btn .composer-dot { font-size: 9px; color: var(--teal); transform: translateY(-.5px); }
.composer-btn.on {
background: var(--accent-soft); color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
.composer-btn.on .composer-dot { color: var(--teal); filter: drop-shadow(0 0 5px var(--teal-soft)); }
/* ───────────────────────── FLOATING WINDOW (Composer, …) ───────────────────────── */
.fw {
position: fixed; left: 0; top: 0; z-index: 4000;
display: flex; flex-direction: column; overflow: hidden;
background: var(--ink-1); border: 1px solid var(--line); border-radius: 11px;
box-shadow: 0 24px 60px -18px color-mix(in srgb, var(--shadow-ink) 91.8%, transparent), 0 0 0 1px var(--scrim-1);
}
.fw[hidden] { display: none; }
.fw.fw-maxed {
left: 12px !important; top: calc(var(--menubar-h) + 10px) !important;
width: calc(100vw - 24px) !important; height: calc(100vh - var(--menubar-h) - 22px) !important;
border-radius: 11px;
}
.fw-bar {
flex: 0 0 38px; display: flex; align-items: center; gap: 10px; padding: 0 8px 0 13px;
background: linear-gradient(var(--surface-raised-2), var(--surface-raised-9)); border-bottom: 1px solid var(--line);
cursor: move; user-select: none;
}
.fw.fw-maxed .fw-bar { cursor: default; }
.fw-title { display: flex; align-items: baseline; gap: 9px; min-width: 0; }
.fw-dot { color: var(--teal); font-size: 9px; }
.fw-title-text { font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: .2px; }
.fw-sub { font-size: 11px; color: var(--faint); font-weight: 600;}
.fw-ctrls { margin-left: auto; display: flex; gap: 4px; }
.fw-btn {
width: 24px; height: 24px; display: grid; place-items: center; padding: 0;
background: transparent; border: 1px solid transparent; border-radius: 6px;
color: var(--muted); font-size: 12px; line-height: 1; cursor: pointer; transition: background .12s, color .12s, border-color .12s;
}
.fw-btn:hover { background: var(--ink-3); color: var(--text); border-color: var(--line); }
.fw-close:hover { background: color-mix(in srgb, var(--danger) 22%, transparent); color: var(--danger); border-color: var(--danger); }
.fw-body { flex: 1; min-height: 0; overflow: hidden; display: flex; }
.fw-grip {
position: absolute; right: 0; bottom: 0; width: 16px; height: 16px; cursor: nwse-resize;
background: linear-gradient(135deg, transparent 50%, var(--line) 50%, var(--line) 64%, transparent 64%, transparent 78%, var(--line) 78%, var(--line) 92%, transparent 92%);
}
.fw.fw-maxed .fw-grip { display: none; }
/* minimized = rolled up to the title bar, in place */
.fw.fw-collapsed { height: auto !important; }
.fw.fw-collapsed .fw-body,
.fw.fw-collapsed .fw-grip { display: none; }
.fw.fw-collapsed .fw-bar { border-bottom: 0; }
/* ───────────────────────── COMPOSER content ───────────────────────── */
.composer-shell { display: flex; flex-direction: column; width: 100%; min-height: 0; }
.composer-tabs { padding: 10px 12px 0; flex: 0 0 auto; }
.composer-scroll { flex: 1; min-height: 0; overflow: auto; padding: 12px; }
.compose-bin { display: flex; flex-direction: column; gap: 8px; height: 100%; }
.compose-ta { flex: 1; min-height: 220px; resize: none; font-family: var(--font-mono); font-size: 12px; line-height: 1.55; }
.lib-cat-tag { margin-left: 8px; padding: 1px 7px; border-radius: 10px; background: var(--teal-soft); color: var(--teal);
font-family: var(--font-mono); font-size: 9px; letter-spacing: .5px; text-transform: uppercase; vertical-align: middle; }
/* + Add ▾ split-button dropdown (Shortcuts / Splits toolbars) */
.composer-add { position: relative; flex-shrink: 0; }
.composer-add-menu { position: absolute; top: calc(100% + 4px); left: 0; z-index: 10; min-width: 150px;
background: var(--surface-modal); border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--shadow); padding: 4px; display: flex; flex-direction: column; }
.composer-add-menu[hidden] { display: none; }
.composer-add-item { text-align: left; background: transparent; border: 0; color: var(--muted); cursor: pointer;
font-family: var(--font-mono); font-size: 11px; padding: 6px 9px; border-radius: 5px; }
.composer-add-item:hover { background: var(--ink-3); color: var(--text); }
/* Compose-tab header row (title + Add shortcut) */
.compose-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
/* Shortcut autocomplete dropdown (anchored under the prompt field) */
.ac-menu { position: fixed; z-index: 99999; max-height: 240px; overflow-y: auto;
background: var(--surface-modal); border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--shadow); padding: 4px; }
.ac-item { display: flex; align-items: baseline; gap: 8px; padding: 6px 9px; border-radius: 5px; cursor: pointer; }
.ac-item.active { background: var(--accent-soft); }
.ac-trigger { color: var(--accent-hi); font-family: var(--font-mono); font-size: 12px; flex-shrink: 0; }
.ac-prompt { color: var(--muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.ac-cat { color: var(--teal); font-family: var(--font-mono); font-size: 9px; letter-spacing: .5px; text-transform: uppercase; flex-shrink: 0; }
/* Shortcut ideas bulb + popover (quiet nudge — lights up when categories go unused) */
.sugg-bulb { padding: 0 4px; font-size: 12px; line-height: 1; opacity: .35; filter: grayscale(1); transition: opacity .3s, filter .3s; }
.sugg-bulb.on { opacity: 1; filter: none; text-shadow: 0 0 7px color-mix(in srgb, var(--accent-hi) 55%, transparent); }
.sugg-fieldwrap { position: relative; }
.sugg-fieldwrap .sugg-bulb { position: absolute; top: -3px; right: 0; }
.sugg-pop { position: fixed; z-index: 99999; width: 330px; max-height: 360px; overflow-y: auto;
background: var(--surface-modal); border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--shadow); padding: 6px; }
.sugg-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 2px 4px 6px; }
.sugg-title { color: var(--muted); font-size: 10px; letter-spacing: .5px; text-transform: uppercase; }
.sugg-list { display: flex; flex-direction: column; }
.sugg-item { display: flex; align-items: baseline; gap: 8px; padding: 6px 9px; border-radius: 5px; cursor: pointer; }
.sugg-item:hover { background: var(--accent-soft); }
.sugg-empty { color: var(--muted); font-size: 11px; padding: 6px 9px; }
.sugg-sec-head { color: var(--accent-hi); font-size: 10px; letter-spacing: .6px; text-transform: uppercase;
padding: 8px 4px 3px; border-top: 1px solid var(--line); margin-top: 4px; }
.sugg-habits:empty { display: none; }
.sugg-habits .sugg-sec-head:first-child, .sugg-list > .sugg-sec-head:first-child { border-top: none; margin-top: 0; }
.sugg-why { color: var(--muted); font-family: var(--font-mono); font-size: 9px; flex-shrink: 0; }
.sugg-cat-head { display: flex; align-items: center; gap: 7px; padding: 7px 4px 2px; }
.sugg-cat-head:first-child { padding-top: 2px; }
.sugg-cat-name { color: var(--teal); font-family: var(--font-mono); font-size: 10px; letter-spacing: .6px; text-transform: uppercase; }
.sugg-cat-count { color: var(--muted); font-size: 9px; font-family: var(--font-mono); background: var(--ink-3); border-radius: 8px; padding: 0 6px; }
.sugg-more { margin-left: auto; font-size: 10px; padding: 0 4px; color: var(--muted); }
/* Editor settings modal */
.es-content { display: flex; flex-direction: column; gap: 18px; }
.es-row { display: flex; flex-direction: column; gap: 5px; }
.es-toggle { font-size: 13px; }
.es-hint { color: var(--muted); font-size: 11px; line-height: 1.45; padding-left: 24px; }
.es-section { display: flex; flex-direction: column; gap: 8px; border-top: 1px solid var(--line); padding-top: 14px; }
.es-section-title { font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: .2px; }
.es-subfields { display: flex; flex-direction: column; gap: 9px; padding-left: 24px; }
/* Add-shortcut picker (Category → [Sub-category →] Shortcut) */
.sc-picker { display: flex; flex-direction: column; gap: 10px; }
.sc-crumb { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; font-family: var(--font-mono); font-size: 11px; }
.sc-crumb-link { background: transparent; border: 0; color: var(--teal); cursor: pointer; padding: 2px 4px; border-radius: 4px; font-family: inherit; font-size: inherit; }
.sc-crumb-link:hover { background: var(--ink-3); color: var(--accent-hi); }
.sc-crumb-sep { color: var(--faint); }
.sc-pick-list { display: flex; flex-direction: column; gap: 4px; max-height: 52vh; overflow-y: auto; }
.sc-pick-folder, .sc-pick-item { display: flex; align-items: baseline; gap: 10px; text-align: left;
background: var(--ink-2); border: 1px solid var(--line); border-radius: 7px; color: var(--text);
cursor: pointer; padding: 9px 12px; font-family: inherit; font-size: 12px; }
.sc-pick-folder:hover, .sc-pick-item:hover { border-color: var(--accent); background: var(--ink-3); }
.sc-pick-folder .sc-pick-name::before { content: "▸ "; color: var(--accent); }
.sc-pick-name { color: var(--text); flex-shrink: 0; }
.sc-pick-prompt { color: var(--muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.sc-pick-count { margin-left: auto; color: var(--faint); font-family: var(--font-mono); font-size: 10px; flex-shrink: 0; }
/* ── unified Settings window (macOS System Settings style) ─────────────── */
.sw-overlay { align-items: center; padding: 4vh 16px; }
.settings-win { width: min(960px, 96vw); height: min(660px, 90vh); display: flex; position: relative;
background: var(--surface-modal); border: 1px solid var(--line); border-radius: 14px;
box-shadow: 0 24px 64px color-mix(in srgb, var(--shadow-ink) 64.7%, transparent); overflow: hidden; animation: pop .16s ease; }
/* Icon rail that expands on hover/focus — overlays the content instead of reflowing it,
so the window works on tiny screens without spending width on labels. */
.sw-side { position: absolute; top: 0; bottom: 0; left: 0; width: 52px; z-index: 5;
display: flex; flex-direction: column; gap: 10px; padding: 12px 9px;
background: var(--surface-deep-4); border-right: 1px solid var(--line); overflow: hidden;
transition: width .16s ease, box-shadow .16s ease; }
.sw-side:hover, .sw-side:focus-within { width: 218px; box-shadow: 18px 0 40px -18px color-mix(in srgb, var(--shadow-ink) 82.4%, transparent); }
.sw-search { width: 100%; min-width: 0; padding: 6px 9px; height: 30px; flex: 0 0 auto;
-webkit-appearance: none; appearance: none;
font: 12.5px var(--font-ui); color: var(--text);
background: var(--ink-2); border: 1px solid var(--line); border-radius: 8px; outline: none; }
.sw-search::-webkit-search-cancel-button { -webkit-appearance: none; }
.sw-search::placeholder { opacity: 0; transition: opacity .16s ease; }
.sw-side:hover .sw-search::placeholder, .sw-side:focus-within .sw-search::placeholder { opacity: 1; }
.sw-search:focus { border-color: var(--accent); }
.sw-nav { flex: 1; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 2px; }
.sw-group-title { margin: 10px 6px 3px; font-size: 10px; font-weight: 700; letter-spacing: .8px;
text-transform: uppercase; color: var(--faint); white-space: nowrap;
opacity: 0; transition: opacity .16s ease; }
.sw-side:hover .sw-group-title, .sw-side:focus-within .sw-group-title { opacity: 1; }
.sw-nav-empty { padding: 12px 8px; font-size: 12px; color: var(--faint); white-space: nowrap; }
.sw-item { display: flex; align-items: center; gap: 9px; padding: 5px 6px; border-radius: 7px;
cursor: pointer; font-size: 13px; color: var(--text); user-select: none; flex: 0 0 auto; }
.sw-item:hover { background: var(--ink-3); }
.sw-item.active { background: linear-gradient(180deg, var(--accent-hi), var(--accent)); color: var(--on-accent-2); font-weight: 600; }
.sw-icon { width: 23px; height: 23px; flex: 0 0 auto; border-radius: 6px; display: grid; place-items: center;
background: linear-gradient(180deg,var(--grip),var(--grip-2));
box-shadow: inset 0 0 0 .5px var(--overlay-4), 0 1px 2px color-mix(in srgb, var(--shadow-ink) 47.1%, transparent); }
.sw-icon svg { display: block; }
.sw-item-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
opacity: 0; transition: opacity .16s ease; }
.sw-side:hover .sw-item-label, .sw-side:focus-within .sw-item-label { opacity: 1; }
.sw-main { flex: 1; min-width: 0; display: flex; flex-direction: column; margin-left: 52px; }
.sw-head { display: flex; align-items: center; gap: 12px; padding: 13px 18px 11px;
border-bottom: 1px solid var(--line); background: linear-gradient(var(--surface-pop), var(--surface-pop-2)); }
.sw-head-text { flex: 1; min-width: 0; }
.sw-head-title { font-family: var(--font-display); font-weight: 700; font-size: 17px; letter-spacing: -.01em; }
.sw-head-sub { margin-top: 1px; font-size: 11px; color: var(--muted); overflow: hidden;
text-overflow: ellipsis; white-space: nowrap; }
.sw-head-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.sw-close { flex: 0 0 auto; }
.sw-body { flex: 1; overflow: auto; padding: 16px 18px 24px; }
/* grouped macOS-style rows (Refinement & Taste, Updates & ComfyUI) */
.sw-stack { display: flex; flex-direction: column; }
.sw-hint { font-size: 11px; line-height: 1.5; color: var(--muted); margin-bottom: 12px; }
.sw-rows-label { margin: 16px 4px 5px; font-size: 10px; font-weight: 700; letter-spacing: .6px;
text-transform: uppercase; color: var(--faint); }
.sw-rows { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 10px;
background: var(--ink-2); overflow: hidden; }
.sw-row { display: flex; align-items: center; gap: 12px; padding: 9px 12px; border-top: 1px solid var(--line); }
.sw-row:first-child { border-top: none; }
.sw-row-main { flex: 1; min-width: 0; }
.sw-row-title { font-size: 13px; color: var(--text); }
.sw-row-hint { margin-top: 1px; font-size: 11px; line-height: 1.4; color: var(--muted); }
.sw-row-value { flex: 0 0 auto; max-width: 45%; font-family: var(--font-mono); font-size: 11px;
color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sw-row .btn { flex: 0 0 auto; }
.sw-led { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; }
.sw-led.ok { background: var(--good); box-shadow: 0 0 6px var(--good); }
.sw-led.bad { background: var(--danger); box-shadow: 0 0 6px var(--danger); }
/* About FunPack ("About This Mac" style) */
.sw-about { display: flex; flex-direction: column; align-items: center; text-align: center;
padding: 34px 20px 10px; gap: 2px; }
.sw-about-mark { font-size: 56px; line-height: 1; color: var(--accent);
text-shadow: 0 0 24px color-mix(in srgb, var(--accent) 45%, transparent); margin-bottom: 10px; }
.sw-about-name { font-family: var(--font-display); font-weight: 700; font-size: 28px; letter-spacing: -.02em; }
.sw-about-codename { font-family: var(--font-display); font-size: 13px; font-style: italic;
color: var(--accent); letter-spacing: .01em; margin-top: 2px; }
.sw-about-sub { font-size: 13px; color: var(--muted); margin-bottom: 18px; }
/* Two-column grid rather than centred rows: values now run from short ("3.14") to long
("NVIDIA RTX PRO 6000 Blackwell · 95.5 GB · sm_120"), and only a shared column keeps
the keys aligned. `display: contents` lets each fact's two spans land in that grid. */
.sw-about-facts { display: inline-grid; grid-template-columns: auto auto; gap: 4px 14px;
align-items: baseline; margin-bottom: 14px; font-size: 12px; }
.sw-about-fact { display: contents; }
.sw-about-k { color: var(--faint); text-align: right; white-space: nowrap; }
.sw-about-v { color: var(--text); font-variant-numeric: tabular-nums; text-align: left;
max-width: 320px; overflow-wrap: anywhere; }
.sw-about-group { grid-column: 1 / -1; margin-top: 12px; padding-bottom: 3px;
border-bottom: 1px solid var(--line);
font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
color: var(--faint); text-align: left; }
.sw-about-hint { max-width: 340px; margin: 0 0 16px; font-size: 11px; color: var(--faint);
line-height: 1.45; text-wrap: balance; }
.sw-about-copy { margin-top: 22px; font-size: 11px; color: var(--faint); }
/* ── Models & Pipeline: inner sidebar layout inside the Settings window ── */
.sw-body.sw-flush { padding: 0; overflow: hidden; display: flex; }
.models-mount { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.models-loading { padding: 16px 18px; }
.models-shell { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.models-cols { flex: 1; min-height: 0; display: flex; }
.models-side { width: 216px; flex: 0 0 auto; overflow: auto; padding: 10px 8px;
border-right: 1px solid var(--line); background: var(--surface-deep-6);
display: flex; flex-direction: column; gap: 2px; }
.models-pane { flex: 1; min-width: 0; overflow: auto; padding: 14px 16px 24px; }
.mn-item { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 7px;
cursor: pointer; user-select: none; min-height: 30px; }
.mn-item:hover { background: var(--ink-3); }
.mn-item.active { background: var(--accent-soft); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent); }
.mn-ico { flex: 0 0 18px; text-align: center; font-size: 12px; }
.mn-dot { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; margin: 0 5px; }
.mn-dot.ok { background: var(--good); }
.mn-dot.warn { background: var(--accent); }
.mn-dot.bad { background: var(--danger); box-shadow: 0 0 5px var(--danger); }
.mn-label { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mn-name { font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mn-sub { font-size: 10px; color: var(--faint); font-family: var(--font-mono);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mn-badge { flex: 0 0 auto; font-size: 10px; color: var(--muted); background: var(--ink-3);
border-radius: 8px; padding: 1px 6px; }
.mn-pencil { flex: 0 0 auto; border: none; background: transparent; color: var(--faint);
font-size: 11px; cursor: pointer; padding: 2px 4px; border-radius: 5px; visibility: hidden; }
.mn-item:hover .mn-pencil { visibility: visible; }
.mn-pencil:hover { background: var(--ink-3); color: var(--accent-hi); }
.mn-sep { height: 1px; background: var(--line); margin: 8px 4px; flex: 0 0 auto; }
.mn-new { display: block; width: 100%; text-align: left; padding: 6px 8px; margin-bottom: 4px;
border: 1px dashed var(--line); border-radius: 7px; background: transparent;
color: var(--muted); font: 12.5px var(--font-ui); cursor: pointer; }
.mn-new:hover { border-color: var(--accent); color: var(--accent-hi); }
.mn-empty { padding: 8px; font-size: 11px; color: var(--faint); }
/* role dropdown under "+ New node" */
.mn-role-pop { position: fixed; z-index: 700; min-width: 220px; max-height: 60vh; overflow: auto;
background: var(--surface-raised-8); border: 1px solid var(--line); border-radius: 10px;
box-shadow: 0 14px 40px color-mix(in srgb, var(--shadow-ink) 70.6%, transparent); padding: 6px; animation: pop .12s ease; }
.mn-role-cat { padding: 6px 8px 2px; font-size: 10px; font-weight: 700; letter-spacing: .6px;
text-transform: uppercase; color: var(--faint); }
.mn-role-item { padding: 5px 8px; border-radius: 6px; font-size: 12px; color: var(--text); cursor: pointer; }
.mn-role-item:hover { background: var(--accent-soft); }
/* link-mode bar (persistent while picking inputs across node pages) */
.models-linkbar { flex: 0 0 auto; display: flex; align-items: center; gap: 10px;
padding: 8px 14px; border-bottom: 1px solid var(--line); background: var(--accent-soft); }
.models-linkbar-txt { flex: 1; min-width: 0; font-size: 12px; color: var(--text);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Setup-node modal */
.ns-modal { width: min(640px, 94vw); }
.ns-content { display: flex; flex-direction: column; gap: 10px; }
.ns-search { width: 100%; padding: 7px 10px; font: 13px var(--font-ui); color: var(--text);
background: var(--ink-2); border: 1px solid var(--line); border-radius: 8px; outline: none; }
.ns-search:focus { border-color: var(--accent); }
.ns-list { max-height: 200px; overflow: auto; border: 1px solid var(--line); border-radius: 8px;
background: var(--ink-1); flex: 0 0 auto; }
.ns-row { display: flex; align-items: baseline; gap: 8px; padding: 6px 10px; cursor: pointer;
border-top: 1px solid var(--line-2); }
.ns-row:first-child { border-top: none; }
.ns-row:hover { background: var(--ink-3); }
.ns-row.active { background: var(--accent-soft); }
.ns-row-name { font-size: 12px; color: var(--text); }
.ns-row-class { font-size: 10px; color: var(--faint); font-family: var(--font-mono);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ns-row-selected { cursor: default; }
.ns-row-selected .ns-row-class { flex: 1; }
.ns-change { margin-left: auto; flex: 0 0 auto; }
.ns-empty { padding: 10px 12px; font-size: 12px; color: var(--faint); }
.ns-detail { display: flex; flex-direction: column; gap: 10px; }
.ns-foot { display: flex; justify-content: flex-end; gap: 8px; padding-top: 4px; }
/* node page header sits flush at the pane top */
.node-page { margin-top: 0; }
/* ── Engine section: category sidebar + macOS row fields ── */
.mn-group { margin: 10px 6px 3px; font-size: 10px; font-weight: 700; letter-spacing: .8px;
text-transform: uppercase; color: var(--faint); white-space: nowrap; flex: 0 0 auto; }
.eng-pane .sw-rows { margin-bottom: 4px; }
.eng-field > input, .eng-field > select { width: auto; min-width: 0; flex: 0 0 auto; }
.eng-field > input[type="number"] { width: 92px; font-family: var(--font-mono); }
.eng-field > input[type="text"] { width: min(46%, 240px); }
.eng-field > select { max-width: 52%; }
.eng-field > input[type="checkbox"] { width: auto; accent-color: var(--accent); transform: scale(1.15); }
.eng-field.eng-stack { flex-direction: column; align-items: stretch; gap: 8px; }
.eng-field.eng-stack > .sw-row-main { width: 100%; }
.eng-empty-row { font-size: 12px; color: var(--faint); }
/* one-line hint by default; the long explanation waits behind this link */
.eng-more { margin-top: 3px; padding: 0; border: 0; background: none; cursor: pointer;
font: inherit; font-size: 11px; color: var(--faint); text-decoration: underline dotted; }
.eng-more:hover { color: var(--accent); }
.eng-detail { margin-top: 4px; padding-left: 8px; border-left: 2px solid var(--line);
color: var(--faint); max-width: 62ch; }
.eng-add { align-self: flex-start; margin-top: 2px; }
.eng-pane .studio-adjust-row { gap: 8px; }
.eng-pane .studio-adjust-row input[type="text"] { min-width: 0; }
.eng-foot { margin-top: 14px; display: flex; align-items: center; gap: 8px; }
.eng-pane .engine-preset-bar { margin-bottom: 10px; }
.eng-sampler-panel { margin-top: 4px; }
/* ── theme picker (Settings ▸ Appearance, and the wizard's theme step) ─────
Each card advertises a palette, so its swatch is painted from LITERAL colours
of that palette — using tokens would make every card look like the theme you
are already in. */
.theme-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.theme-card {
display: flex; flex-direction: column; gap: 10px; align-items: stretch; text-align: left;
padding: 12px; border-radius: 12px; border: 1px solid var(--line);
background: var(--ink-1); cursor: pointer;
transition: border-color .12s, box-shadow .12s, transform .08s;
}
.theme-card:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); transform: translateY(-1px); }
.theme-card.active {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent), 0 8px 22px -14px var(--shadow-ink);
}
.theme-card-title { font-weight: 600; font-size: 13px; color: var(--text); }
.theme-card-hint { font-size: 11px; color: var(--faint); line-height: 1.4; margin-top: 2px; }
.theme-swatch {
position: relative; height: 62px; border-radius: 8px; overflow: hidden;
border: 1px solid var(--line-2); display: block;
}
.theme-swatch-bar { position: absolute; inset: 0 0 auto 0; height: 14px; display: block; }
.theme-swatch-panel { position: absolute; left: 8px; right: 8px; top: 24px; height: 26px; border-radius: 4px; display: block; }
.theme-swatch-accent { position: absolute; left: 8px; bottom: 8px; width: 26px; height: 6px; border-radius: 3px; display: block; }
.theme-swatch-dark { background: #0c0b09; }
.theme-swatch-dark .theme-swatch-bar { background: #16140f; }
.theme-swatch-dark .theme-swatch-panel { background: #1a1814; }
.theme-swatch-dark .theme-swatch-accent { background: #f3a93c; }
.theme-swatch-light { background: #f5f7fa; }
.theme-swatch-light .theme-swatch-bar { background: #f8fafc; }
.theme-swatch-light .theme-swatch-panel { background: #eef1f6; }
.theme-swatch-light .theme-swatch-accent { background: #2f7fd4; }
/* Auto shows both halves — it is not a third palette, it is "whichever the OS says". */
.theme-swatch-auto { background: linear-gradient(105deg, #f5f7fa 0 50%, #0c0b09 50% 100%); }
.theme-swatch-auto .theme-swatch-bar { background: linear-gradient(105deg, #f8fafc 0 50%, #16140f 50% 100%); }
.theme-swatch-auto .theme-swatch-panel { background: linear-gradient(105deg, #eef1f6 0 50%, #1a1814 50% 100%); }
.theme-swatch-auto .theme-swatch-accent { background: linear-gradient(90deg, #2f7fd4, #f3a93c); }
@media (max-width: 620px) { .theme-cards { grid-template-columns: 1fr; } }
/* The film grain is a dark-theme effect: `overlay` blending over a light surface
reads as dirt, not as film stock. */
:root[data-theme="light"] .grain { opacity: .015; mix-blend-mode: multiply; }
/* ── maintenance row (Update / Switch branch / Restart) ───────────────────
On every splash screen, because these are the actions you need BEFORE
opening a project. */
.maint-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.maint-row.welcome-maint { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.maint-btn {
display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left;
padding: 9px 12px; border-radius: 10px; border: 1px solid var(--line);
background: transparent; color: var(--text); cursor: pointer; opacity: .88;
transition: border-color .12s, background .12s, opacity .12s;
}
.maint-btn:hover { opacity: 1; border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); background: var(--ink-2); }
.maint-btn.disabled { opacity: .4; pointer-events: none; }
.maint-btn-label { font-weight: 600; font-size: 13px; }
.maint-btn-hint { font-size: 11px; color: var(--faint); line-height: 1.35; }
@media (max-width: 620px) { .maint-row { grid-template-columns: 1fr; } }
/* ════════════════════════════════════════════════════════════════════════
ONBOARDING WIZARD — macOS Setup Assistant shape
Full screen, no chrome. One centred column per step: glyph, headline,
short paragraph, controls, and an action bar pinned to the bottom so the
primary button never moves between steps.
Type follows Apple's macOS text styles (HIG "Specifications"): Body 13/16,
Callout 12/15, Title 3 15/20, Title 1 22/26, Large Title 26/32 — with a
display scale above them, because Setup Assistant is a full-screen context
and not an inspector.
════════════════════════════════════════════════════════════════════════ */
:root {
--font-system: var(--font-ui);
--oo-col: 560px; /* the centred content column */
--oo-col-wide: 760px; /* steps that hold cards or lists */
}
.oo-root {
/* Below .modal-overlay (500) and .fw (4000) on purpose: Models, Settings and the
Composer open OVER the wizard the same way they open over the editor, and closing
one puts you back on the step you left. Above the menubar (200/300) so the editor
chrome behind stays covered. */
position: fixed; inset: 0; z-index: 400;
display: flex; align-items: center; justify-content: center;
padding: 72px 32px;
background:
radial-gradient(1100px 700px at 50% -15%, color-mix(in srgb, var(--accent) 9%, transparent) 0%, transparent 62%),
var(--ink-0);
font-family: var(--font-system);
-webkit-font-smoothing: antialiased;
overflow-y: auto;
}
/* Back is a chevron in the top-left corner, the way the Setup Assistant does it —
never a button in the action bar, where it would compete with Continue. */
.oo-back {
position: absolute; top: 22px; left: 26px; z-index: 2;
width: 32px; height: 32px; padding: 0 0 3px;
border: 0; border-radius: 50%; background: transparent;
color: var(--muted); font-size: 26px; line-height: 1; cursor: pointer;
transition: background .12s, color .12s;
}
.oo-back:hover { background: var(--ink-2); color: var(--text); }
.oo-back[hidden] { display: none; }
/* Only steps that carry an action bar reserve room for it; the splash has none. */
.oo-root.oo-has-actions { padding-bottom: 140px; }
.oo-stage { width: 100%; display: flex; justify-content: center; }
.oo-stage.oo-in .oo-step, .oo-stage.oo-in .oo-splash { animation: oo-rise .34s cubic-bezier(.22,.61,.36,1) both; }
@keyframes oo-rise { from { opacity: 0; transform: translateY(10px); } }
.oo-step {
width: 100%; max-width: var(--oo-col);
display: flex; flex-direction: column; align-items: center; text-align: center;
}
.oo-step-wide { max-width: var(--oo-col-wide); }
/* ── head: glyph, headline, one short paragraph ─────────────────────────── */
.oo-head { display: flex; flex-direction: column; align-items: center; margin-bottom: 34px; }
.oo-glyph { width: 76px; height: 76px; color: var(--accent); margin-bottom: 22px; }
.oo-title {
margin: 0; font-size: 34px; line-height: 40px; font-weight: 700;
letter-spacing: -.4px; color: var(--text);
}
.oo-sub {
margin: 12px 0 0; max-width: 46ch;
font-size: 15px; line-height: 21px; color: var(--muted);
}
.oo-body { margin: 0 0 18px; font-size: 13px; line-height: 16px; color: var(--muted); }
/* ── action bar, pinned ─────────────────────────────────────────────────── */
.oo-actions {
position: fixed; left: 0; right: 0; bottom: 0; z-index: 3;
display: flex; flex-direction: column; align-items: center; gap: 6px;
padding: 22px 32px 30px;
background: linear-gradient(to top, var(--ink-0) 62%, transparent);
pointer-events: none;
}
.oo-actions > * { pointer-events: auto; }
.oo-btn {
font-family: var(--font-system); font-size: 13px; line-height: 16px; font-weight: 500;
border-radius: 8px; border: 1px solid transparent; cursor: pointer;
padding: 8px 18px; background: transparent; color: var(--text);
transition: background .12s, border-color .12s, opacity .12s, transform .06s;
}
.oo-btn:active:not(.disabled) { transform: scale(.985); }
.oo-btn-primary {
min-width: 220px; padding: 11px 26px;
font-size: 13px; font-weight: 600;
background: var(--accent); border-color: var(--accent); color: var(--on-accent);
box-shadow: 0 1px 3px color-mix(in srgb, var(--shadow-ink) 30%, transparent);
}
.oo-btn-primary:hover:not(.disabled) { background: var(--accent-hi); border-color: var(--accent-hi); }
.oo-btn-primary.disabled { opacity: .38; cursor: default; }
.oo-btn-hero { min-width: 260px; padding: 13px 30px; font-size: 15px; margin-top: 8px; }
.oo-btn-quiet { color: var(--accent); background: transparent; }
.oo-btn-quiet:hover { background: var(--accent-soft); }
.oo-btn-small { padding: 5px 13px; border-color: var(--line); background: var(--ink-1); }
.oo-btn-small:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); }
.oo-busy { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--muted); }
.oo-spinner {
width: 15px; height: 15px; border-radius: 50%; flex: none;
border: 2px solid var(--line); border-top-color: var(--accent);
animation: oo-spin .8s linear infinite;
}
@keyframes oo-spin { to { transform: rotate(360deg); } }
.oo-error { font-size: 13px; line-height: 17px; color: var(--danger); max-width: 46ch; text-align: center; }
/* ── splash ─────────────────────────────────────────────────────────────── */
.oo-splash {
width: 100%; max-width: 620px;
display: flex; flex-direction: column; align-items: center; text-align: center;
}
.oo-splash-mark {
font-size: 34px; color: var(--accent); margin-bottom: 26px;
filter: drop-shadow(0 0 22px var(--accent-soft));
}
.oo-splash-title {
margin: 0; font-size: 56px; line-height: 62px; font-weight: 700;
letter-spacing: -1.4px; color: var(--text);
}
.oo-splash-lead { margin: 14px 0 40px; font-size: 17px; line-height: 22px; color: var(--muted); }
.oo-splash .oo-btn-quiet { margin-top: 4px; }
.oo-maint { margin-top: 48px; width: 100%; max-width: var(--oo-col-wide); }
/* ── fields ─────────────────────────────────────────────────────────────── */
.oo-field { width: 100%; max-width: 420px; text-align: left; margin-bottom: 30px; }
.oo-label {
display: block; margin-bottom: 6px;
font-size: 12px; line-height: 15px; font-weight: 500; color: var(--muted);
}
.oo-input {
width: 100%; padding: 9px 12px;
font-family: var(--font-system); font-size: 13px; line-height: 18px; color: var(--text);
background: var(--ink-1); border: 1px solid var(--line); border-radius: 8px;
}
.oo-input:focus {
outline: none; border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-soft);
}
/* ── choice cards ───────────────────────────────────────────────────────── */
.oo-cards {
width: 100%; display: grid; gap: 12px; margin-bottom: 8px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.oo-cards-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.oo-card {
display: flex; flex-direction: column; gap: 6px; text-align: left;
padding: 16px 17px; border-radius: 12px;
border: 1px solid var(--line); background: var(--ink-1);
font-family: var(--font-system); cursor: pointer;
transition: border-color .12s, box-shadow .12s, transform .08s, background .12s;
}
.oo-card:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); transform: translateY(-1px); }
.oo-card.active {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent), 0 10px 26px -18px var(--shadow-ink);
background: color-mix(in srgb, var(--accent) 5%, var(--ink-1));
}
.oo-card-title { font-size: 15px; line-height: 20px; font-weight: 600; color: var(--text); }
.oo-card-note {
margin-left: 8px; padding: 1px 7px; border-radius: 20px; vertical-align: 2px;
font-size: 10px; line-height: 15px; font-weight: 500;
color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent);
}
.oo-card-sub { font-size: 12px; line-height: 16px; color: var(--muted); }
.oo-theme-cards { width: 100%; margin-bottom: 8px; }
/* ── panels and lists ───────────────────────────────────────────────────── */
.oo-panel {
width: 100%; text-align: left; padding: 18px 20px; margin-bottom: 8px;
border: 1px solid var(--line); border-radius: 12px; background: var(--ink-1);
}
.oo-note { margin: 0 0 12px; font-size: 13px; line-height: 18px; color: var(--text); }
.oo-link { font-size: 12px; line-height: 16px; color: var(--accent); }
.oo-list-label {
margin: 16px 0 7px; font-size: 11px; line-height: 14px; font-weight: 600;
letter-spacing: .4px; text-transform: uppercase; color: var(--faint);
}
.oo-panel > .oo-list-label:first-child { margin-top: 0; }
.oo-list { margin: 0; padding-left: 18px; }
.oo-list li { font-size: 13px; line-height: 18px; color: var(--text); margin-bottom: 5px; }
.oo-list-sub { display: block; font-size: 11px; line-height: 15px; color: var(--faint); font-family: var(--font-mono); }
.oo-rows { width: 100%; display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.oo-row {
display: flex; align-items: center; gap: 16px; text-align: left;
padding: 13px 16px; border: 1px solid var(--line); border-radius: 12px; background: var(--ink-1);
}
.oo-row-main { flex: 1; min-width: 0; }
.oo-row-title { font-size: 13px; line-height: 18px; font-weight: 600; color: var(--text); }
.oo-row-sub { font-size: 12px; line-height: 16px; color: var(--muted); margin-top: 2px; }
/* ── hosted panes ─────────────────────────────────────────────────────────
Models, links, shortcuts and prompt splits, shown as a screen OF the wizard
rather than as a window over it. Wider and taller than a step, left-aligned,
and scrolling inside its own body so the action bar stays put. */
.oo-root.oo-pane-mode { align-items: stretch; padding: 60px 28px 104px; overflow: hidden; }
.oo-root.oo-pane-mode .oo-stage { align-items: stretch; min-height: 0; }
.oo-pane {
display: flex; flex-direction: column; min-height: 0; width: 100%;
max-width: 1040px; margin: 0 auto; text-align: left;
}
.oo-pane-head {
display: flex; align-items: flex-start; gap: 16px;
padding-bottom: 14px; margin-bottom: 4px; border-bottom: 1px solid var(--line);
}
.oo-pane-head-text { flex: 1; min-width: 0; }
.oo-pane-title { margin: 0; font-size: 22px; line-height: 26px; font-weight: 600; letter-spacing: -.3px; color: var(--text); }
.oo-pane-sub { margin: 4px 0 0; font-size: 13px; line-height: 17px; color: var(--muted); }
.oo-pane-tools { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; padding-top: 4px; }
/* The mounted section brings its own scrolling in some cases (Models) and not in
others (Shortcuts, Splits), so the host scrolls and the section may too. */
.oo-pane-body { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: auto; }
.oo-pane-body > * { min-height: 0; }
.oo-projects {
display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: var(--sp-2); padding: var(--sp-3) 0; align-content: start;
}
.oo-project {
display: flex; align-items: center; gap: var(--sp-3); text-align: left;
padding: var(--sp-3); border: 1px solid var(--line); border-radius: 10px;
background: var(--ink-1); color: var(--text); font-family: inherit; cursor: pointer;
transition: border-color .12s, background .12s;
}
.oo-project:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); background: var(--ink-2); }
.oo-project-main { min-width: 0; }
.oo-project-name {
font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 600;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.oo-project-meta { font-size: var(--fs-subhead); line-height: var(--lh-subhead); color: var(--faint); margin-top: 2px; }
@media (max-width: 700px) {
.oo-root { padding: 60px 20px 128px; }
.oo-splash-title { font-size: 40px; line-height: 46px; letter-spacing: -.8px; }
.oo-title { font-size: 27px; line-height: 33px; }
.oo-cards { grid-template-columns: 1fr; }
}
/* ── Models: the node shelf ───────────────────────────────────────────────
A grid of node cards; clicking one opens that node's editor. Leading card
is "+ New node", so adding lives where the nodes are rather than in a
sidebar you have to know about. */
.node-grid {
display: grid; gap: var(--sp-3); margin: var(--sp-1) 0 var(--sp-6);
/* 1fr so the row has no dead strip at its right edge. Safe here only because the art
below is a fixed height — with aspect-ratio, a wide column also made a tall one. */
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.node-card {
display: block; padding: 0;
background: transparent; border: 0; cursor: pointer; text-align: left;
font-family: inherit; color: var(--text);
}
.node-card-art {
position: relative; height: 116px; border-radius: 10px; overflow: hidden;
display: flex; align-items: center; justify-content: center;
background: linear-gradient(160deg, var(--ink-3), var(--ink-1));
border: 1px solid var(--line);
transition: border-color .12s, box-shadow .12s, transform .1s;
}
.node-card:hover .node-card-art {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
box-shadow: 0 12px 26px -16px var(--shadow-ink);
}
.node-card.warn .node-card-art { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.node-card.bad .node-card-art { border-color: color-mix(in srgb, var(--danger) 60%, var(--line)); }
.node-card-mark {
font-family: var(--font-mono); font-size: 10px; line-height: 1.35; font-weight: 500;
color: var(--muted); text-align: center; padding: 6px 9px 42px;
overflow-wrap: anywhere; hyphens: auto;
display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.node-card:hover .node-card-mark { color: var(--text); }
/* FunPack's own nodes: an icon and a plain name where a third-party node shows its class.
The accent tint is the whole point — these read as the built-in, already-wired pieces. */
.node-card-builtin {
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 6px; padding: 4px 9px 42px; text-align: center;
}
.node-card-icon { font-size: 30px; line-height: 1; }
.node-card-kind {
font-size: 11px; font-weight: 600; letter-spacing: .02em; color: var(--text);
overflow-wrap: anywhere;
}
.node-card.built-in .node-card-art {
background: linear-gradient(160deg,
color-mix(in srgb, var(--accent) 14%, var(--ink-3)), var(--ink-1));
border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
}
.node-card.built-in:hover .node-card-art { border-color: color-mix(in srgb, var(--accent) 65%, var(--line)); }
.slot-node.built-in { color: var(--text); font-family: inherit; font-weight: 600; }
.node-card-plus { font-size: 40px; line-height: 1; color: var(--accent); font-weight: 300; }
.node-card-add .node-card-art {
border-style: dashed;
background: color-mix(in srgb, var(--accent) 6%, var(--ink-1));
}
.node-card-flags {
position: absolute; left: 6px; right: 6px; top: 6px;
display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end;
}
.node-flag {
font-family: var(--font-mono); font-size: 9px; letter-spacing: .3px;
padding: 2px 6px; border-radius: 20px;
/* Not --scrim-media: the card art is light in the light theme, so a dark chip with
dark text vanished. This tracks the surface instead. */
background: color-mix(in srgb, var(--ink-0) 84%, transparent);
color: var(--muted); border: 1px solid var(--line);
}
.node-flag.warn { color: var(--accent-hi); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.node-flag.bad { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.node-flag.exposed { color: var(--teal); border-color: color-mix(in srgb, var(--teal) 45%, transparent); }
/* The caption sits ON the tile, over a scrim, so a card reads as one object. */
.node-card-meta {
position: absolute; left: 0; right: 0; bottom: 0; min-width: 0;
padding: 14px 9px 7px;
background: linear-gradient(to top,
var(--ink-1) 0%,
color-mix(in srgb, var(--ink-1) 88%, transparent) 62%,
transparent 100%);
}
.node-card-title {
font-size: 12px; font-weight: 600; line-height: 1.3; color: var(--text);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ── node editor footer: nothing is saved until Save ──────────────────────── */
.node-back { font-size: 20px; line-height: 1; padding: 0 6px 3px; }
.node-foot {
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
position: sticky; bottom: 0; background: var(--ink-1);
}
.node-foot-hint { flex: 1; min-width: 160px; font-size: 11px; color: var(--faint); }
.node-foot-acts { display: flex; gap: 8px; }
.node-foot .btn.primary.disabled, .node-foot .btn.primary:disabled { opacity: .4; cursor: default; }
/* Where a node feeds, on the card itself — the shelf should show how the pipeline is
put together, not just what is in it. */
.node-card-flow {
display: flex; align-items: baseline; gap: 5px; margin-top: 1px;
font-size: 10px; line-height: 1.35; color: var(--teal);
}
.node-card-flow > span:first-child {
min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.node-card-flow.none { color: var(--faint); }
.node-card-more { flex: none; color: var(--faint); }
/* ── Simple mode: one prompt, one Generate, panels on demand ──────────────
Assets and Properties are not rebuilt for this mode — the same zones slide in
over the preview when asked for, and are off-canvas otherwise. */
:root[data-ui-mode="simple"] #media-zone,
:root[data-ui-mode="simple"] #inspector-zone {
position: absolute; top: 0; bottom: 0; z-index: 60;
width: min(340px, 82vw);
box-shadow: 0 0 40px -8px var(--shadow-ink);
transition: transform .18s cubic-bezier(.22,.61,.36,1);
}
:root[data-ui-mode="simple"] #media-zone { left: 0; transform: translateX(-101%); }
:root[data-ui-mode="simple"] #inspector-zone { right: 0; transform: translateX(101%); }
:root[data-ui-mode="simple"] .workspace.show-assets #media-zone,
:root[data-ui-mode="simple"] .workspace.show-props #inspector-zone { transform: none; }
/* Simple mode hides the inspector's folds so the pinned column stays uncluttered — but the
slide-over IS that inspector, opened from a button named "Advanced settings". With the
folds still hidden it opened onto the handful of rows that are not in one, which reads as
the button having done nothing. Asking for the panel is asking for what is in it. */
:root[data-ui-mode="simple"] .workspace.show-props #inspector-zone .insp-fold {
display: block !important;
}
:root[data-ui-mode="simple"] .main-row { position: relative; }
.simple-bar {
flex: 0 0 auto; display: flex; flex-direction: column; gap: var(--sp-2);
padding: var(--sp-3); border-top: 1px solid var(--line); background: var(--ink-1);
}
.simple-bar[hidden] { display: none; }
.simple-prompt {
width: 100%; resize: vertical; min-height: 76px;
font-size: var(--fs-title-3); line-height: 22px;
}
.simple-bar-row { display: flex; gap: var(--sp-2); justify-content: flex-end; }
/* The close lives in the zone head and only exists while the zone is a slide-over. */
.panel-close { margin-left: auto; }
:root:not([data-ui-mode="simple"]) .panel-close { display: none; }
/* ── Settings ▸ Custom Nodes ────────────────────────────────────────────── */
.cn-mount { display: flex; flex-direction: column; gap: var(--sp-3); }
.cn-bar { display: flex; align-items: center; gap: var(--sp-2); }
.cn-busy { font-size: 11px; color: var(--muted); }
.cn-lead { font-size: 13px; color: var(--text); margin-bottom: 6px; }
.cn-hint { font-size: 11px; color: var(--faint); line-height: 1.45; margin-top: 6px;
overflow-wrap: anywhere; }
.cn-modal { max-width: 460px; }
.cn-list { display: flex; flex-direction: column; gap: 4px; }
.cn-row {
display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
padding: 8px 10px; border-radius: 8px;
background: var(--ink-2); border: 1px solid var(--line);
}
.cn-row.self { background: color-mix(in srgb, var(--accent) 10%, var(--ink-2));
border-color: color-mix(in srgb, var(--accent) 30%, var(--line)); }
/* Behind origin — the one row state worth spotting without reading. */
.cn-row.behind { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }
.cn-row-text { min-width: 0; }
.cn-name { font-size: 12px; font-weight: 600; color: var(--text);
overflow-wrap: anywhere; }
.cn-sub { font-size: 10px; color: var(--faint); font-family: var(--font-mono);
margin-top: 2px; overflow-wrap: anywhere; }
.cn-row-acts { display: flex; gap: 4px; flex-shrink: 0; }
.cn-restart {
display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
padding: 8px 10px; border-radius: 8px; font-size: 11px; line-height: 1.45;
background: color-mix(in srgb, var(--accent) 14%, transparent);
border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
}
/* Export-settings card modal. The image is the content, so the box is sized to it and the
picture scrolls rather than being squeezed — a card you cannot read is not a preview. */
.sc-modal { width: min(1140px, 94vw); max-height: 88vh; display: flex; flex-direction: column; }
.sc-content { flex: 1; min-height: 0; overflow: auto; background: var(--ink-0); }
.sc-img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 6px; }
.sc-foot { display: flex; align-items: center; gap: 8px; padding: 12px 16px 14px;
border-top: 1px solid var(--line); background: var(--surface-deep-2); }
.sc-status { flex: 1; font-size: 11px; color: var(--muted); }