diff --git a/services/premiere-plugin-uxp/index.html b/services/premiere-plugin-uxp/index.html index 67cdb04..18afce0 100644 --- a/services/premiere-plugin-uxp/index.html +++ b/services/premiere-plugin-uxp/index.html @@ -9,7 +9,7 @@
-
+
@@ -28,110 +28,121 @@
- + @@ -231,6 +242,7 @@ + diff --git a/services/premiere-plugin-uxp/src/tooltip.js b/services/premiere-plugin-uxp/src/tooltip.js new file mode 100644 index 0000000..da66091 --- /dev/null +++ b/services/premiere-plugin-uxp/src/tooltip.js @@ -0,0 +1,73 @@ +// Hover tooltips — v1 +// Icon-first UI: every actionable control carries a [data-tip] label that +// surfaces on hover. UXP's CSS engine can't be trusted with +// `content: attr(data-tip)` on ::after, so we position a single floating +// bubble with plain DOM + getBoundingClientRect (both well supported). + +(function () { + let bubble = null; + let timer = null; + + function ensure() { + if (bubble) return bubble; + bubble = document.createElement('div'); + bubble.className = 'tip-bubble'; + document.body.appendChild(bubble); + return bubble; + } + + function show(el) { + const text = el.getAttribute('data-tip'); + if (!text) return; + const tip = ensure(); + tip.textContent = text; + tip.style.display = 'block'; + tip.style.opacity = '0'; + + const r = el.getBoundingClientRect(); + const t = tip.getBoundingClientRect(); + const gap = 7; + const pos = el.getAttribute('data-tip-pos') || 'down'; + let x, y; + + if (pos === 'right') { + x = r.right + gap; y = r.top + (r.height - t.height) / 2; + } else if (pos === 'up') { + x = r.left + (r.width - t.width) / 2; y = r.top - t.height - gap; + } else if (pos === 'up-left') { + x = r.right - t.width; y = r.top - t.height - gap; + } else if (pos === 'down-left') { + x = r.right - t.width; y = r.bottom + gap; + } else { + x = r.left + (r.width - t.width) / 2; y = r.bottom + gap; + } + + const vw = window.innerWidth, vh = window.innerHeight; + x = Math.max(4, Math.min(x, vw - t.width - 4)); + y = Math.max(4, Math.min(y, vh - t.height - 4)); + tip.style.left = x + 'px'; + tip.style.top = y + 'px'; + tip.style.opacity = '1'; + } + + function hide() { + clearTimeout(timer); + if (bubble) { bubble.style.opacity = '0'; bubble.style.display = 'none'; } + } + + function bind(el) { + el.addEventListener('mouseenter', () => { + clearTimeout(timer); + timer = setTimeout(() => show(el), 240); + }); + el.addEventListener('mouseleave', hide); + el.addEventListener('click', hide); + } + + function init() { + document.querySelectorAll('[data-tip]').forEach(bind); + } + + if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); + else init(); +})(); diff --git a/services/premiere-plugin-uxp/styles.css b/services/premiere-plugin-uxp/styles.css index d2b3201..23f3a2a 100644 --- a/services/premiere-plugin-uxp/styles.css +++ b/services/premiere-plugin-uxp/styles.css @@ -1,60 +1,69 @@ -/* Dragonflight UXP panel — v2.1.8 */ -/* Tokens mirror services/web-ui DESIGN.md (canonical) */ +/* Dragonflight UXP panel — redesign (icon rail · full-width grid · dock) + * Hex tokens only (UXP's CSS engine predates oklch). Blue accent kept for + * continuity with the web UI. No external font loads — UXP has no network + * for @font-face, so we lean on the host system stack. */ :root { - /* Surfaces */ - --bg-0: #0B0D11; - --bg-1: #14171E; - --bg-2: #1B1F27; - --bg-3: #232833; - --bg-4: #2D3340; + /* Surfaces — cool near-black blues */ + --bg-deep: #090B0F; + --bg-base: #0E1117; + --bg-panel: #14171F; + --bg-surface: #1B1F28; + --bg-raised: #232834; + --bg-hover: #2C313E; - /* Borders + hover overlays */ - --border: rgba(255, 255, 255, 0.06); - --border-strong: rgba(255, 255, 255, 0.10); - --border-stronger: rgba(255, 255, 255, 0.14); - --hover: rgba(255, 255, 255, 0.04); - --hover-strong: rgba(255, 255, 255, 0.07); + /* Accent */ + --accent: #5B7CFA; + --accent-hover: #7B96FB; + --accent-bright: #9DB0FC; + --accent-subtle: rgba(91, 124, 250, 0.14); + --accent-border: rgba(91, 124, 250, 0.42); /* Text */ - --text-1: #F2F3F6; - --text-2: #A8AEBC; - --text-3: #6B7280; - --text-4: #4B5260; + --text-1: #EEF0F4; + --text-2: #A6ACBA; + --text-3: #6E7585; + --text-4: #474D5B; - /* Accent + status (canonical from DESIGN.md) */ - --accent: #5B7CFA; - --accent-h: #6B89FB; - --accent-soft: rgba(91, 124, 250, 0.14); - --accent-soft-2: rgba(91, 124, 250, 0.22); - --accent-text: #B4C3FF; + /* Borders + hover overlays (tinted neutrals via white overlay) */ + --border-faint: rgba(255, 255, 255, 0.05); + --border: rgba(255, 255, 255, 0.09); + --border-strong: rgba(255, 255, 255, 0.16); + --hover: rgba(255, 255, 255, 0.04); + --hover-strong: rgba(255, 255, 255, 0.07); + /* Signals */ --success: #2DD4A8; --warning: #F5A623; --danger: #FF5B5B; + --info: #4AA3FF; --live: #FF3B30; - --danger-soft: rgba(255, 91, 91, 0.14); --success-soft: rgba(45, 212, 168, 0.14); - /* Legacy aliases — keep so v2.1.x rules using them still resolve */ + /* Legacy aliases — older rules / dynamic markup still resolve these */ --ok: var(--success); --warn: var(--warning); + --bg-1: var(--bg-base); + --bg-2: var(--bg-surface); + --bg-3: var(--bg-raised); - /* Type */ - --font-sans: "Geist", -apple-system, "Segoe UI", system-ui, sans-serif; - --font-mono: "Geist Mono", ui-monospace, "Cascadia Mono", Menlo, monospace; + --font-sans: -apple-system, "Segoe UI", system-ui, Roboto, sans-serif; + --font-mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, monospace; - --t-fast: 80ms; - --t-med: 120ms; + --t-fast: 90ms; + --t-med: 150ms; + --ease: cubic-bezier(0.22, 1, 0.36, 1); /* ease-out-quart */ + + --shadow: 0 10px 30px rgba(0, 0, 0, 0.5); } * { box-sizing: border-box; margin: 0; padding: 0; } html, body { - background: var(--bg-0); + background: var(--bg-panel); color: var(--text-1); - font: 12px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif; + font: 12px/1.4 var(--font-sans); height: 100%; overflow: hidden; } @@ -73,10 +82,10 @@ html, body { flex-direction: column; flex: 1 1 auto; min-height: 0; - padding: 10px 10px 0; overflow: hidden; } .pane.hidden { display: none; } +.pane-connect { padding: 10px 16px 0; } /* ── connect screen ─────────────────────────────────────────────── */ .brand { @@ -84,172 +93,17 @@ html, body { flex-direction: column; align-items: center; gap: 4px; - padding: 12px 0 16px; + padding: 22px 0 20px; } -.brand-icon { color: var(--accent); opacity: 0.85; } -.brand-title { font-size: 16px; font-weight: 700; color: var(--text-1); } +.brand-icon { color: var(--accent); opacity: 0.9; } +.brand-title { font-size: 17px; font-weight: 700; color: var(--text-1); letter-spacing: -0.01em; } .brand-tag { font-size: 9px; font-weight: 600; color: var(--text-3); - letter-spacing: 0.1em; + letter-spacing: 0.14em; text-transform: uppercase; } - -.field-label { - display: block; - font-size: 9.5px; - font-weight: 600; - color: var(--text-3); - letter-spacing: 0.06em; - text-transform: uppercase; - margin: 8px 0 3px; -} - -input[type="text"], -input[type="password"], -input[type="search"], -select { - width: 100%; - background: var(--bg-3); - color: var(--text-1); - border: 1px solid var(--border); - border-radius: 4px; - padding: 6px 8px; - font-size: 12px; - outline: none; - appearance: none; - -webkit-appearance: none; -} -input:focus, select:focus { border-color: var(--accent); } -input[type="search"]::-webkit-search-cancel-button { display: none; } - -/* ── buttons ────────────────────────────────────────────────────── */ -.btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 4px; - font-size: 11.5px; - font-weight: 600; - padding: 6px 10px; - border: 1px solid transparent; - border-radius: 4px; - cursor: pointer; - background: var(--bg-3); - color: var(--text-1); - user-select: none; - white-space: nowrap; -} -.btn:disabled { opacity: 0.38; cursor: default; pointer-events: none; } -.btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); } -.btn-primary:not(:disabled):hover { background: var(--accent-h); border-color: var(--accent-h); } -.btn-secondary { background: var(--bg-3); border-color: var(--border); } -.btn-secondary:not(:disabled):hover { background: var(--bg-2); } -.btn-link { background: transparent; color: var(--text-3); border-color: transparent; padding: 3px 6px; font-weight: 500; } -.btn-link:hover { color: var(--text-1); } -.btn-icon { padding: 4px 7px; background: var(--bg-2); border-color: var(--border); } -.btn-icon:hover { background: var(--bg-3); } -.btn-sm { font-size: 11px; padding: 5px 8px; } - -#connect-btn { margin-top: 12px; width: 100%; padding: 8px; } - -/* ── status msg ──────────────────────────────────────────────────── */ -.status-msg { font-size: 11px; margin-top: 6px; min-height: 16px; } -.status-msg.error { color: var(--danger); } -.status-msg.muted { color: var(--text-3); } - -/* ── dot indicators ──────────────────────────────────────────────── */ -.dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex-shrink: 0; } -.dot-ok { background: var(--ok); } -.dot-bad { background: var(--danger); } -.dot-warn { background: var(--warn); } - -/* ── status strip + overflow menu (v2.1.8 redesign) ──────────────── */ -/* 24px-tall identity bar. Disconnect lives behind ⋯ — out of the way - but discoverable. Legacy `.connected-bar` rule is kept as an alias - so any markup that still uses the old class falls through cleanly. */ -.connected-bar, -.status-strip { - display: flex; - align-items: center; - gap: 8px; - padding: 0 8px; - height: 24px; - background: var(--bg-1); - border-bottom: 1px solid var(--border); - margin-bottom: 6px; - flex-shrink: 0; - position: relative; -} -.signal-dot { - width: 6px; - height: 6px; - border-radius: 50%; - background: var(--success); - flex-shrink: 0; -} -.connected-host { - font-family: var(--font-mono); - font-size: 11px; - color: var(--text-2); - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.btn-ghost { - width: 22px; - height: 22px; - display: inline-flex; - align-items: center; - justify-content: center; - border: 1px solid transparent; - border-radius: 4px; - background: transparent; - color: var(--text-3); - font-size: 14px; - line-height: 1; - cursor: pointer; - transition: background var(--t-fast), color var(--t-fast); -} -.btn-ghost:hover { background: var(--hover); color: var(--text-1); } -.menu { - position: absolute; - top: 24px; - right: 4px; - min-width: 130px; - background: var(--bg-2); - border: 1px solid var(--border-strong); - border-radius: 6px; - padding: 4px; - z-index: 50; -} -.menu-item { - display: block; - width: 100%; - text-align: left; - padding: 6px 10px; - font-size: 11.5px; - font-family: inherit; - background: transparent; - border: none; - color: var(--text-1); - border-radius: 3px; - cursor: pointer; -} -.menu-item:hover { background: var(--hover-strong); } - -/* Tiny version chip — verifies which build is actually running. Lives in - the status strip (between host and ⋯) and on the connect-pane brand. */ -.panel-version { - font-family: var(--font-mono); - font-size: 9.5px; - color: var(--text-4); - letter-spacing: 0.04em; - flex-shrink: 0; - padding-right: 2px; -} .brand-version { font-family: var(--font-mono); font-size: 9.5px; @@ -258,126 +112,302 @@ input[type="search"]::-webkit-search-cancel-button { display: none; } letter-spacing: 0.04em; } -/* ── tabs ────────────────────────────────────────────────────────── */ -.tab-nav { - display: flex; - gap: 2px; - margin-bottom: 6px; - flex-shrink: 0; -} -.tab-btn { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 5px 10px; - font-size: 11.5px; +.field-label { + display: block; + font-size: 9.5px; font-weight: 600; - border: 1px solid transparent; - border-radius: 4px; - background: transparent; color: var(--text-3); - cursor: pointer; + letter-spacing: 0.07em; + text-transform: uppercase; + margin: 10px 0 4px; } -.tab-btn:hover { color: var(--text-2); background: var(--bg-2); } -.tab-btn.active { background: var(--bg-2); color: var(--text-1); border-color: var(--border); } -.badge { +input[type="text"], +input[type="password"], +input[type="search"], +select { + width: 100%; + background: var(--bg-deep); + color: var(--text-1); + border: 1px solid var(--border); + border-radius: 6px; + padding: 7px 9px; + font: 400 12px/1.2 var(--font-sans); + outline: none; + appearance: none; + -webkit-appearance: none; +} +input:focus, select:focus { + border-color: var(--accent-border); + box-shadow: 0 0 0 2px var(--accent-subtle); +} +input[type="search"]::-webkit-search-cancel-button { display: none; } + +/* ── buttons (connect + slide panels) ───────────────────────────── */ +.btn { display: inline-flex; align-items: center; justify-content: center; - min-width: 16px; - height: 16px; - padding: 0 4px; - font-size: 9px; - font-weight: 700; - border-radius: 8px; - background: var(--danger); - color: #fff; + gap: 5px; + font: 600 11.5px/1 var(--font-sans); + padding: 7px 11px; + border: 1px solid transparent; + border-radius: 6px; + cursor: pointer; + background: var(--bg-raised); + color: var(--text-1); + user-select: none; + white-space: nowrap; + transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); } +.btn:disabled { opacity: 0.38; cursor: default; pointer-events: none; } +.btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); } +.btn-primary:not(:disabled):hover { background: var(--accent-hover); border-color: var(--accent-hover); } +.btn-secondary { background: var(--bg-surface); border-color: var(--border); } +.btn-secondary:not(:disabled):hover { background: var(--bg-hover); } +.btn-icon { padding: 5px 8px; background: var(--bg-surface); border-color: var(--border); } +.btn-icon:hover { background: var(--bg-hover); } -/* ── search row ──────────────────────────────────────────────────── */ -.search-row { +#connect-btn { margin-top: 16px; width: 100%; padding: 9px; } + +/* ── status msg ─────────────────────────────────────────────────── */ +.status-msg { font-size: 11px; margin-top: 8px; min-height: 16px; text-align: center; } +.status-msg.error { color: var(--danger); } +.status-msg.muted { color: var(--text-3); } + +/* ── app shell ──────────────────────────────────────────────────── */ +.app { display: flex; flex-direction: column; height: 100%; min-height: 0; } + +.statusbar { display: flex; - gap: 4px; - margin-bottom: 6px; + align-items: center; + gap: 8px; + height: 30px; + padding: 0 8px 0 10px; + background: var(--bg-base); + border-bottom: 1px solid var(--border-faint); + flex-shrink: 0; + position: relative; +} +.signal-dot { + width: 7px; height: 7px; + border-radius: 50%; + background: var(--success); + box-shadow: 0 0 6px var(--success); + flex-shrink: 0; +} +.connected-host { + flex: 1; + min-width: 0; + font: 500 11px/1 var(--font-mono); + color: var(--text-2); + letter-spacing: -0.01em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.panel-version { + font-family: var(--font-mono); + font-size: 9.5px; + color: var(--text-4); + letter-spacing: 0.04em; flex-shrink: 0; } -.search-row input { flex: 1; min-width: 0; } -.search-row select { flex: 0 0 100px; min-width: 0; font-size: 11px; } -/* ── seq info bar ────────────────────────────────────────────────── */ +/* overflow menu */ +.menu { + position: absolute; + top: 30px; + right: 6px; + min-width: 132px; + background: var(--bg-raised); + border: 1px solid var(--border-strong); + border-radius: 7px; + box-shadow: var(--shadow); + padding: 4px; + z-index: 50; +} +.menu-item { + display: block; + width: 100%; + text-align: left; + padding: 7px 10px; + font: 500 11.5px/1 var(--font-sans); + background: transparent; + border: none; + color: var(--text-1); + border-radius: 4px; + cursor: pointer; +} +.menu-item:hover { background: var(--hover-strong); } + +.workspace { display: flex; flex: 1; min-height: 0; } + +/* ── icon rail ──────────────────────────────────────────────────── */ +.rail { + width: 44px; + flex-shrink: 0; + background: var(--bg-base); + border-right: 1px solid var(--border-faint); + display: flex; + flex-direction: column; + align-items: center; + padding: 8px 0; + gap: 2px; +} +.rail-btn { + position: relative; + width: 34px; + height: 34px; + border: none; + background: transparent; + border-radius: 8px; + color: var(--text-3); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); +} +.rail-btn:hover { background: var(--bg-hover); color: var(--text-1); } +.rail-btn.active { background: var(--accent-subtle); color: var(--accent-bright); } +.rail-btn svg { width: 18px; height: 18px; } +.rail-btn--accent { color: var(--accent-bright); } +.rail-btn--accent:hover { background: var(--accent-subtle); } +.rail-spacer { flex: 1; } + +.rail-count { + position: absolute; + top: 0; + right: 0; + min-width: 15px; + height: 15px; + padding: 0 4px; + border-radius: 8px; + background: var(--live); + box-shadow: 0 0 0 2px var(--bg-base); + color: #fff; + font: 700 9px/15px var(--font-sans); + text-align: center; +} + +/* ── main column ────────────────────────────────────────────────── */ +.main { flex: 1; display: flex; flex-direction: column; min-width: 0; } + +.toolbar { + display: flex; + align-items: center; + gap: 6px; + padding: 8px; + border-bottom: 1px solid var(--border-faint); + flex-shrink: 0; +} +.search { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 6px; + height: 28px; + padding: 0 9px; + background: var(--bg-deep); + border: 1px solid var(--border); + border-radius: 6px; + transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); +} +.search:focus-within { border-color: var(--accent-border); box-shadow: 0 0 0 2px var(--accent-subtle); } +.search svg { width: 13px; height: 13px; color: var(--text-3); flex-shrink: 0; } +.search input { + flex: 1; + min-width: 0; + height: 100%; + background: transparent; + border: none; + border-radius: 0; + padding: 0; + outline: none; + box-shadow: none; + color: var(--text-1); + font: 400 12px/1 var(--font-sans); +} +.search input:focus { box-shadow: none; } +.search input::placeholder { color: var(--text-3); } + +.filter-select { + flex: 0 0 96px; + height: 28px; + padding: 0 8px; + font-size: 11px; + border-radius: 6px; +} + +/* ── seq info bar ───────────────────────────────────────────────── */ .seq-info-bar { display: flex; align-items: center; gap: 6px; - padding: 4px 8px; - background: var(--bg-1); - border: 1px solid var(--border); - border-radius: 4px; - margin-bottom: 6px; + margin: 8px 8px 0; + padding: 5px 8px; + background: var(--bg-base); + border: 1px solid var(--border-faint); + border-radius: 6px; font-size: 11px; flex-shrink: 0; } .seq-info-name { color: var(--text-2); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .chip { - font-size: 9px; - font-weight: 700; - padding: 2px 5px; - border-radius: 3px; + font: 700 9px/1 var(--font-sans); + padding: 3px 5px; + border-radius: 4px; letter-spacing: 0.05em; flex-shrink: 0; } -.chip-ok { background: var(--ok); color: #000; } +.chip-ok { background: var(--success); color: #06120d; } -/* ── grid container ──────────────────────────────────────────────── */ -.grid-container { - flex: 1 1 auto; - min-height: 0; - overflow: hidden; - display: flex; - flex-direction: column; -} +/* ── grid ───────────────────────────────────────────────────────── */ +.grid-container { flex: 1 1 auto; min-height: 0; overflow: hidden; display: flex; flex-direction: column; } .grid-container.hidden { display: none; } -/* ── asset grid ──────────────────────────────────────────────────── */ -/* UXP: no auto-fill grid, no aspect-ratio → flex-wrap + fixed sizes */ +/* UXP has no aspect-ratio + flaky auto-fill grid → flex-wrap, fixed sizes. */ .asset-grid { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-wrap: wrap; - gap: 5px; - padding: 2px; + gap: 8px; + padding: 10px; align-content: flex-start; } - .asset-card { - flex: 0 0 130px; - background: var(--bg-2); - border: 1px solid var(--border); - border-radius: 4px; + flex: 1 1 calc(50% - 4px); + min-width: 0; + max-width: calc(50% - 4px); + background: var(--bg-base); + border: 1px solid var(--border-faint); + border-radius: 8px; overflow: hidden; cursor: pointer; display: flex; flex-direction: column; position: relative; + transition: border-color var(--t-fast) var(--ease); } -.asset-card:hover { border-color: var(--text-3); } -.asset-card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); } +.asset-card:hover { border-color: var(--border-strong); } +.asset-card.selected { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); } .asset-thumb { width: 100%; - height: 75px; + height: 78px; object-fit: cover; - background: var(--bg-3); + background: var(--bg-deep); display: block; flex-shrink: 0; } .asset-thumb-placeholder { width: 100%; - height: 75px; - background: var(--bg-3); + height: 78px; + background: var(--bg-deep); display: flex; align-items: center; justify-content: center; @@ -385,194 +415,127 @@ input[type="search"]::-webkit-search-cancel-button { display: none; } font-size: 10px; flex-shrink: 0; } - -.asset-info { padding: 4px 5px 5px; display: flex; flex-direction: column; gap: 2px; } +.asset-info { padding: 6px 7px 7px; display: flex; flex-direction: column; gap: 3px; } .asset-name { - font-size: 10.5px; + font: 500 10.5px/1.3 var(--font-sans); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-1); } -.asset-meta { font-size: 9.5px; color: var(--text-3); display: flex; gap: 5px; } +.asset-meta { + font: 400 9px/1.3 var(--font-mono); + color: var(--text-3); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Status as a corner pip rather than a loud full badge */ .asset-status { position: absolute; - top: 4px; - right: 4px; - font-size: 8.5px; - font-weight: 700; - padding: 1px 4px; - border-radius: 3px; - letter-spacing: 0.04em; - text-transform: uppercase; -} -.status-live { background: var(--live); color: #fff; } -.status-ingesting { background: var(--warn); color: #000; } -.status-processing { background: var(--warn); color: #000; } -.status-ready { background: var(--ok); color: #000; } -.status-error { background: var(--danger); color: #fff; } - -/* ── details panel ───────────────────────────────────────────────── */ -.details-panel { - flex-shrink: 0; - background: var(--bg-1); - border: 1px solid var(--border); + top: 6px; + left: 6px; + display: inline-flex; + align-items: center; + font: 700 8.5px/1 var(--font-sans); + padding: 3px 5px; border-radius: 4px; - padding: 6px 8px; - margin-top: 5px; -} -.details-panel.hidden { display: none; } -.details-header { - font-size: 9.5px; - font-weight: 700; - color: var(--text-3); + letter-spacing: 0.05em; text-transform: uppercase; - letter-spacing: 0.07em; - margin-bottom: 5px; -} -.details-row { - display: flex; - gap: 6px; - font-size: 11px; - margin-bottom: 2px; - min-height: 15px; -} -.dl { color: var(--text-3); flex: 0 0 66px; } -.dv { color: var(--text-1); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.tags-row { display: flex; flex-wrap: wrap; gap: 3px; flex: 1; } -.tag { - font-size: 9.5px; - padding: 1px 5px; - background: var(--bg-3); - border: 1px solid var(--border); - border-radius: 3px; - color: var(--text-2); } +.status-live { background: var(--live); color: #fff; } +.status-ingesting { background: var(--info); color: #04121f; } +.status-processing{ background: var(--info); color: #04121f; } +.status-ready { background: var(--success); color: #06120d; } +.status-error { background: var(--danger); color: #fff; } -/* ── actions / footer ────────────────────────────────────────────── */ -.actions { +/* ── action dock ────────────────────────────────────────────────── */ +.dock { flex-shrink: 0; - border-top: 1px solid var(--border); - padding: 6px 0 0; - margin-top: 5px; - display: flex; - flex-direction: column; - gap: 4px; -} -.action-row { display: flex; gap: 4px; } -/* Compact action buttons (v2.2.0): tighter again. 20px tall, 10.5px font, - thinner padding. Two rows fit where one used to. */ -.action-row .btn { - flex: 1; - height: 20px; - padding: 0 6px; - font-size: 10.5px; - font-weight: 600; - letter-spacing: 0.01em; - white-space: nowrap; - border-radius: 3px; -} - -/* ── advanced section ────────────────────────────────────────────── - v2.2.0: collapsible. The toggle is a tiny full-width strip with a - caret + label; clicking it reveals the action row below. Default - collapsed so the main 6 buttons stay the dominant action surface. */ -.advanced-section { - flex-shrink: 0; - border-top: 1px solid var(--border); - margin-top: 4px; -} -.advanced-toggle { display: flex; align-items: center; - gap: 6px; - width: 100%; - padding: 4px 4px; - font: inherit; + gap: 5px; + padding: 7px 8px; + border-top: 1px solid var(--border-faint); + background: var(--bg-base); +} +.dock-sep { + width: 1px; + height: 18px; + margin: 0 3px; + background: var(--border); + flex-shrink: 0; +} + +/* ── icon button ────────────────────────────────────────────────── */ +.iconbtn { + position: relative; + width: 30px; + height: 30px; + flex-shrink: 0; + border: 1px solid transparent; background: transparent; - border: none; - border-radius: 3px; + border-radius: 7px; + color: var(--text-2); + display: flex; + align-items: center; + justify-content: center; cursor: pointer; - color: var(--text-3); - transition: color var(--t-fast), background var(--t-fast); -} -.advanced-toggle:hover { color: var(--text-2); background: var(--hover); } -.advanced-caret { - display: inline-block; - font-size: 8px; - width: 10px; - text-align: center; - transition: transform var(--t-fast); -} -.advanced-toggle[aria-expanded="true"] .advanced-caret { transform: rotate(90deg); } -.advanced-title { - font-size: 9.5px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.07em; -} -.advanced-body { - padding: 4px 0 8px; + transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); } +.iconbtn:hover { background: var(--bg-hover); color: var(--text-1); } +.iconbtn svg { width: 16px; height: 16px; } +.iconbtn:disabled { opacity: 0.32; cursor: default; pointer-events: none; } +.iconbtn--sm { width: 24px; height: 24px; border-radius: 6px; color: var(--text-3); } +.iconbtn--sm svg { width: 15px; height: 15px; } +.iconbtn--primary { background: var(--accent); color: #fff; border-color: var(--accent); } +.iconbtn--primary:not(:disabled):hover { background: var(--accent-hover); border-color: var(--accent-hover); } -/* ── progress ────────────────────────────────────────────────────── */ -.progress-row { display: flex; flex-direction: column; gap: 3px; } -.progress-bar { - height: 5px; - background: var(--bg-3); - border-radius: 3px; - overflow: hidden; -} -#progress-fill { - height: 100%; - background: var(--accent); - width: 0%; - transition: width 100ms linear; -} -.progress-label { font-size: 10px; color: var(--text-3); } +/* ── progress ───────────────────────────────────────────────────── */ +.progress-row { display: flex; flex-direction: column; gap: 4px; padding: 8px 10px 0; flex-shrink: 0; } +.progress-bar { height: 5px; background: var(--bg-raised); border-radius: 3px; overflow: hidden; } +#progress-fill { height: 100%; background: var(--accent); width: 0%; transition: width 120ms linear; } +.progress-label { font: 400 10px/1.3 var(--font-sans); color: var(--text-3); } -/* ── toast ───────────────────────────────────────────────────────── */ +/* ── toast ──────────────────────────────────────────────────────── */ .toast { - padding: 5px 8px; - border-radius: 4px; + margin: 8px 10px 0; + padding: 6px 9px; + border-radius: 6px; font-size: 11px; - background: var(--bg-2); + background: var(--bg-surface); border: 1px solid var(--border); color: var(--text-1); + flex-shrink: 0; } -.toast.ok { border-color: var(--ok); } +.toast.ok { border-color: var(--success); } .toast.error { border-color: var(--danger); background: var(--danger-soft); } -/* ── slide panels ────────────────────────────────────────────────── */ -.slide-overlay { - position: fixed; - inset: 0; - background: rgba(0,0,0,0.5); - z-index: 10; -} +/* ── slide panels ───────────────────────────────────────────────── */ +.slide-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.55); z-index: 10; } .slide-panel { position: fixed; - bottom: 0; - left: 0; - right: 0; - background: var(--bg-1); + bottom: 0; left: 0; right: 0; + background: var(--bg-panel); border-top: 1px solid var(--border); - border-radius: 8px 8px 0 0; + border-radius: 12px 12px 0 0; + box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.45); z-index: 11; display: flex; flex-direction: column; - max-height: 80%; + max-height: 82%; } .slide-header { display: flex; align-items: center; - padding: 10px 12px 8px; - border-bottom: 1px solid var(--border); + padding: 12px 12px 10px; + border-bottom: 1px solid var(--border-faint); flex-shrink: 0; } -.slide-title { flex: 1; font-size: 13px; font-weight: 700; color: var(--text-1); } +.slide-title { flex: 1; font: 700 13px/1 var(--font-sans); color: var(--text-1); } .slide-body { - padding: 10px 12px; + padding: 12px; overflow-y: auto; flex: 1 1 auto; min-height: 0; @@ -582,75 +545,80 @@ input[type="search"]::-webkit-search-cancel-button { display: none; } } .slide-footer { display: flex; - gap: 6px; - padding: 8px 12px; - border-top: 1px solid var(--border); + gap: 8px; + padding: 10px 12px; + border-top: 1px solid var(--border-faint); flex-shrink: 0; } -.slide-footer .btn { flex: 1; } +.slide-footer .btn { flex: 1; padding: 9px; } -/* ── preset cards ────────────────────────────────────────────────── */ -.preset-grid { - display: flex; - flex-wrap: wrap; - gap: 4px; - margin-bottom: 4px; -} +/* ── preset cards ───────────────────────────────────────────────── */ +.preset-grid { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; } .preset-card { - flex: 0 0 calc(50% - 2px); - background: var(--bg-2); - border: 1px solid var(--border); - border-radius: 4px; - padding: 6px 8px; + flex: 0 0 calc(50% - 3px); + background: var(--bg-base); + border: 1px solid var(--border-faint); + border-radius: 7px; + padding: 8px 10px; cursor: pointer; + transition: border-color var(--t-fast) var(--ease); } -.preset-card:hover { border-color: var(--text-3); } -.preset-card.selected { border-color: var(--accent); background: rgba(79,124,255,0.08); } -.pc-title { font-size: 11.5px; font-weight: 700; color: var(--text-1); } -.pc-desc { font-size: 10px; color: var(--text-3); margin-top: 2px; } +.preset-card:hover { border-color: var(--border-strong); } +.preset-card.selected { border-color: var(--accent); background: var(--accent-subtle); } +.pc-title { font: 700 11.5px/1.2 var(--font-sans); color: var(--text-1); } +.pc-desc { font: 400 10px/1.3 var(--font-sans); color: var(--text-3); margin-top: 3px; } -/* ── clip info ───────────────────────────────────────────────────── */ -.clip-info { - font-size: 11px; - color: var(--text-2); - padding: 6px 0 2px; -} - -/* ── clip list (relink) ──────────────────────────────────────────── */ -.clip-list { - display: flex; - flex-direction: column; - gap: 4px; -} +/* ── clip info / list (relink) ──────────────────────────────────── */ +.clip-info { font-size: 11px; color: var(--text-2); padding: 6px 0 2px; } +.clip-list { display: flex; flex-direction: column; gap: 5px; } .clip-item { display: flex; align-items: center; gap: 8px; - padding: 5px 7px; - background: var(--bg-2); - border: 1px solid var(--border); - border-radius: 4px; + padding: 6px 8px; + background: var(--bg-base); + border: 1px solid var(--border-faint); + border-radius: 7px; font-size: 11px; } .clip-item input[type="checkbox"] { flex-shrink: 0; } -.clip-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.clip-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-1); } .clip-item-status { flex-shrink: 0; font-size: 10px; color: var(--text-3); } -.clip-item.matched { border-color: var(--ok); } +.clip-item.matched { border-color: var(--success); } .clip-item.unmatched { opacity: 0.5; } - .relink-summary { margin-top: 8px; padding: 8px; - background: var(--bg-2); - border: 1px solid var(--border); - border-radius: 4px; + background: var(--bg-base); + border: 1px solid var(--border-faint); + border-radius: 7px; font-size: 11px; color: var(--text-2); } -/* ── empty state ──────────────────────────────────────────────────── */ -.empty { padding: 20px; text-align: center; font-size: 12px; } +/* ── empty / misc ───────────────────────────────────────────────── */ +.empty { padding: 24px; text-align: center; font-size: 12px; width: 100%; } .muted { color: var(--text-3); } - -/* ── misc ────────────────────────────────────────────────────────── */ .hidden { display: none !important; } + +/* ── hover tooltip bubble (driven by src/tooltip.js) ────────────── */ +.tip-bubble { + position: fixed; + z-index: 100; + display: none; + pointer-events: none; + white-space: nowrap; + background: var(--bg-raised); + color: var(--text-1); + border: 1px solid var(--border-strong); + box-shadow: var(--shadow); + font: 500 11px/1 var(--font-sans); + padding: 5px 8px; + border-radius: 6px; + opacity: 0; + transition: opacity var(--t-fast) var(--ease); +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { transition-duration: 0ms !important; animation-duration: 0ms !important; } +}