tts-voice-creator-clone-and.../static/style.css
2026-09-30 10:26:27 +02:00

5576 lines
349 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.

/* ── [hidden] must always hide ────────────────────────────────────────────────
Any component that sets `display:flex/grid/block` on its base selector beats
the UA's `[hidden]{display:none}` at equal specificity, making the element
render as an empty box while "hidden". This bit .ab-char-bar, .wf-stepper,
.reader-extract-banner, .ab-castpanel-inline and ~20 others individually —
one root rule ends the whole bug class. */
[hidden] { display: none !important; }
/* ── MDI icon integration ────────────────────────────────────────────────── */
.mdi {
vertical-align: -0.125em;
line-height: 1;
display: inline-block;
}
button .mdi, a .mdi { font-size: 22px; }
.nav-icon .mdi { font-size: 22px; line-height: 1; }
.section-icon .mdi { font-size: 22px; line-height: 1; }
.llm-card-icon .mdi { font-size: inherit; }
.llm-local-icon.mdi { font-size: 22px; }
.backend-metric-tag .mdi, .llm-metric-chip .mdi, .dc-metric-chip .mdi { font-size: 11px; vertical-align: -0.05em; }
.link-icon { font-size: 11px; opacity: .7; margin-left: 1px; }
/* ── Off-screen rendering skip (native virtualization) ───────────────────────
Long lists (300+ voices, 500+ online cards, big casts) only paint rows near the
viewport. content-visibility:auto lets the browser skip layout/paint for the rest;
contain-intrinsic-size reserves approximate height so the scrollbar stays stable. */
.vl-row { content-visibility: auto; contain-intrinsic-size: auto 64px; }
.voice-source-card, .fa-card, .el-card { content-visibility: auto; contain-intrinsic-size: auto 320px; }
.reh-cast-view-card .reh-cast-card { content-visibility: auto; contain-intrinsic-size: auto 420px; }
.reh-cast-view-list .reh-cast-card { content-visibility: auto; contain-intrinsic-size: auto 72px; }
/* ── Theme tokens (warm cream light theme) ──────────────────────────────── */
:root {
--bg: #F5F3EE;
--surface: #FFFFFF;
--panel: #F3F4F6;
--border: #E5E7EB;
--text: #111827;
--subtext: #5C6470;
--placehld: #5C6470;
--accent: #2563EB;
--green: #16A34A;
--red: #DC2626;
--error: #DC2626;
--yellow: #D97706;
--mauve: #7C3AED;
--teal: #0F766E;
--on-accent:#FFFFFF;
--radius: 8px;
--font: 'Segoe UI', system-ui, sans-serif;
--shadow: 0 2px 8px rgba(0,0,0,0.08);
--sidebar-width: 220px;
}
[data-theme="dark"] {
--bg: #111827;
--surface: #1F2937;
--panel: #374151;
--border: #4B5563;
--text: #F9FAFB;
--subtext: #9CA3AF;
--placehld: #6B7280;
--accent: #3B82F6;
--green: #22C55E;
--red: #EF4444;
--error: #EF4444;
--yellow: #F59E0B;
--mauve: #A855F7;
--teal: #14B8A6;
--on-accent:#FFFFFF;
--shadow: 0 4px 12px rgba(0,0,0,0.5);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; } /* stop iOS auto-inflating text */
body {
background: var(--bg); color: var(--text); font-family: var(--font);
font-size: 16px; height: 100vh; display: flex; flex-direction: column;
overflow: hidden;
-webkit-tap-highlight-color: transparent;
}
/* Dynamic viewport height — avoids the iOS Safari address-bar resize cutting off / locking
the layout (a common cause of "stuck"/unscrollable mobile pages). dvh==vh on desktop. */
@supports (height: 100dvh) { body { height: 100dvh; } }
/* Never allow sideways scroll on phones, and keep content clear of the notch */
@media (max-width: 768px) {
body { overflow-x: hidden; }
#app-shell { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
}
/* Language picker in the sidebar brand */
.app-lang-toggle {
margin-left: auto; padding: 2px; border: 1px solid var(--border); border-radius: 5px;
background: var(--panel); cursor: pointer; line-height: 0; display: inline-flex;
align-items: center; transition: border-color .15s, transform .1s;
}
.app-lang-toggle:hover { border-color: var(--accent); }
.app-lang-toggle:active { transform: scale(.94); }
.app-lang-toggle:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.18); }
.app-lang-toggle .fi { width: 20px; height: 14px; border-radius: 2px; }
/* ── App shell ───────────────────────────────────────────────────────────── */
#app-shell {
display: flex; flex: 1; min-height: 0; overflow: hidden;
}
/* ── Sidebar ─────────────────────────────────────────────────────────────── */
#sidebar {
width: var(--sidebar-width); flex-shrink: 0;
background: var(--surface); border-right: 1px solid var(--border);
display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden;
box-shadow: 2px 0 12px rgba(0,0,0,0.06);
}
.sidebar-brand {
padding: 18px 16px 14px;
border-bottom: 1px solid var(--border);
display: flex; align-items: flex-start; justify-content: space-between; gap: 8px;
}
.sidebar-brand-text { min-width: 0; }
.sidebar-collapse-btn, .sidebar-expand-btn {
background: none; border: none; cursor: pointer; color: var(--subtext);
padding: 4px; border-radius: 6px; font-size: 18px; line-height: 1;
flex-shrink: 0; display: flex; align-items: center; justify-content: center;
}
.sidebar-collapse-btn:hover { background: var(--panel); color: var(--text); }
#sidebar { transition: width .18s ease; }
.sidebar-expand-btn { display: none; }
/* ── Collapsed = slim 56 px icon rail; individual item labels appear as
floating tooltips via JS (#nav-rail-tooltip) — layout never shifts ── */
@media (min-width: 768px) {
body.sidebar-collapsed #sidebar { width: 56px; overflow-x: hidden; }
/* Rail: hide all text/badges/chevrons, keep leading icons only */
body.sidebar-collapsed #sidebar .nav-label,
body.sidebar-collapsed #sidebar .nav-badge,
body.sidebar-collapsed #sidebar .ntc,
body.sidebar-collapsed #sidebar .nav-chevron,
body.sidebar-collapsed #sidebar .nav-group-label,
body.sidebar-collapsed #sidebar .nav-group-head,
body.sidebar-collapsed #sidebar .sidebar-brand-text { display: none; }
body.sidebar-collapsed #sidebar .sidebar-brand { justify-content: center; padding-left: 0; padding-right: 0; }
body.sidebar-collapsed #sidebar .nav-item,
body.sidebar-collapsed #sidebar .nav-tree-item,
body.sidebar-collapsed #sidebar .nav-tree-head {
padding-left: 18px; padding-right: 0; gap: 0; white-space: nowrap;
font-size: 0;
}
body.sidebar-collapsed #sidebar .nav-item .mdi,
body.sidebar-collapsed #sidebar .nav-tree-item .mdi,
body.sidebar-collapsed #sidebar .nav-tree-head .mdi { font-size: 15px; }
body.sidebar-collapsed #sidebar .nav-tree .nav-tree-item,
body.sidebar-collapsed #sidebar .nav-tree .nav-tree-head.nav-subhead,
body.sidebar-collapsed #sidebar .nav-tree .nav-tree .nav-tree-item { padding-left: 18px; }
}
/* Floating label tooltip for icon-rail items */
#nav-rail-tooltip {
position: fixed; z-index: 200;
background: var(--surface); border: 1px solid var(--border);
border-radius: 6px; padding: 5px 11px;
font-size: 13px; font-weight: 500; color: var(--text);
white-space: nowrap; pointer-events: none; display: none;
box-shadow: 2px 4px 14px rgba(0,0,0,.18);
transform: translateY(-50%);
}
@media (max-width: 767px) {
.sidebar-collapse-btn, .sidebar-expand-btn { display: none !important; }
}
.sidebar-brand h1 {
font-size: 15px; font-weight: 800; color: var(--accent);
letter-spacing: -0.01em; line-height: 1.2;
display: flex; align-items: center; gap: 6px;
}
.sidebar-brand p {
font-size: 14px; color: var(--subtext); margin-top: 3px;
}
.sidebar-nav { flex: 1; padding: 8px 0; }
.nav-group-label {
padding: 10px 16px 4px;
font-size: 10px; font-weight: 800; color: var(--subtext);
text-transform: uppercase; letter-spacing: 0.09em;
}
/* ── Sidebar tree (My Voices) ────────────────────────────────────────────── */
.nav-tree-head { position: relative; }
.nav-label { flex: 1; }
.nav-badge {
font-size: 10.5px; font-weight: 700; color: var(--subtext);
background: var(--panel); border: 1px solid var(--border);
border-radius: 10px; padding: 1px 6px; min-width: 18px; text-align: center;
}
.nav-chevron { font-size: 14px; color: var(--subtext); transition: transform .2s; margin-left: 2px; }
.nav-casting-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex-shrink: 0; margin-left: auto; animation: pulse 1s infinite; }
.nav-chevron.open { transform: rotate(180deg); }
.nav-tree { display: none; flex-direction: column; padding: 2px 0 6px; }
.nav-tree.open { display: flex; }
.nav-tree-item {
display: flex; align-items: center; gap: 7px;
padding: 5px 16px 5px 32px; font-size: 12.5px; color: var(--subtext);
cursor: pointer; transition: background .1s, color .1s;
}
.nav-tree-item .mdi { font-size: 14px; flex-shrink: 0; }
.nav-tree-item:hover { background: var(--panel); color: var(--text); }
.nav-tree-item.is-active { color: var(--accent); font-weight: 700; }
/* Only show sub-item highlight when the parent section head is the CURRENT page.
When you're on a different section the remembered sub-item stays stored but
should not look "active" — it just creates visual noise. */
.nav-item:not(.active) ~ .nav-tree .nav-tree-item.is-active,
.nav-item:not(.active) ~ .nav-tree .nav-tree-head.nav-subhead.active {
color: var(--subtext); font-weight: normal;
}
/* Suppress sub-item highlight when its section-head is not the current section.
Covers Language Models, Books, Stage etc. that are hardcoded is-active in HTML. */
[data-nav-section]:not(.active) + .nav-tree .nav-tree-item.is-active {
color: var(--subtext); background: transparent; font-weight: normal;
}
/* ── Background-process busy indicator ──────────────────────────────────────
A small animated dot shown on a nav-item or nav-tree-head when a background
task (synthesis, benchmark, cast, playback) is running in that section.
Set via window.setNavBusy(sectionId, true|false) in nav.js. */
@keyframes nav-busy-pulse { 0%,100%{opacity:.5;transform:scale(.9)} 50%{opacity:1;transform:scale(1.15)} }
.nav-busy-dot {
display: inline-block; width: 7px; height: 7px; border-radius: 50%;
background: var(--accent); flex-shrink: 0; margin-left: auto;
animation: nav-busy-pulse 1.2s ease-in-out infinite;
}
/* Current page/section within its parent group */
.nav-tree-item.active {
background: rgba(37,99,235,0.08); color: var(--accent); font-weight: 700;
border-right: 3px solid var(--accent);
}
/* Virtual tag subfolders under My Voices */
.nav-tree-tag-label { padding: 7px 16px 3px 32px; font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--subtext); pointer-events: none; }
.nav-tree-item.nav-tree-tag { padding-left: 38px; }
.nav-tree-item.nav-tree-tag .mdi { font-size: 13px; opacity: .8; }
.ntc { font-size: 14px; color: var(--subtext); font-weight: 500; }
/* ── Collapsible group headers (Voice Actions · Speak · Setup) ───────────── */
.nav-group-head {
display: flex; align-items: center; gap: 8px; cursor: pointer;
padding: 10px 16px 4px; margin-top: 2px;
font-size: 10px; font-weight: 800; color: var(--subtext);
text-transform: uppercase; letter-spacing: 0.09em;
user-select: none;
}
.nav-group-head .nav-label { flex: 1; }
.nav-group-head:hover { color: var(--text); }
.nav-group-head .nav-chevron { font-size: 13px; }
/* ── Sub-headers nested inside a tree (Tags · Script Rehearsal · Library ·
Engines · Integrations · Settings) — look like items, carry a chevron ── */
.nav-tree .nav-tree-head.nav-subhead {
display: flex; align-items: center; gap: 7px; cursor: pointer;
padding: 5px 16px 5px 32px; font-size: 12.5px; color: var(--subtext);
transition: background .1s, color .1s;
}
.nav-tree .nav-tree-head.nav-subhead .nav-icon .mdi,
.nav-tree .nav-tree-head.nav-subhead > .mdi { font-size: 14px; flex-shrink: 0; }
.nav-tree .nav-tree-head.nav-subhead .nav-label { flex: 1; }
.nav-tree .nav-tree-head.nav-subhead:hover { background: var(--panel); color: var(--text); }
.nav-tree .nav-tree-head.nav-subhead.active { color: var(--accent); font-weight: 700; }
/* Nested trees indent one extra level per depth */
.nav-tree .nav-tree .nav-tree-item,
.nav-tree .nav-tree .nav-tree-head.nav-subhead { padding-left: 44px; }
.nav-tree .nav-tree .nav-tree .nav-tree-item { padding-left: 56px; }
.nav-tree-item.is-active .ntc { color: var(--accent); }
.nav-item {
display: flex; align-items: center; gap: 10px;
padding: 9px 16px; cursor: pointer; color: var(--subtext);
font-size: 13.5px; font-weight: 500;
transition: background 0.12s, color 0.12s;
border-right: 3px solid transparent;
user-select: none;
}
.nav-item:hover { background: var(--panel); color: var(--text); }
.nav-item.active {
background: rgba(37,99,235,0.08);
color: var(--accent); font-weight: 700;
border-right-color: var(--accent);
}
.nav-icon { font-size: 15px; width: 18px; text-align: center; flex-shrink: 0; }
.sidebar-footer {
padding: 12px 16px; border-top: 1px solid var(--border);
display: flex; gap: 8px; align-items: center;
}
.sidebar-footer button {
background: var(--panel); border: 1px solid var(--border); color: var(--subtext);
border-radius: var(--radius); padding: 6px 10px; font-size: 13px; cursor: pointer;
flex: 1; transition: background 0.12s, color 0.12s;
}
.sidebar-footer button:hover { background: var(--border); color: var(--text); }
/* ── Main content ────────────────────────────────────────────────────────── */
#main-content {
flex: 1; overflow-y: auto; overflow-x: hidden;
padding: 0 28px 0; min-width: 0;
}
/* ── Page sections ───────────────────────────────────────────────────────── */
.page-section { padding-top: 7px; display: none; }
.page-section.is-active { display: block; }
.section-head {
display: flex; align-items: center; gap: 14px;
padding: 20px; border-bottom: 2px solid var(--border);
margin-bottom: 20px;
background: var(--surface);
border-radius: var(--radius);
}
.section-icon { font-size: 26px; line-height: 1; }
.section-title h2 {
font-size: 20px; font-weight: 800; color: var(--text);
letter-spacing: -0.02em; margin: 0;
}
.section-title p {
font-size: 13px; color: var(--subtext); margin: 3px 0 0; line-height: 1.4;
}
/* Section head right-side actions (search + button) */
.section-head-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
/* Previous/Next workflow shortcut, auto-injected top-right on every section
header — same navigation as the stepper widget further down, without
needing to scroll to it first. */
.wf-header-nav { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
.wf-header-nav-btn {
display: inline-flex; align-items: center; gap: 4px;
padding: 7px 14px; border-radius: 8px; border: 1px solid var(--border);
background: var(--panel); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
}
.wf-header-nav-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); background: rgba(37,99,235,.08); }
.wf-header-nav-btn:disabled { opacity: .35; cursor: not-allowed; }
.wf-header-nav-label { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Guidance bar under the section header: what to do on this step, and what
either Previous/Next actually leads to — sits right where the user's eye
already is after reading the Previous/Next buttons. */
.wf-step-hint {
display: flex; align-items: baseline; gap: 10px;
padding: 8px 20px; margin: -12px 0 20px;
background: var(--panel); border: 1px solid var(--border); border-top: none;
border-radius: 0 0 var(--radius) var(--radius);
font-size: 12.5px; color: var(--subtext); line-height: 1.4;
}
/* Studio's own Previous/Next (not .wf-header-nav — see s-caststudio.html) */
.stu-phase-nav { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
.stu-phase-nav-btn {
display: inline-flex; align-items: center; gap: 4px;
padding: 7px 14px; border-radius: 8px; border: 1px solid var(--border);
background: var(--panel); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
}
.stu-phase-nav-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); background: rgba(37,99,235,.08); }
.stu-phase-nav-btn:disabled { opacity: .35; cursor: not-allowed; }
.wf-step-hint-badge {
flex-shrink: 0; font-weight: 700; color: var(--accent);
font-size: 11px; letter-spacing: .02em; text-transform: uppercase;
}
.wf-step-hint-text { flex: 1; min-width: 0; }
.section-search {
width: 220px; padding: 6px 12px; font-size: 13px; font-family: var(--font);
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
color: var(--text); transition: border-color .15s;
}
.section-search:focus, .section-search:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
.section-new-voice-btn { padding: 6px 14px; font-size: 13px; white-space: nowrap; }
.section-search::placeholder {
color: var(--placehld);
}
/* ── Force all tab-content visible ──────────────────────────────────────── */
.tab-content {
display: flex !important; flex-direction: column; gap: 18px; padding: 0;
}
#tab-library { min-height: 0; }
/* Hide noisy sub-panels we don't need in this layout */
.library-benchmark-panel { display: none !important; }
#library-filter-panel { display: none; }
#disabled-info { display: none; }
/* ── Cards ──────────────────────────────────────────────────────────────── */
.card {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius); padding: 20px;
display: flex; flex-direction: column; gap: 14px;
box-shadow: var(--shadow); min-width: 0; max-width: 100%;
}
.card h2 {
font-size: 12px; font-weight: 700; color: var(--subtext);
text-transform: uppercase; letter-spacing: .09em;
}
/* ── Collapsible cards ───────────────────────────────────────────────────── */
.card-collapse-h2 { cursor: pointer; user-select: none; display: flex; align-items: center; gap: 7px; }
.card-collapse-h2:hover { opacity: .8; }
.card-chev { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 18px; height: 18px; border-radius: 4px; background: var(--panel); border: 1px solid var(--border); color: var(--accent); font-size: 13px; line-height: 1; transition: transform .2s; }
.card-col-closed .card-chev { transform: rotate(-90deg); }
/* Sync <details> inside cards to the same chevron look */
.card > details > summary { list-style: none; cursor: pointer; user-select: none; display: flex; align-items: center; gap: 7px; }
.card > details > summary::marker, .card > details > summary::-webkit-details-marker { display: none; }
.card > details > summary::before { content: '▾'; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 16px; height: 16px; border-radius: 4px; background: var(--panel); border: 1px solid var(--border); color: var(--accent); font-size: 10px; transition: transform .2s; }
.card > details:not([open]) > summary::before { transform: rotate(-90deg); }
/* ── Drop zone ──────────────────────────────────────────────────────────── */
/* Clone source picker — segmented File / URL / Mic */
/* Integrated tab box: the tab strip and the panel below read as one unit */
.clone-tabbox { display: flex; flex-direction: column; }
.clone-src-picker { display: flex; gap: 4px; margin: 0 0 -1px; align-items: flex-end; padding: 0 4px; border-bottom: 1px solid var(--border); position: relative; z-index: 1; }
.clone-src-tab { display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 11px 18px; border: 1px solid transparent; border-bottom: none; background: transparent; color: var(--subtext); font-size: 14px; font-weight: 600; border-radius: 10px 10px 0 0; cursor: pointer; transition: background .15s, color .15s, border-color .15s; font-family: var(--font); position: relative; }
.clone-src-tab:hover { color: var(--text); background: color-mix(in srgb, var(--surface) 60%, transparent); }
.clone-src-tab.active { background: var(--surface); color: var(--accent); border-color: var(--border); border-bottom-color: var(--surface); }
.clone-src-tab.active::after { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px; background: var(--accent); border-radius: 2px 2px 0 0; }
.clone-src-tab .mdi { font-size: 18px; }
.clone-srcpanel { background: var(--surface); border: 1px solid var(--border); border-radius: 0 var(--radius) var(--radius) var(--radius); padding: 20px; box-shadow: var(--shadow); }
.clone-src-intro { color: var(--subtext); font-size: 13px; margin: 0 0 14px; display: flex; align-items: center; gap: 7px; }
.clone-src-intro .mdi { font-size: 16px; color: var(--accent); }
.clone-id-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
/* author `display` on .card overrides the UA [hidden] rule — restore it */
.clone-src-card[hidden] { display: none; }
@media (max-width: 560px) { .clone-src-tab span:not(.mdi) { display: none; } }
#drop-zone {
border: 2px dashed var(--border); border-radius: var(--radius);
padding: 44px 20px; text-align: center; cursor: pointer; color: var(--subtext);
transition: border-color .2s, background .2s; font-size: 15px;
}
#drop-zone.drag-over { border-color: var(--accent); background: rgba(37,99,235,.05); color: var(--accent); }
#drop-zone span { display: block; font-size: 13px; margin-top: 9px; }
#drop-zone input[type=file] { display: none; }
/* ── Buttons ────────────────────────────────────────────────────────────── */
button {
cursor: pointer; border: none; border-radius: var(--radius);
padding: 9px 18px; font-size: 14px; font-family: inherit;
transition: opacity .15s, filter .15s;
}
button:disabled { opacity: .4; cursor: default; }
button:not(:disabled):hover { filter: brightness(0.95); }
.btn-primary { background: var(--accent); color: var(--on-accent); font-weight: 600; }
.btn-secondary { background: var(--panel); color: var(--text); border: 1px solid var(--border); }
.btn-danger { background: var(--error); color: #fff; font-weight: 600; }
.btn-green { background: #15803D; color: var(--on-accent); font-weight: 600; }
.btn-red { background: var(--red); color: var(--on-accent); font-weight: 600; }
.btn-teal { background: var(--teal); color: var(--on-accent); font-weight: 600; }
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
/* ── Waveform ───────────────────────────────────────────────────────────── */
#waveform-wrap { background: var(--panel); border-radius: var(--radius); overflow: hidden; }
#waveform { min-height: 90px; }
.time-row { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.time-row label { color: var(--subtext); font-size: 13px; display: flex; align-items: center; gap: 7px; }
.time-row input[type=number] {
background: var(--panel); border: 1px solid var(--border); color: var(--text);
border-radius: 4px; padding: 6px 10px; width: 100px; font-size: 14px;
}
#trim-duration { font-size: 14px; padding: 6px 14px; border-radius: 4px; font-weight: 600; }
.dur-ok { background: rgba(22,163,74,.12); color: var(--green); }
.dur-warn { background: rgba(217,119,6,.12); color: var(--yellow); }
.dur-bad { background: rgba(220,38,38,.12); color: var(--red); }
/* ── URL row ────────────────────────────────────────────────────────────── */
.url-row { display: flex; gap: 8px; }
.url-row input[type=text] {
flex: 1; background: var(--panel); border: 1px solid var(--border);
color: var(--text); border-radius: var(--radius); padding: 9px 14px; font-size: 14px;
}
input::placeholder, textarea::placeholder { color: var(--placehld); }
#yt-progress { font-size: 13px; color: var(--subtext); min-height: 1.4em; font-family: monospace; }
/* ── Recording ──────────────────────────────────────────────────────────── */
#rec-indicator { display: none; align-items: center; gap: 8px; color: var(--red); font-size: 14px; }
#rec-indicator.active { display: flex; }
#rec-dot { width: 10px; height: 10px; background: var(--red); border-radius: 50%; animation: pulse 1s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
/* ── Voice ID field ─────────────────────────────────────────────────────── */
.voice-id-row input[type=text] {
flex: 1; background: var(--panel); border: 1px solid var(--border); color: var(--text);
border-radius: var(--radius); padding: 10px 14px; font-size: 15px; font-family: monospace;
font-weight: 600; width: 100%;
}
.voice-id-row { display: flex; gap: 8px; }
input.id-valid { border-color: var(--green) !important; }
input.id-invalid { border-color: var(--red) !important; }
/* ── Helper details ─────────────────────────────────────────────────────── */
details.helper { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); }
details.helper summary { padding: 10px 14px; cursor: pointer; font-size: 13px; color: var(--subtext); user-select: none; list-style: none; }
details.helper summary::before { content: '\25B6 '; font-size: 14px; }
details.helper[open] summary::before { content: '\25BC '; }
details.helper .helper-body { padding: 12px 14px 14px; display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field label { font-size: 12px; color: var(--subtext); font-weight: 600; letter-spacing: .03em; text-transform: uppercase; }
.field select, .field input[type=text] {
background: var(--bg); border: 1px solid var(--border); color: var(--text);
border-radius: var(--radius); padding: 8px 12px; font-size: 14px;
}
/* ── Textareas ──────────────────────────────────────────────────────────── */
#transcript-area, #preview-text-area, #design-instruct, #design-sample-text {
width: 100%; background: var(--panel); border: 1px solid var(--border); color: var(--text);
border-radius: var(--radius); padding: 10px 14px; font-size: 14px; font-family: inherit; resize: vertical;
}
#transcript-area { min-height: 90px; }
#preview-text-area { min-height: 72px; }
#design-instruct { min-height: 110px; }
#design-sample-text { min-height: 56px; }
audio { width: 100%; }
@media (min-width: 900px) {
#clone-sample-text, #lib-add-sample-text {
min-height: 190px;
font-size: 22px;
line-height: 1.65;
}
}
.tryout-voice-row { display: grid; grid-template-columns: minmax(150px,1fr) minmax(230px,1.7fr) minmax(150px,1fr); gap: 12px; align-items: end; }
.tryout-voice-row .field select { width: 100%; min-width: 0; }
.tryout-voice-pick { display: flex; gap: 6px; align-items: stretch; min-width: 0; }
.tryout-voice-pick select { flex: 1 1 auto; min-width: 0; }
.tryout-voice-pick .vp-root { flex: 1 1 auto; min-width: 0; } /* searchable widget replaces the select */
.conv-config-group .vp-root[data-vp-for="conv-tts-voice-select"] {
min-width: min(360px, 100%);
flex: 1 1 360px;
}
.conv-config-group .vp-root[data-vp-for="conv-tts-voice-select"] .vp-drop {
z-index: 120;
}
@media (max-width: 900px) {
.conv-config-group .vp-root[data-vp-for="conv-tts-voice-select"] {
width: 100%;
min-width: 0;
}
}
.tryout-voice-pick .btn-sm { flex: 0 0 auto; padding: 0 11px; display: inline-flex; align-items: center; }
@media (max-width: 720px) { .tryout-voice-row { grid-template-columns: 1fr; } }
/* ── Settings pages ─────────────────────────────────────────────────────── */
.s-settings-page { display:none; flex-direction:column; gap:16px; }
.s-settings-page.is-active { display:flex; }
.s-engines-page { display:none; flex-direction:column; gap:16px; }
.s-engines-page.is-active { display:flex; }
/* Combined Library — tabs + panels */
.lib-tabs { display:flex; gap:6px; margin:4px 0 16px; flex-wrap:wrap; }
.lib-tab {
display:inline-flex; align-items:center; gap:6px; padding:8px 14px;
border:1px solid var(--border); border-radius:8px; background:var(--surface);
color:var(--subtext); font-size:13px; font-weight:500; cursor:pointer;
transition:background .14s ease, color .14s ease, border-color .14s ease;
}
.lib-tab:hover { color:var(--text); border-color:var(--accent); }
.lib-tab.is-active { background:var(--accent); border-color:var(--accent); color:#fff; }
.lib-panel { display:none; }
.lib-panel.is-active { display:block; }
.lib-empty { display:flex; flex-direction:column; align-items:center; gap:8px; padding:40px 0; color:var(--subtext); text-align:center; }
.lib-empty .mdi { font-size:42px; opacity:.4; }
.lib-empty p { margin:0; font-size:13px; line-height:1.5; }
.lib-empty-hint { opacity:.8; }
.lib-chars-loading { padding:32px; text-align:center; color:var(--subtext); font-size:13px; }
/* ── Characters / Cast view ─────────────────────────────────────────────────── */
.lib-chars-toolbar { display:flex; gap:8px; margin-bottom:16px; flex-wrap:wrap; align-items:center; }
.lib-chars-toolbar #lib-chars-back-reader { margin-right:4px; }
.lib-chars-visual-review { margin:0 0 12px; padding:10px 12px; border:1px solid color-mix(in srgb, var(--accent) 35%, var(--border)); border-radius:8px; color:var(--subtext); line-height:1.5; }
.lib-chars-review-item { display:inline-block; margin-left:10px; }
.lib-chars-sort { display:flex; align-items:center; gap:6px; font-size:12.5px; color:var(--subtext); font-weight:600; }
.lib-chars-sort select {
padding:5px 8px; border-radius:6px; border:1px solid var(--border); background:var(--surface);
color:var(--text); font-size:12.5px; cursor:pointer;
}
.lib-chars-view-toggle { display:flex; gap:2px; margin-left:auto; }
.lib-chars-view-toggle button.is-active { background:var(--accent); color:#fff; border-color:var(--accent); }
/* Table view — dense alternative to the card grid for scanning a large cast */
.lib-chars-tbl-wrap {
width:100%; max-width:100%; min-width:0; overflow-x:scroll; overflow-y:hidden;
border:1px solid var(--border); border-radius:12px; background:var(--surface);
position:relative; scrollbar-gutter:stable; scrollbar-width:auto;
}
.lib-chars-tbl-wrap::-webkit-scrollbar { height:12px; }
.lib-chars-tbl-wrap::-webkit-scrollbar-track { background:var(--panel); }
.lib-chars-tbl-wrap::-webkit-scrollbar-thumb { background:var(--subtext); border-radius:8px; border:3px solid var(--panel); }
.lib-chars-column-chooser { position:relative; display:flex; justify-content:flex-end; margin:0 0 6px; }
.lib-chars-column-button { display:inline-flex; align-items:center; gap:5px; }
.lib-chars-column-menu {
display:none; position:absolute; top:calc(100% + 4px); right:0; z-index:20;
min-width:190px; padding:8px; border:1px solid var(--border); border-radius:8px;
background:var(--surface); box-shadow:0 8px 24px rgba(0,0,0,.18);
}
.lib-chars-column-menu.is-open { display:block; }
.lib-chars-column-menu label { display:flex; align-items:center; gap:5px; padding:3px 2px; color:var(--text); font-size:12px; white-space:nowrap; cursor:pointer; }
.lib-chars-column-menu label:hover { background:var(--panel); border-radius:4px; }
.lib-chars-column-menu input { accent-color:var(--accent); margin:0; }
.lib-chars-tbl .lib-chars-col-hidden { display:none !important; }
.lib-chars-tbl { width:100%; min-width:2470px; table-layout:fixed; border-collapse:collapse; font-size:12.9px; white-space:nowrap; }
.lib-chars-tbl td { overflow: hidden; text-overflow: ellipsis; }
.lib-chars-tbl thead th {
text-align:left; padding:8px 8px; font-size:10.5px; font-weight:800; text-transform:uppercase;
letter-spacing:.04em; color:var(--subtext); border-bottom:1px solid var(--border); background:var(--panel);
position:sticky; top:0; z-index:1;
}
.lib-chars-tbl thead th.lib-chars-tbl-sortable { cursor: pointer; user-select: none; }
.lib-chars-tbl thead th.lib-chars-tbl-sortable:hover { color: var(--accent); }
.lib-chars-tbl thead th.lib-chars-tbl-sortable .mdi { font-size: 11px; vertical-align: -1px; }
.lib-chars-tbl td { padding:8px 8px; border-bottom:1px solid var(--border); vertical-align:middle; }
.lib-chars-tbl th:nth-child(1), .lib-chars-tbl td:nth-child(1),
.lib-chars-tbl th:nth-child(2), .lib-chars-tbl td:nth-child(2),
.lib-chars-tbl th:nth-child(3), .lib-chars-tbl td:nth-child(3) {
position: sticky;
background: var(--surface);
}
.lib-chars-tbl thead th:nth-child(1),
.lib-chars-tbl thead th:nth-child(2),
.lib-chars-tbl thead th:nth-child(3) {
background: var(--panel);
}
.lib-chars-tbl th:nth-child(1), .lib-chars-tbl td:nth-child(1) { left: 0; z-index: 5; width: 28px; min-width: 28px; }
.lib-chars-tbl th:nth-child(2), .lib-chars-tbl td:nth-child(2) { left: 28px; z-index: 4; width: 40px; min-width: 40px; }
.lib-chars-tbl th:nth-child(3), .lib-chars-tbl td:nth-child(3) {
left: 68px; z-index: 3; width: 260px; min-width: 260px;
box-shadow: 10px 0 14px -14px rgba(0,0,0,.28);
}
.lib-chars-tbl-row:hover td:nth-child(1),
.lib-chars-tbl-row:hover td:nth-child(2),
.lib-chars-tbl-row:hover td:nth-child(3) {
background: var(--panel);
}
/* Rows reuse .lib-char-card so the existing per-card click/voice/export wiring
picks them up, but that class's display:flex;flex-direction:column (meant
for the card grid) turned every <tr> into a flex column, stacking its <td>s
vertically instead of laying the table out in columns. Reset it back to a
real table row, and undo the card-specific chrome that leaked in with it. */
tr.lib-char-card.lib-chars-tbl-row {
display: table-row; cursor: pointer;
background: none; border: 0; border-radius: 0; box-shadow: none; transition: none;
/* Let Chromium skip layout/paint for distant rows while retaining the full
DOM, so sorting, bulk selection, and row event wiring remain unchanged. */
content-visibility: auto;
contain-intrinsic-size: auto 86px;
}
tr.lib-char-card.lib-chars-tbl-row:hover { transform: none; box-shadow: none; background: var(--panel); }
.lib-chars-tbl-row:hover { background:var(--panel); }
.lib-chars-tbl td.lib-chars-tbl-avatar-cell {
overflow: visible;
text-overflow: clip;
padding-left: 6px;
padding-right: 2px;
}
/* Same specificity as the base .lib-char-avatar rule (card-grid sizing) but
declared earlier in the file, so without the extra qualifiers here the
later, larger card-grid rule silently won the cascade — table rows ended
up with ~90px avatars overlapping the name text instead of these 26px
ones. Ancestor + two classes beats the single-class rule regardless of
source order. */
.lib-chars-tbl-avatar-cell .lib-char-avatar.lib-chars-tbl-avatar {
width: 48px; height: 48px; font-size: 18px; border: none; box-shadow: 0 1px 4px rgba(0,0,0,.10);
border-radius: 50%; overflow: hidden;
}
.lib-chars-tbl-row .lib-char-export { position:static; opacity:1; width:auto; height:auto; border:0; background:none; color:var(--subtext); padding:2px; }
.lib-chars-tbl-row .lib-char-export:hover { color:var(--accent); background:none; border:0; }
.lib-chars-tbl-name { font-weight:600; white-space:normal; min-width:240px; }
.lib-chars-tbl-name-main { display:flex; align-items:center; gap:8px; flex-wrap:wrap; line-height:1.15; }
.lib-chars-tbl-sub { margin-top:3px; font-size:11.5px; color:var(--subtext); white-space:normal; line-height:1.35; }
.lib-chars-tbl-book { margin-top:4px; font-size:11px; color:var(--accent); white-space:normal; line-height:1.35; font-weight:600; }
/* Two stacked rows (voice name+play, then Auswahl/Auto) instead of one —
a long voice id used to push the action buttons out of the visible
column width entirely, confirmed live. */
.lib-chars-tbl-voice-wrap { display:flex; flex-direction:column; align-items:flex-start; gap:4px; }
.lib-chars-tbl-voice-row { display:flex; align-items:center; gap:6px; flex-wrap:wrap; max-width:100%; }
.lib-chars-tbl-voice button { padding:2px 7px; font-size:11px; }
/* display:flex directly on a <td> breaks its table-cell layout participation
(Chrome renders it detached from the column grid — width/position stop
matching its own header entirely). Flex only the inner wrapper instead. */
.lib-chars-tbl-tags { white-space:normal; max-width:260px; }
.lib-chars-tbl-tags-wrap { display:flex; flex-wrap:wrap; gap:3px; }
.lib-chars-tbl-profile { text-align:center; }
.lib-chars-profile-count {
display:inline-block; min-width:54px; padding:3px 6px; border-radius:999px;
font-size:11.5px; font-weight:800; font-variant-numeric:tabular-nums;
border:1px solid var(--border); background:var(--panel); color:var(--subtext);
}
.lib-chars-profile-count.is-sparse { color:#b42318; background:rgba(239,68,68,.10); border-color:rgba(239,68,68,.35); }
.lib-chars-profile-count.is-partial { color:#a15c00; background:rgba(245,158,11,.12); border-color:rgba(245,158,11,.4); }
.lib-chars-profile-count.is-strong { color:#137333; background:rgba(34,197,94,.10); border-color:rgba(34,197,94,.35); }
.lib-chars-tbl-rating { display:inline-flex; gap:1px; }
.lib-chars-tbl-rating-star {
border:0; background:transparent; padding:1px; color:#d1d5db; cursor:pointer; line-height:1;
}
.lib-chars-tbl-rating-star:hover, .lib-chars-tbl-rating-star.is-on { color:#f59e0b; }
.lib-chars-tbl-prompt {
color:var(--subtext); font-size:11.5px; font-style:italic;
white-space:normal; overflow-wrap:anywhere; word-break:normal; line-height:1.4;
vertical-align:top;
}
.lib-chars-tbl-note-cell { padding:5px 8px !important; }
.lib-chars-tbl-voice-note {
display:block; width:100%; min-width:0; min-height:42px; resize:vertical;
border:1px solid transparent; background:transparent; color:var(--text);
padding:4px 5px; border-radius:5px; font:inherit; line-height:1.35;
white-space:pre-wrap; overflow-wrap:anywhere;
}
.lib-chars-tbl-voice-note:hover, .lib-chars-tbl-voice-note:focus { border-color:var(--border); background:var(--panel); outline:none; }
.lib-chars-tbl-voice-note:focus { min-height:64px; }
.lib-chars-tbl-dash { opacity:.4; }
.lib-chars-tbl-check { display:inline-flex; }
.lib-chars-tbl-check.is-yes { color:#4caf50; }
.lib-chars-tbl-check.is-no { color:var(--subtext); opacity:.35; }
.lib-chars-tbl td .lib-char-align-bar { width:60px; flex:none; display:inline-block; }
.lib-chars-production { margin-bottom:28px; border-radius: 12px; transition: box-shadow .3s, background .3s; }
.lib-chars-production-highlight { box-shadow: 0 0 0 3px var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); }
/* Compact single-line list row instead of a bordered box per fact — the
card body has very little room once the banner became a square (see
.lib-char-card's playing-card aspect-ratio), so a table/list layout that
only spends space on facts that actually have a value fits far more in. */
.lib-char-stat-row {
display:flex; align-items:baseline; gap:7px; min-width:0;
padding:4px 0; border-bottom:1px solid rgba(0,0,0,.06);
font-size:12.5px; line-height:1.35;
}
.lib-char-stat-icon { flex-shrink:0; font-size:12px; color:var(--accent); align-self:center; }
.lib-char-stat-label {
flex-shrink:0; text-transform:uppercase; letter-spacing:.06em; font-size:10px;
font-weight:800; color:var(--subtext); width:72px;
}
.lib-char-stat-value { min-width:0; font-weight:600; color:var(--text); overflow-wrap:anywhere; }
.lib-chars-prod-head {
display: flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px;
padding:10px 14px; border-radius:8px 8px 0 0; gap:10px;
background: linear-gradient(90deg, var(--pk1,#4f46e5), var(--pk2,#7c3aed));
color: #fff; cursor:pointer;
}
.lib-chars-prod-collapse-btn {
flex-shrink:0; width:24px; height:24px; padding:0; border:0; border-radius:6px;
background:rgba(255,255,255,.15); color:#fff; cursor:pointer;
display:flex; align-items:center; justify-content:center;
}
.lib-chars-prod-collapse-btn:hover { background:rgba(255,255,255,.28); }
.lib-chars-prod-collapse-btn .mdi { transition:transform .18s; }
.lib-chars-production-collapsed .lib-chars-prod-collapse-btn .mdi { transform:rotate(-90deg); }
.lib-chars-production-collapsed .lib-chars-prod-head { border-radius:8px; }
.lib-chars-production-collapsed .lib-chars-prod-body { display:none; }
.lib-chars-prod-title { font-weight:600; font-size:14px; display:flex; align-items:center; gap:8px; }
.lib-chars-prod-title .mdi { opacity:.8; }
.lib-chars-prod-actions { display:flex; gap:6px; flex-wrap:wrap; }
.lib-chars-prod-actions .btn-secondary {
background: rgba(255,255,255,.15); border-color: rgba(255,255,255,.3); color:#fff; font-size:11px;
}
.lib-chars-prod-actions .btn-secondary:hover { background: rgba(255,255,255,.28); }
.lib-chars-prod-actions .lib-chars-bulk-delete-btn:not(:disabled) { border-color: rgba(255,120,120,.6); }
.lib-chars-prod-actions .lib-chars-bulk-delete-btn:not(:disabled):hover { background: rgba(220,60,60,.35); }
.lib-chars-prod-actions .lib-chars-image-provider {
background: rgba(255,255,255,.15); border: 1px solid rgba(255,255,255,.3); color:#fff;
font-size: 11px; border-radius: 5px; padding: 0 6px; height: 26px; font-family: inherit;
}
.lib-chars-prod-actions .lib-chars-image-provider option { color: #111; }
.lib-chars-prod-actions .lib-chars-visual-style,
.lcd-visual-style {
background: var(--panel, #fff); border: 1px solid var(--border); color: var(--text, #222);
font-size: 11px; border-radius: 5px; padding: 0 7px; height: 28px; font-family: inherit;
}
.lib-chars-prod-actions .lib-chars-visual-style option,
.lcd-visual-style option { color: #111; }
.lib-chars-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 18px; padding:18px;
background: var(--panel);
border: 1px solid var(--border); border-top: none; border-radius: 0 0 8px 8px;
}
/* Portrait-style character card */
.lib-char-card {
display: flex; flex-direction:column; align-items:stretch;
background: var(--surface); cursor:pointer; position:relative;
border-radius:16px; overflow:hidden; border:1px solid var(--border);
transition: transform .13s, box-shadow .13s;
box-shadow: 0 10px 24px rgba(0,0,0,.12);
/* Standard playing-card proportion (2.5:3.5) so every card in the grid
reads as a uniform deck regardless of how much fact/text content each
character has — the body below flexes to fill whatever's left under
the square banner instead of driving the card's total height. */
aspect-ratio: 5 / 7;
/* A production's full character grid (each card carrying a generated
portrait image) stays fully laid out and painted at once with no
virtualization, the same category of issue confirmed and fixed for the
casting view's segment list — matches part of what was running when a
later crash was reported (bulk profile/portrait/voice generation across
dozens of characters). Same proven fix, same reasoning: off-screen
cards stop costing layout/paint, nothing else about the page changes. */
content-visibility: auto;
contain-intrinsic-size: auto 320px;
}
.lib-char-card:hover { transform:translateY(-4px); box-shadow:0 14px 34px rgba(0,0,0,.18); }
.lib-char-select {
position:absolute; top:8px; left:8px; z-index:3; cursor:pointer;
width:20px; height:20px; display:flex; align-items:center; justify-content:center;
background:rgba(0,0,0,.35); border-radius:5px;
}
.lib-char-select-cb { width:15px; height:15px; cursor:pointer; }
/* Coloured banner at top of each card */
.lib-char-card-banner {
aspect-ratio: 1 / 1; height:auto; flex-shrink:0;
display:flex; align-items:flex-end; justify-content:flex-start; position:relative;
gap:14px; padding:16px; overflow:hidden;
background: linear-gradient(135deg, var(--ch1,#4f46e5) 0%, var(--ch2,#7c3aed) 100%);
}
.lib-char-avatar {
width:96px; height:96px; border-radius:50%;
display:flex; align-items:center; justify-content:center;
font-size:36px; font-weight:700; color:#fff; letter-spacing:0;
border:4px solid rgba(255,255,255,.32); box-shadow:0 10px 22px rgba(0,0,0,.34);
flex-shrink:0;
}
/* Once the banner itself is the portrait, the avatar circle collapses to a
small "change photo" corner button instead of duplicating the same image
at icon size on top of itself. */
.lib-char-card-banner.has-photo { align-items:flex-end; }
.lib-char-avatar.is-photo-edit {
position:absolute; top:10px; right:10px; width:30px; height:30px;
font-size:15px; border-width:2px; box-shadow:0 3px 8px rgba(0,0,0,.4);
background:rgba(0,0,0,.38); opacity:.75; transition:opacity .15s;
}
.lib-char-avatar.is-photo-edit:hover { opacity:1; }
.lib-char-banner-copy {
flex:1; min-width:0; min-height:0; display:flex; flex-direction:column; justify-content:center; gap:6px;
color:#fff; padding:4px 34px 4px 0; overflow:hidden;
}
.lib-char-name {
font-weight:800; font-size:20px; text-align:left;
display:flex; align-items:center; gap:8px; flex-wrap:wrap;
line-height:1.1;
}
.lib-char-tier { font-size:9px; font-weight:700; letter-spacing:.5px; text-transform:uppercase;
padding:2px 6px; border-radius:10px; }
.lib-char-tier.main { background: rgba(245,158,11,.2); color: #d97706; }
.lib-char-tier.support { background: rgba(99,102,241,.15); color: var(--accent); }
/* Whether a character has a voice — and which one — used to only be
readable as text at the very bottom of a long card, so scanning a whole
grid for "who still needs a voice" meant reading every card in full. A
clickable pill right at the top of the banner makes it a glance instead
of a read, and doubles as the fastest way to fix it: opens the same
pick/design popup used everywhere else. */
.lib-char-voice-top-row {
/* left offset clears the select checkbox, which sits at the same corner
(top:8px/left:8px, 20px wide) one layer above the banner. Holds the
"hear a sample" play button directly in front of the voice pill instead
of down at the bottom of the card, now that the pill itself lives here. */
position:absolute; top:10px; left:34px; z-index:2;
display:flex; align-items:center; gap:6px; max-width:calc(100% - 44px);
}
.lib-char-card-banner.has-photo .lib-char-voice-top-row { max-width:calc(100% - 80px); }
.lib-char-voice-top-row .lib-char-voice-play {
flex-shrink:0; width:22px; height:22px; padding:0; border-radius:50%; border:0;
background:var(--green,#22c55e); color:#fff;
}
.lib-char-voice-top-row .lib-char-voice-play:hover { background:#1ca750; }
.lib-char-voice-top-row .lib-char-voice-play.playing { background:var(--accent); }
.lib-char-voice-pill {
display:flex; align-items:center; gap:5px; min-width:0; flex:1;
height:22px; padding:0 9px; border-radius:11px; border:0; cursor:pointer;
background:rgba(0,0,0,.4); color:rgba(255,255,255,.7); font-size:11px; font-weight:700;
transition:background .12s, color .12s;
}
.lib-char-voice-pill:hover { background:rgba(0,0,0,.6); color:#fff; }
.lib-char-voice-pill .mdi { flex-shrink:0; font-size:13px; }
.lib-char-voice-pill-text { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.lib-char-voice-pill.has-voice { background:var(--green,#22c55e); color:#fff; }
.lib-char-voice-pill.has-voice:hover { background:#1ca750; }
.lib-char-voice-pill.voice-missing { background:var(--red,#ef4444); color:#fff; }
.lib-char-voice-pill.voice-missing:hover { background:#dc2626; }
.lib-chars-tbl-voice-missing, .lcd-voice-missing { color:var(--red,#ef4444); font-weight:600; }
.lib-chars-tbl-voice-missing .mdi, .lcd-voice-missing .mdi { font-size:13px; }
.lib-char-roleline {
font-size:14px; color:rgba(255,255,255,.92); font-weight:700; line-height:1.25;
display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.lib-char-subline {
font-size:12.5px; color:rgba(255,255,255,.75); line-height:1.35; font-style:italic;
overflow-wrap:anywhere;
display:-webkit-box; -webkit-line-clamp:1; -webkit-box-orient:vertical; overflow:hidden;
}
.lib-char-meta-chips { display:flex; flex-wrap:wrap; gap:6px; margin-top:2px; }
.lib-char-meta-chip {
display:inline-flex; align-items:center; gap:5px; padding:4px 8px; border-radius:999px;
background: rgba(255,255,255,.15); border:1px solid rgba(255,255,255,.18);
color:#fff; font-size:11px; font-weight:700;
}
.lib-char-meta-chip .mdi { font-size:11px; }
.lib-char-body {
/* Fills whatever's left under the square banner within the card's own
aspect-ratio, instead of a hardcoded height — the card's total size is
now driven by aspect-ratio + width, not by summing fixed child sizes. */
flex:1; min-height:0; padding:14px 16px 16px; display:flex; flex-direction:column; gap:6px;
overflow-y:auto;
}
.lib-char-facts {
display:flex; flex-direction:column;
}
.lib-char-archetype {
font-size:13px; color:var(--subtext); text-align:left; margin:0; font-style:italic;
}
.lib-char-snippet {
font-size:13.5px; line-height:1.55; color:var(--subtext); flex:1; margin:0;
display:-webkit-box; -webkit-line-clamp:5; -webkit-box-orient:vertical; overflow:hidden;
min-height: 88px;
}
/* Table-view voice actions (Auswahl/Auto) — base look + per-action hover tint. */
.lib-char-pick-voice, .lib-char-auto-voice, .lib-char-online-voice, .lib-char-gen-voice {
font-size:10px; padding:2px 8px; border-radius:4px; cursor:pointer;
border:1px solid var(--border); background:var(--panel); color:var(--text);
transition: background .12s, border-color .12s, color .12s;
}
.lib-char-pick-voice:hover { border-color:var(--accent); color:var(--accent); }
.lib-char-auto-voice:hover { border-color: var(--green,#22c55e); color: var(--green,#22c55e); }
.lib-char-online-voice:hover { border-color:#0ea5e9; color:#0ea5e9; }
.lib-char-gen-voice:hover { border-color:#a855f7; color:#a855f7; }
/* Quick "hear a sample line" play button — sits next to the voice ID in
both the card and table views, wherever a character already has a voice
assigned. Toggles to a stop icon while its own preview is playing. */
.lib-char-voice-play {
flex-shrink:0; min-width:22px; height:22px; padding:0 10px; border-radius:11px;
display:inline-flex; align-items:center; justify-content:center; gap:5px;
border:1px solid var(--border); background:var(--panel); color:var(--accent);
cursor:pointer; font-size:12px; transition:background .12s, border-color .12s, color .12s;
}
/* Icon-only (table view) stays a plain circle — no label text to pad for. */
.lib-chars-tbl-voice-wrap .lib-char-voice-play { padding:0; width:22px; border-radius:50%; }
.lib-char-voice-play:hover { border-color:var(--accent); background:rgba(var(--accent-rgb,124,106,247),.12); }
.lib-char-voice-play.loading .mdi { animation: spin .8s linear infinite; }
.lib-char-voice-play.playing { border-color:var(--accent); background:var(--accent); color:#fff; }
.lib-chars-tbl-voice-wrap .lib-char-voice-play { margin-left:2px; }
/* Icon-only "design a new voice" action — for when the current voice just
doesn't fit, next to (not replacing) Auswahl/Auto so there's an explicit
one-click way to get something genuinely different. */
.lib-char-redesign-voice {
flex-shrink:0; width:22px; height:22px; padding:0; border-radius:50%;
display:inline-flex; align-items:center; justify-content:center;
border:1px solid var(--border); background:var(--panel); color:var(--accent);
cursor:pointer; font-size:13px; transition:background .12s, border-color .12s, color .12s;
}
.lib-char-redesign-voice:hover:not(:disabled) { border-color:var(--accent); background:rgba(var(--accent-rgb,124,106,247),.12); }
.lib-char-redesign-voice:disabled { opacity:.5; cursor:not-allowed; }
/* Big hover preview of a character's profile picture — a table/card
thumbnail alone (often 32-40px) gives no real sense of the actual
portrait. Fixed-position, follows whichever avatar is hovered, never the
click target itself (pointer-events:none) so it can't interfere with the
avatar's own click-to-upload behavior. */
.lib-avatar-hover-preview {
position:fixed; z-index:2000; width:512px; height:512px;
border-radius:12px; overflow:hidden; pointer-events:none;
box-shadow:0 12px 40px rgba(0,0,0,.35); border:1px solid var(--border);
background:var(--panel);
}
.lib-avatar-hover-preview img { width:100%; height:100%; object-fit:cover; display:block; }
/* Alignment bar */
.lib-char-align { display:flex; align-items:center; gap:5px; margin:6px 0 4px; }
.lib-char-align-evil { font-size:9px; color:#555; flex-shrink:0; line-height:1; }
.lib-char-align-good { font-size:9px; color:#ddd; flex-shrink:0; line-height:1; }
.lib-char-align-bar {
flex:1; height:7px; border-radius:4px; position:relative; cursor:default;
background: linear-gradient(to right, #111 0%, #444 30%, #888 50%, #ccc 70%, #f0f0f0 100%);
box-shadow: inset 0 1px 2px rgba(0,0,0,.4);
}
.lib-char-align-dot {
position:absolute; top:50%; transform:translate(-50%,-50%);
width:11px; height:11px; border-radius:50%;
background: #fff; border:2px solid rgba(0,0,0,.6);
box-shadow: 0 0 0 1px rgba(255,255,255,.4), 0 1px 3px rgba(0,0,0,.5);
transition: left .3s ease;
}
.lib-char-align-arrow { font-size:13px; flex-shrink:0; line-height:1; font-style:normal; }
/* Most-interacted character dots */
.lib-char-rels { display:flex; align-items:center; gap:5px; margin:5px 0 7px; flex-wrap:wrap; }
.lib-char-rel-dot {
width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center;
justify-content:center; font-size:10px; font-weight:700; color:#fff; flex-shrink:0;
cursor:default; border:1.5px solid rgba(255,255,255,.15);
box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
@media (max-width: 1100px) {
.lib-chars-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
}
@media (max-width: 700px) {
.lib-chars-grid { grid-template-columns: 1fr; }
/* A single full-width column would stretch a 5:7 card absurdly tall —
drop the aspect-ratio and let content size the card again. */
.lib-char-card { aspect-ratio: auto; height: auto; }
.lib-char-card-banner { aspect-ratio: auto; height: auto; min-height: 120px; }
.lib-char-avatar { width:82px; height:82px; font-size:30px; }
.lib-char-name { font-size:18px; }
.lib-chars-tbl { min-width: 2470px; }
}
/* ── Character detail modal (D&D / LARP card) ───────────────────────────────── */
.lib-char-detail-ov {
position:fixed; inset:0; z-index:1100;
background: rgba(0,0,0,.78); backdrop-filter:blur(6px);
display:flex; align-items:flex-start; justify-content:center;
padding:32px 16px 48px; overflow-y:auto;
}
.lib-char-detail-box {
background: var(--surface); border-radius:16px; width:100%; max-width:860px;
box-shadow: 0 32px 80px rgba(0,0,0,.6); overflow:hidden; flex-shrink:0;
}
.lcd-header {
display:flex; gap:20px; align-items:stretch; padding:28px 28px 24px;
background: linear-gradient(135deg, var(--lc1,#4f46e5) 0%, var(--lc2,#7c3aed) 100%);
color:#fff; position:relative;
}
/* A character with an already-saved profile picture used to show it as a
small ~80px square tucked in the corner like the plain letter fallback —
once there's a real photo, it deserves to fill the whole header instead
of being squeezed down to icon size. The letter-only placeholder stays at
its normal compact size (align-items:stretch above only affects children
that don't set their own height, like this one via align-self below). */
.lcd-header .cs-avatar.cs-avatar-img {
width:110px; height:auto; align-self:stretch; border-radius:8px;
}
.lcd-avatar {
flex-shrink:0; width:90px; height:90px; border-radius:50%;
display:flex; align-items:center; justify-content:center;
font-size:38px; font-weight:700; color:#fff; letter-spacing:0;
border:3px solid rgba(255,255,255,.4); box-shadow: 0 6px 18px rgba(0,0,0,.35);
overflow:hidden; cursor:pointer;
}
.lcd-avatar:hover::after {
content:'\F04F4'; font-family:'Material Design Icons'; font-size:28px;
position:absolute; inset:0; border-radius:50%;
display:flex; align-items:center; justify-content:center;
background:rgba(0,0,0,.45); color:#fff;
}
.lcd-avatar { position:relative; }
.lcd-avatar img { width:100%; height:100%; object-fit:cover; }
.lcd-avatar-wrap { position: relative; flex-shrink: 0; }
.lcd-avatar-actions {
position: absolute; left: 50%; bottom: -8px; transform: translateX(-50%); z-index: 2;
display: flex; gap: 4px;
}
.lcd-avatar-actions button {
width: 24px; height: 24px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
background: var(--accent); color: #fff; border: 2px solid var(--surface);
cursor: pointer; font-size: 12px; box-shadow: 0 2px 6px rgba(0,0,0,.25);
}
.lcd-avatar-actions button:hover { filter: brightness(1.1); }
.lcd-avatar-actions button:disabled { opacity: .6; cursor: default; }
.lcd-avatar-online-btn { background: var(--teal, #0F766E) !important; }
.lcd-avatar-upload-btn { background: var(--mauve, #7C3AED) !important; }
.lcd-header-body { flex:1; min-width:0; }
.lcd-form-switcher { display:inline-flex; align-items:center; gap:8px; margin-top:10px; font-size:12px; font-weight:600; color:rgba(255,255,255,.9); }
.lcd-form-switcher select { max-width:190px; padding:5px 8px; border:1px solid rgba(255,255,255,.35); border-radius:6px; background:rgba(0,0,0,.22); color:#fff; }
.lcd-form-switcher option { background:var(--surface,#20202a); color:var(--text,#fff); }
.lcd-name { font-size:26px; font-weight:700; line-height:1.15; margin-bottom:5px; }
.lcd-aliases { font-size:14px; opacity:.72; margin-bottom:7px; font-style:italic; }
.lcd-archetype { font-size:17px; opacity:.88; margin-bottom:12px; font-weight:500; }
.lcd-tier-gender { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.lcd-tier { font-size:12px; font-weight:700; letter-spacing:.6px; text-transform:uppercase;
padding:4px 12px; border-radius:14px; background:rgba(255,255,255,.22); }
.lcd-linecount {
display:inline-flex; align-items:center; justify-content:center;
font-size:12px; font-weight:700; letter-spacing:.02em;
padding:4px 10px; border-radius:14px;
border:1px solid rgba(255,255,255,.28);
background:rgba(255,255,255,.14);
color:#fff;
}
.lcd-gender { font-size:14px; opacity:.82; }
/* The auto-generated concept-art sheet — a full-width banner just below the
header (its own .lcd-section-full row), sized to actually be readable
instead of squeezed to a 110px header thumbnail (confirmed live: too
small to make out any detail in a multi-pose design sheet). */
.lcd-conceptart-headrow {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
margin-bottom: 14px;
}
.lcd-conceptart-img {
width: 100%; max-height: 70vh; border-radius: 10px; overflow: hidden;
cursor: pointer; border: 1px solid var(--border);
display: flex; justify-content: center; background: color-mix(in srgb, var(--panel) 60%, transparent);
}
.lcd-conceptart-img img { max-width: 100%; max-height: 70vh; object-fit: contain; display: block; }
.lcd-conceptart-empty {
width: 100%; min-height: 160px; border-radius: 10px;
border: 2px dashed var(--border);
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 6px; font-size: 13px; text-align: center; color: var(--subtext); padding: 20px;
}
.lcd-conceptart-empty .mdi { font-size: 30px; }
.lcd-conceptart-empty.is-noprompt { opacity: .6; }
.lcd-conceptart-empty { cursor:pointer; }
.lcd-conceptart-empty:hover { border-color:var(--accent); }
.conceptart-lightbox-box { width: min(980px, 96vw); max-height: 94vh; overflow-y: auto; }
.conceptart-lightbox-img { width: 100%; height: auto; border-radius: 10px; display: block; }
.conceptart-editor-preview { display:flex; justify-content:center; min-height:120px; margin-top:18px; }
.conceptart-editor-preview .conceptart-lightbox-img { max-width:min(900px, 90vw); max-height:62vh; object-fit:contain; width:auto; }
.conceptart-editor-empty { width:min(700px, 88vw); min-height:240px; border:2px dashed var(--border); border-radius:10px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:8px; color:var(--subtext); }
.conceptart-editor-empty .mdi { font-size:38px; }
.conceptart-quick-actions { display:flex; justify-content:center; flex-wrap:wrap; gap:10px; margin:18px 0; }
.conceptart-editor-tools { display:flex; flex-direction:column; gap:9px; padding:0 10px; }
.conceptart-editor-tools textarea { width:100%; resize:vertical; padding:10px; font:inherit; min-height:120px; }
.lcd-header-btns { display:flex; gap:8px; flex-shrink:0; align-self:flex-start; }
.lcd-header-btns button {
background:rgba(255,255,255,.18); border:1px solid rgba(255,255,255,.32); color:#fff;
border-radius:8px; padding:7px 16px; font-size:14px; cursor:pointer;
transition:background .12s; display:flex; align-items:center; gap:6px;
}
.lcd-header-btns button:hover { background:rgba(255,255,255,.32); }
/* Body with alternating section backgrounds */
.lcd-body { padding:0; }
.lcd-align-section {
padding:20px 28px 18px; border-bottom:1px solid var(--border);
background: var(--panel);
}
.lcd-align-bar-wrap { display:flex; align-items:center; gap:12px; margin:10px 0 6px; }
.lcd-align-label { font-size:14px; color:var(--subtext); flex-shrink:0; font-weight:600; }
.lcd-align-bar {
flex:1; height:12px; border-radius:6px; position:relative;
background: linear-gradient(to right, #1a1a1a 0%, #555 30%, #888 50%, #bbb 70%, #efefef 100%);
box-shadow: inset 0 2px 4px rgba(0,0,0,.5);
}
.lcd-align-dot {
position:absolute; top:50%; transform:translate(-50%,-50%);
width:20px; height:20px; border-radius:50%;
background:#fff; border:3px solid rgba(0,0,0,.5);
box-shadow: 0 0 0 2px rgba(255,255,255,.6), 0 3px 8px rgba(0,0,0,.55);
}
.lcd-align-arc { font-size:15px; font-weight:500; margin-top:7px; }
.lcd-arc-note { font-size:14px; color:var(--subtext); font-style:italic; margin-top:5px; line-height:1.6; }
/* Two-column section grid */
.lcd-sections { display:grid; grid-template-columns:1fr 1fr; }
@media (max-width:620px) { .lcd-sections { grid-template-columns:1fr; } }
.lcd-section {
padding:22px 28px; border-bottom:1px solid var(--border);
background: var(--surface);
}
.lcd-section:nth-child(odd) { border-right:1px solid var(--border); }
/* Alternating panel rows */
.lcd-section:nth-child(4n+1),
.lcd-section:nth-child(4n+2) { background: var(--panel); }
.lcd-section-full {
padding:22px 28px; border-bottom:1px solid var(--border);
background: var(--surface);
}
.lcd-section-full:nth-child(even) { background: var(--panel); }
.lcd-empty-note {
display: flex; align-items: center; gap: 10px;
color: var(--subtext); font-size: 14px; font-style: italic;
}
.lcd-empty-note .mdi { font-size: 20px; opacity: .7; }
.lcd-section-label {
font-size:11px; font-weight:700; letter-spacing:.9px; text-transform:uppercase;
color:var(--accent); margin-bottom:14px; display:flex; align-items:center; gap:7px;
}
/* Generation Prompts section: four fold-out "ready to copy" boxes */
.lcd-prompts-section .lcd-section-label { justify-content: space-between; }
.lcd-prompts-section .lcd-gen-prompts { margin-left: auto; text-transform: none; letter-spacing: 0; }
.lcd-prompt-box {
border: 1px solid var(--border); border-radius: 8px; background: var(--surface);
margin-bottom: 8px; overflow: hidden;
}
.lcd-prompt-box summary {
cursor: pointer; padding: 9px 12px; font-size: 12.5px; font-weight: 700; color: var(--text);
list-style: none; display: flex; align-items: center; gap: 6px; user-select: none;
}
.lcd-prompt-box summary::before { content: '›'; font-size: 15px; color: var(--subtext); transition: transform .15s; }
.lcd-prompt-box[open] summary::before { transform: rotate(90deg); }
.lcd-prompt-box summary:hover { background: var(--panel); }
.lcd-prompt-hint { margin-left: auto; font-size: 11px; font-weight: 400; color: var(--subtext); }
.lcd-prompt-empty { font-weight: 400; font-size: 11px; color: var(--subtext); font-style: italic; }
.lcd-prompt-body { padding: 0 12px 10px; display: flex; flex-direction: column; gap: 8px; }
.cs-concept-art-preview { border-radius: 8px; overflow: hidden; border: 1px solid var(--border); }
.cs-concept-art-preview img { display: block; width: 100%; height: auto; }
.lcd-prompt-text {
white-space: pre-wrap; font-size: 12.5px; line-height: 1.55; color: var(--text);
background: var(--panel); border: 1px solid var(--border); border-radius: 6px;
padding: 8px 10px; min-height: 40px; outline: none;
}
.lcd-prompt-text:focus { border-color: var(--accent); }
.lcd-prompt-actions { display: flex; gap: 6px; justify-content: flex-end; }
.lcd-prompt-actions .lcd-save-prompt { margin-right: auto; }
.lcd-generated-voice-file .lcd-regenerate-voice { margin-left: auto; flex: 0 0 auto; }
.lcd-voice-prompt-box { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); box-shadow: 0 2px 8px rgba(37,99,235,.08); }
.lcd-voice-prompt-box .lcd-prompt-actions { padding-top: 2px; }
.lcd-voice-actions { display: flex; justify-content: flex-end; margin: -1px 0 10px; }
@media (max-width: 560px) {
.lcd-prompt-hint { display: none; }
.lcd-generated-voice-file { flex-wrap: wrap; }
.lcd-generated-voice-file .lcd-regenerate-voice { margin-left: auto; }
.lcd-voice-actions { justify-content: stretch; }
.lcd-voice-actions button { width: 100%; }
}
.lcd-generated-voice-file {
display: flex; align-items: center; gap: 8px; margin: -2px 0 8px; padding: 7px 10px;
border: 1px solid var(--border); border-radius: 8px; background: var(--panel);
color: var(--subtext); font-size: 11.5px;
}
.lcd-generated-voice-file-label { min-width: 0; overflow-wrap: anywhere; }
.lcd-generated-voice-file-label strong { color: var(--text); font-weight: 600; }
.lcd-voice-replace-confirm {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
margin: -2px 0 10px; padding: 10px 12px; border: 1px solid #f59e0b;
border-radius: 8px; background: color-mix(in srgb, #f59e0b 10%, var(--surface));
color: var(--text); font-size: 12px; line-height: 1.4;
}
.lcd-voice-replace-confirm[hidden] { display: none; }
.lcd-voice-replace-confirm > span:first-child { display: flex; align-items: flex-start; gap: 7px; }
.lcd-voice-replace-confirm .mdi-alert-outline { color: #d97706; font-size: 17px; }
.lcd-voice-replace-actions { display: flex; gap: 7px; flex: 0 0 auto; }
@media (max-width: 640px) {
.lcd-voice-replace-confirm { align-items: stretch; flex-direction: column; }
.lcd-voice-replace-actions { justify-content: flex-end; }
}
.lcd-generated-voice-play {
display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
width: 28px; height: 28px; padding: 0; border: 1px solid var(--accent);
border-radius: 50%; background: var(--accent); color: #fff; cursor: pointer;
}
.lcd-generated-voice-play:hover { filter: brightness(.92); }
.lcd-generated-voice-play.playing { background: #1d4ed8; }
.lcd-generated-voice-play.loading { opacity: .65; cursor: wait; }
.lcd-field { margin-bottom:16px; }
.lcd-field:last-child { margin-bottom:0; }
/* Compact list row — label left, value right, thin separator — used inside
the grouped 2-column sections for a scannable list feel instead of the
more spacious stacked .lcd-field blocks. */
.lcd-row {
display: grid; grid-template-columns: minmax(88px, auto) 1fr; gap: 10px;
padding: 7px 0; border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
font-size: 13.5px;
}
.lcd-row:last-child { border-bottom: none; }
.lcd-row.lcd-row-full { grid-template-columns: 1fr; }
.lcd-row dt {
font-weight: 800; color: var(--subtext); text-transform: uppercase;
font-size: 10px; letter-spacing: .05em; line-height: 1.4;
}
.lcd-row dd { margin: 0; color: var(--text); line-height: 1.5; }
.lcd-row dd .cs-source-mark { margin-left: 6px; vertical-align: middle; }
/* Character sheets are read as a profile, not a compact comparison table:
each field has a bold heading followed by normal prose in one column.
Scope this to the sheet so the denser casting/library editor remains intact. */
.cs-profile-layout .lcd-sections { grid-template-columns: 1fr; }
.cs-profile-layout .lcd-section:nth-child(odd) { border-right: none; }
.cs-profile-layout .lcd-section:nth-child(odd) { background: var(--surface); }
.cs-profile-layout .lcd-section:nth-child(even) { background: var(--panel); }
.cs-profile-layout .lcd-row {
display: block;
padding: 10px 0;
}
.cs-profile-layout .lcd-row dt {
color: var(--text);
font-size: 12px;
font-weight: 800;
letter-spacing: .02em;
text-transform: none;
}
.cs-profile-layout .lcd-row dd { margin-top: 4px; font-size: 14px; line-height: 1.55; }
.lcd-field-label {
font-size:11px; font-weight:700; color:var(--subtext); text-transform:uppercase;
letter-spacing:.5px; margin-bottom:5px;
}
.lcd-field-value { font-size:15px; line-height:1.65; color:var(--text); white-space:pre-wrap; }
.lcd-rels-dots { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
.lcd-rel-dot {
width:36px; height:36px; border-radius:50%; display:inline-flex; align-items:center;
justify-content:center; font-size:14px; font-weight:700; color:#fff;
border:2px solid rgba(255,255,255,.18); box-shadow:0 3px 7px rgba(0,0,0,.35);
cursor:default;
}
.lcd-voice-section {
padding:22px 28px 28px; background:var(--panel);
}
.lcd-voice-row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:10px; }
.lcd-voice-label { font-size:15px; flex:1; min-width:140px; }
.lcd-voice-row button {
font-size:13px; padding:6px 16px; border-radius:7px; cursor:pointer;
border:1px solid var(--border); background:var(--surface); color:var(--text);
transition:background .12s, border-color .12s, color .12s;
}
.lcd-pick-voice:hover { border-color:var(--accent); color:var(--accent); }
.lcd-auto-voice:hover { border-color:var(--green,#22c55e); color:var(--green,#22c55e); }
.lcd-online-voice:hover { border-color:#0ea5e9; color:#0ea5e9; }
.lcd-gen-voice:hover { border-color:#a855f7; color:#a855f7; }
.lcd-analysis {
background:var(--panel); border-top:1px solid var(--border);
padding:20px 28px; font-size:14px; line-height:1.7; color:var(--subtext); white-space:pre-wrap;
}
/* Voice section at top of modal body */
.lcd-voice-top {
padding:20px 28px 18px; border-bottom:1px solid var(--border);
background:var(--surface); display:flex; align-items:center; gap:12px; flex-wrap:wrap;
}
.lcd-voice-top .lcd-section-label { margin-bottom:0; flex-shrink:0; }
.lcd-voice-top .lcd-voice-label { font-size:14px; flex:0 1 auto; min-width:0; }
.lcd-voice-top button {
font-size:13px; padding:6px 16px; border-radius:7px; cursor:pointer;
border:1px solid var(--border); background:var(--panel); color:var(--text);
transition:background .12s, border-color .12s, color .12s;
}
.lcd-voice-top .lcd-pick-voice:hover { border-color:var(--accent); color:var(--accent); }
.lcd-voice-top .lcd-auto-voice:hover { border-color:var(--green,#22c55e); color:var(--green,#22c55e); }
.lcd-voice-top .lcd-online-voice:hover { border-color:#0ea5e9; color:#0ea5e9; }
.lcd-voice-top .lcd-gen-voice:hover { border-color:#a855f7; color:#a855f7; }
.lcd-voice-top .lcd-preview-voice { display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; padding:0; border-radius:50%; }
.lcd-voice-top .lcd-preview-voice { background:#2563eb; border-color:#2563eb; color:#fff; }
.lcd-voice-top .lcd-preview-voice:hover { background:#1d4ed8; border-color:#1d4ed8; color:#fff; }
.lcd-voice-top .lcd-preview-voice.playing { background:#1d4ed8; border-color:#1d4ed8; color:#fff; }
.lcd-voice-top .lcd-preview-voice.loading { opacity:.65; cursor:wait; }
.lcd-voice-top .lcd-design-voice-icon {
display:inline-flex; align-items:center; justify-content:center;
width:30px; height:30px; padding:0; border-radius:50%;
color:#7c3aed;
}
.lcd-voice-top .lcd-design-voice-icon:hover { background:#f3e8ff; border-color:#a855f7; color:#7c3aed; }
/* Sources section */
.lcd-sources {
padding:20px 28px; background:var(--panel); border-top:1px solid var(--border);
}
.lcd-source-list { display:flex; flex-direction:column; gap:8px; margin-top:10px; }
.lcd-source-item {
background:var(--surface); border:1px solid var(--border); border-radius:8px;
padding:10px 14px;
}
.lcd-source-page { font-size:11px; font-weight:700; color:var(--accent); margin-bottom:4px; text-transform:uppercase; letter-spacing:.4px; }
.lcd-source-quote { font-size:13px; line-height:1.55; color:var(--text); font-style:italic; }
.lcd-source-hint { font-size:11px; color:var(--subtext); margin-top:3px; }
.lcd-sources-hint { font-size:10px; opacity:.45; font-weight:400; letter-spacing:0; }
.lcd-source-clickable { cursor:pointer; transition:background .12s, border-color .12s; }
.lcd-source-clickable:hover { background:rgba(var(--accent-rgb,124,106,247),.12); border-color:var(--accent); }
/* ── Character detail page (full-page layout, no modal) ─────────────────── */
/*
Fixed height so each panel scrolls independently.
The outer content wrapper already has overflow-y:auto (line ~284),
so sticky doesn't work inside it. Instead we give .lib-char-page a
real viewport height and let each column overflow internally.
*/
.lib-char-page {
display:flex; flex-direction:row;
height:calc(100dvh - 148px); /* viewport minus app header + section tabs */
min-height:400px; overflow:hidden;
}
.lib-cpg-main { flex:1; overflow-y:auto; min-width:0; padding-bottom:60px; }
.lib-cpg-back {
display:inline-flex; align-items:center; gap:6px;
background:none; border:none; cursor:pointer; color:var(--accent);
font-size:13px; padding:14px 20px 8px; opacity:.8;
}
.lib-cpg-back:hover { opacity:1; }
/* Remove the outer box from the modal — header fills edge-to-edge */
.lib-char-page .lcd-header { border-radius:0; }
.lib-char-page .lcd-body { padding:0; }
/* Inline-editable fields inside the detail page */
.lcd-field-editable {
outline:none; border-radius:4px; cursor:text;
padding:2px 5px; margin:-2px -5px;
transition:background .15s, box-shadow .15s;
min-height:1.2em;
}
.lcd-field-editable:hover { background:rgba(255,255,255,.05); }
.lcd-field-editable:focus { background:rgba(255,255,255,.09); box-shadow:inset 0 -2px 0 var(--accent); }
/* Same treatment for the live casting card's own pencil-toggle editing —
only actionable once the card is in edit mode (contenteditable="true"). */
.cs-field-editable[contenteditable="true"] {
outline:none; border-radius:4px; cursor:text;
padding:2px 5px; margin:-2px -5px; display:inline-block;
transition:background .15s, box-shadow .15s;
}
.cs-field-editable[contenteditable="true"]:hover { background:rgba(var(--accent-rgb,124,106,247),.08); }
.cs-field-editable[contenteditable="true"]:focus { background:rgba(var(--accent-rgb,124,106,247),.14); box-shadow:inset 0 -2px 0 var(--accent); }
/* Header name/aliases/archetype editable */
.lcd-header [contenteditable] { outline:none; cursor:text; }
.lcd-header [contenteditable]:hover { text-decoration:underline; text-underline-offset:3px; text-decoration-style:dotted; }
.lcd-header [contenteditable]:focus { text-decoration:none; background:rgba(0,0,0,.2); border-radius:4px; padding:0 4px; }
/* Alignment slider */
.lcd-align-slider { flex:1; height:6px; accent-color:var(--accent,#7c6af7); cursor:pointer; }
.lcd-align-slider-val { font-size:13px; font-weight:600; opacity:.7; flex-shrink:0; min-width:48px; text-align:right; }
/* Right sidebar — independent scroll, no sticky needed (fixed-height parent) */
.lib-cpg-sidebar {
width:240px; flex-shrink:0;
border-left:3px solid var(--border);
box-shadow:-4px 0 12px rgba(0,0,0,.18);
overflow-y:auto; background:var(--panel);
}
.lib-cpg-sidebar-title {
padding:12px 14px 8px; font-size:10px; font-weight:700;
letter-spacing:.07em; text-transform:uppercase; opacity:.45; border-bottom:1px solid var(--border);
}
.lib-cpg-sidebar-tools { display:flex; gap:5px; padding:8px; border-bottom:1px solid var(--border); }
.lib-cpg-sidebar-search, .lib-cpg-sidebar-sort {
min-width:0; padding:5px 6px; border:1px solid var(--border); border-radius:5px;
background:var(--surface); color:var(--text); font:inherit; font-size:11px; outline:none;
}
.lib-cpg-sidebar-search { flex:1; }
.lib-cpg-sidebar-sort { width:76px; cursor:pointer; }
.lib-cpg-sidebar-search:focus, .lib-cpg-sidebar-sort:focus { border-color:var(--accent); }
.lib-cpg-sidebar-item {
display:flex; align-items:center; gap:9px; padding:8px 12px;
cursor:pointer; transition:background .12s; border-bottom:1px solid rgba(255,255,255,.03);
}
.lib-cpg-sidebar-item:hover, .lib-cpg-sidebar-item.is-active { background:var(--surface); }
.lib-cpg-sidebar-item.is-active { border-left:2px solid var(--accent); padding-left:10px; }
.lib-cpg-sidebar-dot {
width:26px; height:26px; border-radius:50%; flex-shrink:0;
display:flex; align-items:center; justify-content:center;
font-size:11px; font-weight:700; color:#fff;
}
.lib-cpg-sidebar-name { flex:1; font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.lib-cpg-sidebar-count { font-size:11px; opacity:.4; flex-shrink:0; }
/* Voice picker popup */
.lib-voice-picker-popup {
/* position/left/top/bottom/width set inline in JS (fixed, anchored via
getBoundingClientRect) — see _openVoicePicker */
z-index:500;
background: var(--surface); border:1px solid var(--border); border-radius:8px;
box-shadow: 0 8px 24px rgba(0,0,0,.25); overflow:hidden; max-height:280px;
display:flex; flex-direction:column;
}
.lib-vp-search { padding:8px; border-bottom:1px solid var(--border); }
.lib-vp-quick { padding:0 8px 8px; border-bottom:1px solid var(--border); }
.lib-vp-design-btn {
width:100%; display:flex; align-items:center; justify-content:center; gap:6px;
padding:7px; border-radius:6px; border:1px dashed var(--accent); background:none;
color:var(--accent); font-size:12px; font-weight:600; cursor:pointer;
transition:background .12s;
}
.lib-vp-design-btn:hover { background:rgba(var(--accent-rgb,124,106,247),.1); }
.lib-vp-input { width:100%; box-sizing:border-box; background:var(--panel); border:1px solid var(--border);
border-radius:6px; padding:5px 9px; font-size:12px; color:var(--text); outline:none; }
.lib-vp-input:focus { border-color:var(--accent); }
.lib-vp-list { overflow-y:auto; flex:1; }
.lib-vp-item { padding:7px 12px; font-size:12px; cursor:pointer; transition:background .1s; }
.lib-vp-item:hover { background:var(--panel); }
.lib-vp-item.selected { color:var(--accent); font-weight:600; }
/* Character production tags */
.cl-card-tags { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }
.cl-tag-chip {
display:inline-flex; align-items:center; gap:3px; padding:2px 8px;
border-radius:10px; background:var(--chip-bg, rgba(127,127,127,.16));
color:var(--subtext); font-size:11px; font-weight:500;
}
.cl-tag-chip .mdi { font-size:12px; opacity:.7; }
.lib-char-tags { display:flex; flex-wrap:wrap; gap:4px; margin:4px 0; }
/* Page card head */
.s-page-head { border-bottom:1px solid var(--border); padding-bottom:14px; }
.s-page-head h3 { font-size:16px; font-weight:700; margin:0 0 4px; color:var(--text); }
.s-page-head p { font-size:13px; color:var(--subtext); margin:0; line-height:1.5; }
.s-page-head-row { display:flex; justify-content:space-between; align-items:flex-start; gap:16px; }
.s-stack-badge { display:inline-flex; align-items:center; gap:5px; border:1px solid color-mix(in srgb,var(--green) 40%,transparent); background:rgba(22,163,74,.07); color:#166534; border-radius:999px; padding:5px 11px; font-size:12px; font-weight:600; white-space:nowrap; flex-shrink:0; }
/* Groups */
.s-group { display:flex; flex-direction:column; gap:14px; }
.s-group + .s-group { border-top:1px solid var(--border); padding-top:18px; }
.s-group-head { display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.s-group-head strong { font-size:14px; font-weight:600; color:var(--text); }
.s-group-head span { font-size:12px; color:var(--subtext); }
/* Field grids */
.settings-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(280px,1fr)); gap:16px; }
.settings-grid.three { grid-template-columns:repeat(auto-fit, minmax(240px,1fr)); }
.settings-grid.compact { grid-template-columns:repeat(2, minmax(220px,1fr)); gap:14px; }
.settings-behavior-grid { grid-template-columns:minmax(220px,.6fr) minmax(220px,.6fr); gap:16px; align-items:start; }
.settings-param-grid textarea { min-height:58px; }
/* Fields */
.s-field { display:flex; flex-direction:column; gap:6px; }
.s-field label { font-size:13px; color:var(--text); font-weight:500; }
.s-label-note { font-weight:400; color:var(--subtext); }
.s-field input, .s-field select, .s-field textarea { background:var(--panel); border:1px solid var(--border); color:var(--text); border-radius:var(--radius); padding:9px 12px; font-size:14px; transition:border-color .15s,box-shadow .15s; width:100%; box-sizing:border-box; }
.s-field input:focus, .s-field select:focus, .s-field textarea:focus { border-color:var(--accent); outline:none; box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 12%,transparent); }
.s-field textarea { min-height:76px; resize:vertical; font-family:monospace; }
.s-hint { font-size:12px; color:var(--subtext); line-height:1.5; }
.s-key-row { display:flex; gap:6px; }
.s-key-row input { flex:1; }
.s-eye-btn { background:var(--panel); border:1px solid var(--border); color:var(--subtext); border-radius:var(--radius); padding:0 13px; font-size:15px; cursor:pointer; flex-shrink:0; transition:color .15s; }
.s-eye-btn:hover { color:var(--text); }
.settings-guide { display: grid; grid-template-columns: 34px minmax(0,1fr); gap: 12px; align-items: start; margin: 14px 0 4px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border)); border-radius: 8px; background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.settings-guide-icon { width: 34px; height: 34px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); font-size: 18px; }
.settings-guide-body { min-width: 0; }
.settings-guide-body strong { display: block; font-size: 13px; color: var(--text); margin-bottom: 3px; }
.settings-guide-body p { margin: 0; color: var(--subtext); font-size: 12px; line-height: 1.5; }
.settings-guide-body ul { margin: 7px 0 0; padding-left: 18px; color: var(--subtext); font-size: 12px; line-height: 1.55; }
.s-field label { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.s-help-tip { position: relative; display: inline-flex; align-items: center; }
.s-help-tip button { width: 18px; height: 18px; border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border)); border-radius: 50%; background: color-mix(in srgb, var(--accent) 7%, var(--panel)); color: var(--accent); display: inline-flex; align-items: center; justify-content: center; padding: 0; cursor: help; font-size: 12px; line-height: 1; }
.s-help-tip button:hover, .s-help-tip button:focus-visible { background: var(--accent); color: #fff; }
.s-tooltip { position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%) translateY(3px); width: min(300px, calc(100vw - 40px)); padding: 9px 10px; border-radius: 7px; background: var(--text); color: var(--bg); font-size: 12px; line-height: 1.45; font-weight: 500; box-shadow: var(--shadow); opacity: 0; pointer-events: none; z-index: 250; transition: opacity .14s ease, transform .14s ease; }
.s-tooltip::after { content: ''; position: absolute; left: 50%; top: 100%; transform: translateX(-50%); border: 6px solid transparent; border-top-color: var(--text); }
.s-help-tip:hover .s-tooltip, .s-help-tip:focus-within .s-tooltip { opacity: 1; transform: translateX(-50%) translateY(0); }
.s-field-tip { display: block; border-left: 3px solid color-mix(in srgb, var(--accent) 32%, var(--border)); padding: 6px 9px; border-radius: 0 6px 6px 0; background: color-mix(in srgb, var(--accent) 4%, var(--panel)); color: var(--subtext); font-size: 12px; line-height: 1.45; }
.s-field:focus-within .s-field-tip { color: var(--text); background: color-mix(in srgb, var(--accent) 7%, var(--panel)); border-left-color: var(--accent); }
.s-page-actions { position: sticky; bottom: 0; background: color-mix(in srgb, var(--surface) 94%, transparent); backdrop-filter: blur(8px); margin: 0 -2px -2px; padding: 14px 2px 2px; z-index: 5; }
@media (max-width: 700px) { .settings-guide { grid-template-columns: 1fr; } .settings-guide-icon { display: none; } .s-tooltip { display: none; } }
/* STT layout */
.stt-settings-grid { grid-template-columns:minmax(320px,.65fr) minmax(240px,1fr); }
.settings-mini-actions { margin-top:4px; gap:8px; flex-wrap:wrap; }
.settings-mini-actions button { min-height:32px; padding:6px 11px; font-size:12px; }
/* Captures toggle grid */
.s-toggle-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px,1fr)); gap:10px; }
.s-toggle-row { display:flex; align-items:flex-start; gap:12px; cursor:pointer; padding:10px 12px; border:1px solid var(--border); border-radius:var(--radius); background:var(--panel); transition:border-color .15s; }
.s-toggle-row:hover { border-color:var(--accent); }
.s-toggle-row input[type="checkbox"] { margin-top:2px; flex-shrink:0; accent-color:var(--accent); width:16px; height:16px; cursor:pointer; }
.s-toggle-title { display:block; font-size:13px; font-weight:600; color:var(--text); margin-bottom:2px; }
.s-toggle-row .s-hint { display:block; margin:0; }
/* Page save/reload actions */
.s-page-actions { border-top:1px solid var(--border); padding-top:14px; display:flex; gap:10px; }
.s-page-actions button { min-width:120px; }
/* Log viewer */
.s-log-toolbar { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.s-log-live-label { display:inline-flex; align-items:center; gap:6px; font-size:13px; color:var(--subtext); cursor:pointer; padding:0 4px; }
.s-log-live-label input { accent-color:var(--accent); cursor:pointer; }
.s-log-count { font-size:12px; color:var(--subtext); margin-left:auto; }
.s-log-filters { display:flex; gap:6px; flex-wrap:wrap; }
.s-log-filter { border:1px solid var(--border); background:transparent; color:var(--subtext); border-radius:999px; padding:3px 10px; font-size:12px; cursor:pointer; transition:all .15s; }
.s-log-filter:hover { border-color:var(--accent); color:var(--accent); }
.s-log-filter.is-active { background:var(--accent); border-color:var(--accent); color:#fff; }
.s-log-viewer { background:var(--panel); border:1px solid var(--border); border-radius:var(--radius); padding:12px 14px; font-family:monospace; font-size:12px; line-height:1.6; max-height:75vh; overflow-y:auto; display:flex; flex-direction:column; gap:1px; }
.s-log-empty { color:var(--subtext); font-family:inherit; text-align:center; padding:24px 0; }
.s-log-row { display:grid; grid-template-columns:max-content max-content 1fr; gap:12px; align-items:baseline; padding:2px 0; border-bottom:1px solid color-mix(in srgb,var(--border) 50%,transparent); }
.s-log-row:last-child { border-bottom:none; }
.s-log-ts { color:var(--subtext); font-size:11px; white-space:nowrap; }
.s-log-level { font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; }
.s-log-level.ERROR, .s-log-level.CRITICAL { color:var(--red); }
.s-log-level.WARNING { color:#f59e0b; }
.s-log-level.INFO { color:var(--accent); }
.s-log-level.DEBUG { color:var(--subtext); }
.s-log-msg { color:var(--text); word-break:break-all; }
/* About */
.s-about-block { display:flex; flex-direction:column; gap:14px; max-width:640px; }
.s-about-name { font-size:20px; font-weight:700; color:var(--text); display:flex; align-items:center; gap:8px; }
.s-about-name .mdi { font-size:22px; color:var(--accent); }
.s-about-desc { font-size:14px; color:var(--subtext); line-height:1.65; margin:0; }
.s-about-stack { display:flex; flex-wrap:wrap; gap:8px; }
.s-about-chip { display:inline-flex; align-items:center; gap:5px; background:var(--panel); border:1px solid var(--border); border-radius:var(--radius); padding:4px 10px; font-size:12px; color:var(--subtext); }
.s-about-backends { display:flex; flex-wrap:wrap; gap:8px; margin-top:4px; }
.s-about-backend { display:inline-flex; align-items:center; gap:6px; border:1px solid var(--border); border-radius:var(--radius); padding:5px 10px; font-size:12px; color:var(--subtext); }
.s-about-backend.online { border-color:color-mix(in srgb,var(--green) 50%,transparent); color:var(--green); }
.s-about-backend.offline { opacity:.55; }
.s-about-backend .mdi { font-size:11px; }
/* Responsive */
@media (max-width:1100px) { .settings-grid.compact { grid-template-columns:1fr; } .settings-behavior-grid { grid-template-columns:1fr; } }
@media (max-width:900px) { .stt-settings-grid { grid-template-columns:1fr; } }
/* Accessibility helpers */
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.skip-link { position: fixed; left: 12px; top: 12px; z-index: 6000; transform: translateY(-160%); background: var(--accent); color: #fff; padding: 9px 13px; border-radius: 7px; font-weight: 800; box-shadow: var(--shadow); }
.skip-link:focus { transform: translateY(0); outline: 3px solid #fff; outline-offset: 2px; }
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible, .nav-item:focus-visible, .nav-tree-item:focus-visible { outline: 3px solid color-mix(in srgb, var(--accent) 78%, white); outline-offset: 2px; }
/* ── Toast ──────────────────────────────────────────────────────────────── */
#toast { position: fixed; top: 50%; left: 50%; background: var(--surface); border: 2px solid var(--accent); border-left-width: 8px; color: var(--text); padding: 16px 20px; border-radius: 8px; font-size: 15px; font-weight: 700; opacity: 0; transform: translate(-50%, calc(-50% + 12px)) scale(.98); transition: opacity .18s, transform .18s; pointer-events: none; z-index: 5000; max-width: min(520px, calc(100vw - 40px)); min-width: min(360px, calc(100vw - 40px)); box-shadow: 0 20px 70px rgba(0,0,0,.35); text-align: center; }
#toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
#toast.success { border-color: var(--green); color: var(--green); }
#toast.error { border-color: var(--red); color: var(--red); }
#toast.info { border-color: var(--accent); color: var(--accent); }
/* ── Status bar ─────────────────────────────────────────────────────────── */
#status-bar {
background: var(--surface); border-top: 1px solid var(--border);
padding: 4px 18px; font-size: 12px; color: var(--subtext);
min-height: 24px; flex-shrink: 0;
display: flex; align-items: center; gap: 16px; min-width: 0;
}
#status-message { flex: 0 1 auto; min-width: 120px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#status-engines {
margin-left: auto; min-width: 0; display: flex; align-items: center;
justify-content: flex-end; gap: 16px; overflow: hidden;
}
.status-engine {
min-width: 0; display: inline-flex; align-items: center; gap: 5px;
white-space: nowrap; color: var(--subtext);
background: none; border: none; padding: 2px 4px; margin: 0; border-radius: 4px;
font: inherit; cursor: pointer;
}
.status-engine:hover { background: var(--panel); color: var(--text); }
.status-engine-caret { font-size: 13px; opacity: .55; }
.status-dot {
width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto;
background: var(--red); box-shadow: 0 0 0 2px color-mix(in srgb, var(--red) 14%, transparent);
}
.status-engine.ok .status-dot { background: var(--green); box-shadow: 0 0 0 2px color-mix(in srgb, var(--green) 16%, transparent); }
.status-engine-label { font-weight: 800; color: var(--text); }
.status-engine-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; max-width: min(34vw, 420px); }
.status-engine.bad .status-engine-value { color: var(--red); }
/* Fly-up menu opened by clicking a footer engine chip — quick-switch the
active LLM model / STT backend / TTS backend without opening Settings. */
.status-flyup {
position: fixed; z-index: 2000; min-width: 200px; max-width: 320px;
max-height: 320px; display: flex; flex-direction: column;
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
box-shadow: 0 -8px 24px rgba(0,0,0,.18); padding: 4px;
}
.status-flyup-search {
display: flex; align-items: center; gap: 6px; padding: 4px 8px 6px;
border-bottom: 1px solid var(--border); margin-bottom: 4px; flex-shrink: 0;
}
.status-flyup-search .mdi { font-size: 14px; color: var(--subtext); flex-shrink: 0; }
.status-flyup-search input {
flex: 1; min-width: 0; border: none; background: none; outline: none;
font-size: 12.5px; color: var(--text); font-family: inherit;
}
.status-flyup-list { overflow-y: auto; }
.status-flyup-item {
display: flex; align-items: center; gap: 6px; width: 100%; text-align: left;
padding: 7px 10px; border: none; background: none; border-radius: 6px;
font-size: 12.5px; color: var(--text); cursor: pointer;
}
.status-flyup-item:hover { background: var(--panel); }
.status-flyup-item.is-active { color: var(--accent); font-weight: 700; }
.status-flyup-item .mdi { font-size: 14px; flex-shrink: 0; }
.status-flyup-empty { padding: 10px 12px; font-size: 12px; color: var(--subtext); font-style: italic; }
@media (max-width: 820px) {
#status-bar { align-items: flex-start; flex-direction: column; gap: 4px; }
#status-engines { margin-left: 0; width: 100%; justify-content: flex-start; flex-wrap: wrap; gap: 8px 14px; }
.status-engine-value { max-width: 72vw; }
}
.info-box { background: var(--panel); border-radius: var(--radius); padding: 12px 16px; font-family: monospace; font-size: 13px; color: var(--accent); word-break: break-all; }
hr { border: none; border-top: 1px solid var(--border); }
.note { font-size: 13px; color: var(--subtext); line-height: 1.5; }
code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-family: monospace; font-size: 12px; }
/* ── Library ────────────────────────────────────────────────────────────── */
.lib-toolbar { display: flex; align-items: center; gap: 12px; min-height: 34px; margin-bottom: 6px; }
.lib-toolbar h2 { flex: 0 0 auto; }
.lib-toolbar .spacer { flex: 1 1 auto; }
.show-disabled-control { font-size: 13px; color: var(--subtext); display:flex; align-items:center; gap:7px; cursor:pointer; white-space:nowrap; }
.loading-panel { min-height: 170px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--subtext); padding: 18px; }
.loading-box { width: min(680px,100%); display: flex; flex-direction: column; gap: 13px; }
.loading-head { display: flex; align-items: center; gap: 10px; color: var(--text); font-weight: 700; font-size: 14px; }
.spinner { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--border); border-top-color: var(--accent); animation: spin .8s linear infinite; flex: 0 0 auto; }
@keyframes spin { to { transform: rotate(360deg); } }
.loading-sub { font-size: 13px; line-height: 1.4; }
.skeleton-stack { display: flex; flex-direction: column; gap: 8px; }
.skeleton-row { height: 38px; border-radius: 6px; border: 1px solid var(--border); background: linear-gradient(90deg, var(--panel), rgba(37,99,235,.06), var(--panel)); background-size: 220% 100%; animation: skeletonSweep 1.15s ease-in-out infinite; }
@keyframes skeletonSweep { 0% { background-position: 120% 0; } 100% { background-position: -120% 0; } }
.library-benchmark-panel { display: none !important; }
.library-benchmark-panel .field { min-width: 0; }
#benchmark-sample-text { min-height: 62px; resize: vertical; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); padding: 10px 14px; font-size: 14px; font-family: inherit; width: 100%; }
.benchmark-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.volume-actions { align-items: flex-end; }
.target-db-field { display: flex; flex-direction: column; gap: 4px; flex: 0 0 112px; color: var(--subtext); font-size: 14px; text-transform: uppercase; letter-spacing: .06em; }
.target-db-field input { width: 112px; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); padding: 8px 10px; font-size: 14px; }
.play-mode-field select { width: 100%; }
.benchmark-progress { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); display: flex; flex-direction: column; gap: 7px; }
.benchmark-progress[hidden] { display: none; }
.benchmark-progress-head { display: flex; justify-content: space-between; gap: 12px; color: var(--subtext); font-size: 13px; }
#benchmark-progress-label { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.benchmark-progress-track { height: 8px; background: var(--bg); border-radius: 999px; overflow: hidden; border: 1px solid var(--border); }
#benchmark-progress-bar { height: 100%; width: 0%; background: var(--accent); transition: width .2s ease; }
.benchmark-live-stats { display: grid; grid-template-columns: repeat(6, minmax(72px,1fr)); gap: 6px; font-size: 12px; color: var(--subtext); }
.benchmark-live-stats span { border: 1px solid var(--border); border-radius: 5px; padding: 5px 7px; background: var(--bg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.benchmark-live-last { min-height: 1.3em; font-size: 12px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.library-insights { display: grid; grid-template-columns: repeat(6, minmax(100px,1fr)); gap: 6px; margin-top: 5px; }
.insight { border: 1px solid var(--border); border-radius: 6px; background: var(--panel); min-height: 30px; padding: 5px 9px; display:flex; align-items:baseline; gap:8px; }
.insight[data-filter] { cursor: pointer; }
.insight[data-filter]:hover, .insight.active { border-color: var(--accent); background: rgba(37,99,235,.08); }
.insight strong { display: block; color: var(--text); font-size: 14px; line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width:0; }
.insight span { display: block; color: var(--subtext); font-size: 10px; text-transform: uppercase; letter-spacing: .06em; margin-top: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width:0; line-height: 1.1; }
.library-filter-note { border: 1px solid var(--border); border-radius: 6px; background: rgba(37,99,235,.05); color: var(--subtext); padding: 8px 10px; font-size: 13px; display: flex; justify-content: space-between; align-items: center; gap: 10px; margin: 8px 0; }
.library-filter-note strong { color: var(--text); }
.library-filter-note button { flex: 0 0 auto; }
.library-control-panel { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; align-items: end; padding: 12px; border: 1px solid var(--border); border-radius: 7px; background: rgba(37,99,235,.035); }
.library-control-panel .field { min-width: 0; }
.library-control-panel input, .library-control-panel select { width: 100%; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); padding: 8px 10px; }
.library-list-title { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 8px 2px 8px; color: var(--subtext); font-size: 12px; text-transform: uppercase; letter-spacing: .08em; font-weight: 800; }
.library-list-title strong { color: var(--text); font-size: 13px; }
.library-action-row { display: grid; grid-template-columns: auto 1fr auto auto; gap: 8px; align-items: center; margin: 8px 0 12px; }
.voice-action-group { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.voice-action-group button { min-height: 34px; padding: 7px 12px; white-space: nowrap; }
.action-add { grid-column: 1; }
.action-refresh { grid-column: 2; justify-content: flex-start; }
.action-refresh button { flex: 0 0 auto; }
.action-db { display: none; }
.action-benchmark { display: none; }
.action-copy { display: none; }
.action-show-disabled { grid-column: 4; justify-self: end; align-self: center; min-height: 34px; padding: 0 4px; margin: 0; }
.benchmark-confirm { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 10px 0 0 132px; padding: 10px 12px; max-width: 760px; border: 1px solid rgba(217,119,6,.45); border-radius: 7px; background: rgba(217,119,6,.07); color: var(--text); box-shadow: var(--shadow); }
.benchmark-confirm[hidden] { display: none; }
.benchmark-confirm strong { color: var(--yellow); font-size: 13px; }
.benchmark-confirm span { color: var(--subtext); font-size: 13px; line-height: 1.35; flex: 1 1 260px; }
.benchmark-confirm button { white-space: nowrap; }
.benchmark-confirm .benchmark-confirm-start { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.disabled-info { background: rgba(37,99,235,.06); border: 1px solid var(--border); border-radius: var(--radius); padding: 11px 15px; font-size: 13px; color: var(--subtext); line-height: 1.6; }
.disabled-info strong { color: var(--text); }
/* Voice list rows - Card grid layout */
.vl-grid { display: grid; grid-template-columns: repeat(2, minmax(320px, 1fr)); gap: 16px; padding: 12px 0; }
.vl-header { display: none; }
.vl-row { position: relative; padding: 16px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); transition: all .2s; display: flex; flex-direction: column; gap: 12px; }
.vl-row:hover { border-color: var(--accent); background: rgba(37,99,235,.02); box-shadow: 0 8px 24px rgba(37,99,235,.15); transform: translateY(-2px); }
.vl-row.vr-disabled { opacity: .42; }
.vl-row.edit-open { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(37,99,235,.15); }
.vr-main-row { display: flex; flex-direction: column; gap: 12px; width: 100%; }
.vr-photo { width: 100%; height: 200px; border-radius: 12px; overflow: hidden; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); position: relative; display: flex; align-items: center; justify-content: center; }
.vr-photo img { width: 100%; height: 100%; object-fit: cover; }
.vr-photo .ph-icon { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-size: 64px; color: white; font-weight: 700; }
.vr-photo:hover::after { content: ''; }
.vr-photo.drag-over { opacity: 0.8; outline: 3px dashed var(--accent); outline-offset: -4px; transition: all 0.2s; }
.vr-identity { display: flex; gap: 10px; align-items: center; min-width: 0; width: 100%; }
.vr-flag { display: none; }
.vr-flag .flag-emoji { font-size: 22px; line-height: 1; transition: transform .15s; }
.vr-flag .flag-code { font-size: 10px; font-family: monospace; font-weight: 700; color: var(--subtext); letter-spacing: .04em; }
.vr-flag:hover .flag-emoji { transform: scale(1.18); }
.flag-picker { display: none; }
.vr-gender { display: none; }
.gender-badge { display: inline-flex; align-items: center; gap: 5px; border-radius: 6px; padding: 4px 10px; background: rgba(37,99,235,.08); border: 1px solid rgba(37,99,235,.18); cursor: pointer; transition: border-color .15s, background .15s; font-size: 13px; font-weight: 600; }
.gender-badge:hover { background: rgba(37,99,235,.14); border-color: var(--accent); }
.gender-sym { font-size: 14px; line-height: 1; }
.gender-txt { font-size: 12px; font-weight: 600; letter-spacing: .01em; }
.g-f { color: #e91e8c; }
.g-m { color: #0ea5e9; }
.g-n { color: #8b5cf6; }
.vr-name { display: flex; align-items: center; gap: 4px; min-width: 0; flex: 1; }
.vr-name-text { font-weight: 800; color: var(--text); font-family: inherit; font-size: 15px; overflow: hidden; text-overflow: ellipsis; flex: 1; cursor: text; white-space: nowrap; }
.vr-name-input { flex: 1; background: var(--bg); border: 1px solid var(--accent); color: var(--text); border-radius: 4px; padding: 4px 8px; font-size: 13px; font-family: monospace; min-width: 0; }
.icon-btn { background: none; border: none; padding: 3px 5px; font-size: 14px; color: var(--subtext); border-radius: 4px; cursor: pointer; flex-shrink: 0; }
.icon-btn:hover { background: var(--border); color: var(--text); }
.rename-confirm { display: none; gap: 3px; }
.rename-confirm.show { display: flex; }
.vr-type { display: none; }
.vr-length { display: none; }
.vr-db { display: none; }
.vr-bench { display: none; }
.vr-edit { display: flex; justify-content: flex-end; }
.edit-audio-btn { width: 38px; height: 34px; border-radius: 7px; padding: 0; background: rgba(37,99,235,.10); border: 1px solid var(--border); color: var(--accent); font-size: 22px; line-height: 1; display: flex; align-items: center; justify-content: center; }
.edit-audio-btn:hover { border-color: var(--accent); background: rgba(37,99,235,.18); filter: none; }
.benchmark-one-btn { width: 26px; height: 26px; border-radius: 6px; padding: 0; font-size: 12px; }
.vr-rating { display: flex; gap: 2px; font-size: 18px; justify-content: flex-start; align-items: center; min-height: 31px; }
.star { cursor: pointer; color: var(--border); transition: color .1s; }
.star.on { color: var(--yellow); }
.vr-rating:hover .star { color: var(--yellow); }
.vr-rating:hover .star ~ .star { color: var(--border); }
.vr-play { display: flex; align-items: center; justify-content: flex-start; }
.vr-play-group { display: flex; gap: 8px; align-items: center; justify-content: flex-start; }
.vr-play button { width: 40px; height: 40px; border-radius: 50%; background: var(--accent); color: var(--on-accent); font-size: 13px; display: flex; align-items: center; justify-content: center; padding: 0; }
.vr-play-synth button { background: var(--teal); }
.vr-toggle { display: flex; justify-content: center; }
.toggle { position: relative; display: inline-block; width: 42px; height: 24px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.t-slider { position: absolute; cursor: pointer; inset: 0; background: var(--border); border-radius: 24px; transition: .2s; }
.t-slider::before { position: absolute; content: ''; height: 18px; width: 18px; left: 3px; bottom: 3px; background: var(--bg); border-radius: 50%; transition: .2s; }
.toggle input:checked + .t-slider { background: var(--green); }
.toggle input:checked + .t-slider::before { transform: translateX(18px); }
.vr-delete { display: flex; justify-content: flex-end; }
.delete-btn { width: 30px; height: 30px; border-radius: 6px; padding: 0; background: none; border: 1px solid transparent; font-size: 15px; color: var(--subtext); display: flex; align-items: center; justify-content: center; transition: background .15s, border-color .15s, color .15s; }
.delete-btn:hover { background: rgba(220,38,38,.12); border-color: var(--red); color: var(--red); filter: none; }
.delete-confirm { position: absolute; right: 38px; top: 16px; z-index: 20; display: none; align-items: center; gap: 8px; min-width: 270px; max-width: min(380px, calc(100vw - 80px)); padding: 8px 9px; border: 1px solid rgba(220,38,38,.45); border-radius: 7px; background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
.delete-confirm strong { font-size: 12px; color: var(--red); white-space: nowrap; }
.delete-confirm span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--subtext); }
.delete-confirm button { height: 28px; padding: 0 10px; border-radius: 6px; font-size: 12px; white-space: nowrap; }
.delete-confirm .delete-confirm-go { background: rgba(220,38,38,.12); border-color: rgba(220,38,38,.45); color: var(--red); }
.vl-row.delete-pending { border-color: rgba(220,38,38,.65); }
.vl-row.delete-pending .delete-confirm { display: flex; }
.vl-row.delete-pending .delete-btn { background: rgba(220,38,38,.12); border-color: var(--red); color: var(--red); }
.vr-detail-row { display: none; }
.vr-detail-active { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; min-height: 31px; }
.vr-detail-active .vr-active-tools { justify-content: flex-end; width: 100%; }
.vr-detail-delete { display: flex; align-items: start; justify-content: flex-end; min-height: 31px; padding-top: 18px; }
.vr-active-tools { display: flex; gap: 10px; align-items: center; }
.vr-ref, .vr-note, .vr-source { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
.vr-ref .vr-inline, .vr-note .vr-inline, .vr-source .vr-inline { display: flex; gap: 6px; align-items: center; min-width: 0; }
.vr-ref input { width: 100%; min-width: 0; background: transparent; border: none; border-bottom: 1px solid transparent; color: var(--subtext); font-size: 13px; padding: 3px 5px; font-family: inherit; outline: none; }
.vr-ref input:focus { border-bottom-color: var(--accent); color: var(--text); }
.vr-ref input::placeholder { color: var(--placehld); font-style: italic; }
.ref-transcribe-btn { width: 28px; height: 28px; padding: 0; border-radius: 6px; background: none; border: 1px solid transparent; color: var(--subtext); flex-shrink: 0; font-size: 14px; }
.ref-transcribe-btn:hover { background: var(--border); color: var(--text); filter: none; }
.vr-note input, .vr-source input { width: 100%; background: transparent; border: none; border-bottom: 1px solid var(--border); color: var(--text); font-size: 13px; padding: 3px 5px; font-family: inherit; outline: none; }
.vr-note input:focus, .vr-source input:focus { border-bottom-color: var(--accent); }
.vr-note input::placeholder, .vr-source input::placeholder { color: var(--placehld); }
.vr-row-subtle { color: var(--subtext); font-size: 14px; font-family: monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vr-optimizer { grid-column: auto; display: none; margin: 6px 0 0; width: 100%; box-sizing: border-box; }
.vl-row.edit-open .vr-optimizer { display: block; }
.optimizer-grid { display: grid; grid-template-columns: minmax(280px,1.2fr) minmax(280px,1fr); gap: 12px; align-items: start; }
.opt-group { box-shadow: var(--shadow); margin-top: 20px; margin-right: 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); padding: 10px; min-width: 0; }
.opt-group-title { font-size: 14px; font-weight: 800; color: var(--accent); text-transform: uppercase; letter-spacing: .08em;}
.opt-group-note { font-size: 12px; color: var(--subtext); line-height: 1.4; margin-top: 7px; }
.opt-compare-panel { grid-column: 1 / -1; }
.opt-compare-grid { display: grid; grid-template-columns: repeat(2, minmax(240px,1fr)); gap: 10px; }
.opt-compare-card { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.opt-compare-card strong { font-size: 12px; color: var(--text); }
.opt-compare-card audio { width: 100%; }
.opt-style-panel { grid-column: 1 / -1; display: grid; grid-template-columns: minmax(280px,1fr) minmax(260px,.8fr); gap: 10px; }
.opt-style-preview-box { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.opt-style-audio { width: 100%; display: none; }
.backend-help { border: 1px solid var(--border); border-radius: 6px; background: rgba(37,99,235,.05); padding: 10px 12px; color: var(--subtext); font-size: 13px; line-height: 1.45; display: grid; gap: 7px; min-width: min(100%, 620px); }
.backend-help strong { color: var(--text); }
.backend-help-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.backend-tag { border: 1px solid var(--border); border-radius: 4px; padding: 2px 6px; background: var(--panel); color: var(--subtext); font-size: 12px; }
.backend-tag.good { color: #166534; border-color: rgba(22,163,74,.35); } /* AA on light */
.backend-tag.warn { color: #92400E; border-color: rgba(217,119,6,.35); } /* AA on light */
.backend-metrics-row { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 2px; }
.backend-metric-tag { border: 1px solid rgba(99,102,241,.3); border-radius: 4px; padding: 1px 6px; background: rgba(99,102,241,.07); color: #1D4ED8; font-size: 11px; white-space: nowrap; }
.style-backend-warn {
margin-top: 6px; padding: 7px 10px; border-radius: 6px;
background: rgba(220,38,38,.07); border: 1px solid rgba(220,38,38,.25);
color: var(--red); font-size: 12px; line-height: 1.45;
}
.opt-wave { cursor: crosshair; touch-action: none; width: 100%; height: 86px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; display: block; }
.opt-controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: end; margin-top: 8px; }
.crop-duration-hint { align-self: center; color: var(--subtext); font-size: 12px; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); }
.crop-duration-hint.ok { color: var(--green); border-color: rgba(22,163,74,.35); }
.crop-duration-hint.warn { color: var(--yellow); border-color: rgba(217,119,6,.35); }
.optimizer-workflow { grid-column: 1 / -1; }
.opt-maintenance { grid-column: 1 / -1; }
.opt-field { display: flex; flex-direction: column; gap: 4px; }
.opt-field label { font-size: 10px; color: var(--subtext); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.opt-field input { width: 74px; background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 5px; padding: 6px 8px; font-size: 12px; font-family: monospace; }
.opt-field select { background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 5px; padding: 6px 8px; font-size: 12px; font-family: monospace; }
.opt-field.wide { flex: 1 1 220px; }
.opt-field.wide input, .opt-field.wide select { width: 100%; min-width: 180px; }
.opt-transcript { width: 100%; min-height: 86px; background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 8px 10px; font-size: 13px; resize: vertical; }
.opt-status { font-size: 12px; color: var(--subtext); min-height: 16px; margin-top: 6px; }
.opt-restart-note { font-size: 12px; color: var(--yellow); align-self: center; }
.opt-restart-note[hidden] { display: none; }
.opt-restart-needed .opt-restart-tts { border-color: var(--yellow); color: var(--yellow); }
/* ── Audio bar ──────────────────────────────────────────────────────────── */
#lib-audio-bar { background: var(--panel); border: 1px solid var(--accent); border-radius: var(--radius); padding: 10px 14px; }
#lib-audio-bar audio { width: 100%; }
#lib-audio-bar .lib-audio-label { font-size: 13px; color: var(--accent); font-family: monospace; margin-bottom: 5px; font-weight: 700; }
/* ── Library add panel ──────────────────────────────────────────────────── */
.lib-add-panel { display: none; border: 1px solid rgba(37,99,235,.3); border-radius: 8px; background: rgba(37,99,235,.04); padding: 16px; margin: 6px 0 12px; }
.lib-add-panel.open { display: block; }
.lib-add-stack { display: flex; flex-direction: column; gap: 16px; }
.lib-add-section { border: 1px solid rgba(37,99,235,.2); border-radius: 8px; background: var(--surface); padding: 16px; }
.lib-add-section > h2 { color: var(--accent); margin-bottom: 14px !important; letter-spacing: .08em; }
.lib-add-input-grid { display: grid; grid-template-columns: minmax(300px,.9fr) minmax(420px,1.1fr); gap: 12px; align-items: stretch; }
.lib-add-import-box { border: 1px solid rgba(37,99,235,.2); border-radius: 8px; background: var(--panel); padding: 14px; display: flex; flex-direction: column; gap: 14px; }
.lib-add-record-box { border: 1px solid rgba(37,99,235,.2); border-radius: 8px; background: var(--panel); padding: 14px; display: flex; flex-direction: column; gap: 10px; }
.lib-add-drop { border: 2px dashed rgba(37,99,235,.4); border-radius: 8px; min-height: 150px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; cursor: pointer; color: var(--subtext); text-align: center; padding: 16px; transition: border-color .15s, background .15s, color .15s; background: rgba(37,99,235,.03); }
.lib-add-drop.drag-over { border-color: var(--accent); background: rgba(37,99,235,.08); color: var(--accent); }
.lib-add-drop strong { color: var(--text); font-size: 16px; }
.lib-add-drop span { font-size: 12px; color: var(--subtext); }
.lib-add-source-box { display: flex; flex-direction: column; gap: 10px; }
.lib-add-source-box input[type=text] { width: 100%; background: var(--surface); border: 1px solid rgba(37,99,235,.22); color: var(--text); border-radius: var(--radius); padding: 9px 12px; font-size: 14px; }
.lib-add-source-preview { display: none; align-items: center; gap: 10px; border: 1px solid rgba(37,99,235,.25); border-radius: 8px; background: rgba(37,99,235,.06); padding: 8px 10px; min-width: 0; }
.lib-add-source-preview.open { display: flex; }
.lib-add-source-preview img { width: 44px; height: 44px; border-radius: 6px; object-fit: cover; border: 1px solid var(--border); background: var(--bg); }
.lib-add-source-preview strong { display: block; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-add-source-preview span { display: block; color: var(--subtext); font-size: 12px; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.record-head .note { font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); }
.record-head-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.record-head-actions button { padding: 6px 10px; font-size: 12px; }
.lib-add-recorder-tools { display: flex; flex-direction: column; gap: 10px; }
.lib-add-mic-row { display: grid; grid-template-columns: minmax(240px,1fr) minmax(260px,.9fr); gap: 10px; align-items: stretch; }
.sample-read-box, .mic-monitor-box { border: 1px solid rgba(37,99,235,.18); border-radius: 6px; background: var(--surface); padding: 12px; }
.mic-monitor-box { padding: 10px; display: flex; flex-direction: column; gap: 8px; }
.sample-head, .mic-monitor-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 6px; }
.sample-head label, .mic-monitor-head span:first-child { font-size: 14px; font-weight: 700; color: var(--accent); text-transform: uppercase; letter-spacing: .06em; }
.sample-head select { background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 8px; font-size: 13px; min-width: 150px; }
.sample-sentence { width: 100%; min-height: 120px; font-size: 16px; line-height: 1.55; color: var(--text); background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--accent); border-radius: 6px; padding: 10px 12px; resize: vertical; font-family: inherit; }
.sample-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 8px; }
.sample-actions button { padding: 6px 10px; font-size: 12px; }
.recording-tips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.recording-tip { font-size: 14px; color: var(--subtext); border: 1px solid rgba(37,99,235,.25); border-radius: 999px; padding: 3px 8px; background: rgba(37,99,235,.07); }
.meter-readout { font-family: monospace; color: var(--subtext); font-size: 12px; white-space: nowrap; }
.mic-meter { display: grid; grid-template-columns: repeat(18, 1fr); gap: 3px; height: 24px; align-items: end; margin-bottom: 8px; }
.mic-meter .bar { height: 7px; border-radius: 3px; background: var(--border); transition: height .08s linear, background .08s linear, opacity .08s linear; opacity: .55; }
.mic-meter .bar.on { opacity: 1; background: var(--green); }
.mic-meter .bar.hot { background: var(--yellow); }
.mic-meter .bar.clip { background: var(--red); }
.mic-live-wave { width: 100%; height: 52px; border-radius: 4px; display: block; background: rgba(0,0,0,.06); margin-bottom: 4px; }
[data-theme="dark"] .mic-live-wave { background: rgba(17,17,27,.6); }
.mic-buttons { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px,1fr)); gap: 8px; align-content: start; min-width: 0; }
.mic-buttons button { padding-left: 10px; padding-right: 10px; min-height: 44px; }
.mic-timer { font-family: monospace; font-size: 13px; color: var(--subtext); }
.mic-gain-row { display: grid; grid-template-columns: auto minmax(120px,1fr) 42px; gap: 8px; align-items: center; }
.mic-gain-row label { font-size: 12px; color: var(--accent); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.mic-gain-row input[type=range] { width: 100%; accent-color: var(--accent); }
.mic-gain-value { font-family: monospace; color: var(--text); font-size: 12px; text-align: right; }
.mic-help-panel { display: none; border: 1px solid var(--border); border-radius: 6px; background: rgba(37,99,235,.06); padding: 10px; color: var(--subtext); font-size: 12px; line-height: 1.45; }
.mic-help-panel.open { display: block; }
.mic-help-panel strong { color: var(--text); }
.mic-help-panel ul { margin: 7px 0 0 18px; }
.mic-help-panel li { margin: 4px 0; }
.lib-add-audio-row { display: grid; grid-template-columns: minmax(240px,1fr) auto; gap: 10px; align-items: center; margin-top: 14px; }
.lib-add-panel audio { width: 100%; }
.lib-add-panel .opt-wave { cursor: crosshair; touch-action: none; }
.lib-add-panel textarea { width: 100%; min-height: 80px; background: var(--surface); border: 1px solid rgba(37,99,235,.22); color: var(--text); border-radius: 6px; padding: 8px 10px; font-size: 13px; resize: vertical; }
.lib-add-panel textarea.sample-sentence { min-height: 128px; font-size: 16px; line-height: 1.55; border-left: 3px solid var(--accent); padding: 10px 12px; }
.lib-add-name-grid { display: grid; grid-template-columns: 100px 100px minmax(240px,1fr); gap: 8px; align-items: end; }
.lib-add-name-grid .opt-field input, .lib-add-name-grid .opt-field select { width: 100%; }
#lib-add-status { border-radius: 6px; background: rgba(37,99,235,.07); padding: 8px 10px; color: var(--subtext); font-size: 12px; }
/* ── Design preset library ──────────────────────────────────────────────── */
.design-preset-library { display: flex; flex-direction: column; gap: 6px; }
.design-preset-row { display: grid; grid-template-columns: minmax(120px,.8fr) 70px 90px minmax(180px,1.5fr) minmax(180px,1.4fr) 220px; gap: 8px; align-items: center; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); padding: 8px 10px; font-size: 13px; }
.design-preset-row .preset-desc, .design-preset-row .preset-transcript { color: var(--subtext); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.design-preset-row .preset-actions { display: flex; gap: 6px; justify-content: flex-end; }
/* ── Get voices ─────────────────────────────────────────────────────────── */
.getvoices-source-editor { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: stretch; }
.getvoices-source-editor textarea { width: 100%; min-height: 96px; resize: vertical; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); padding: 10px 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }
.getvoices-source-buttons { display: flex; flex-direction: column; gap: 8px; min-width: 132px; }
.getvoices-toolbar { display: grid; grid-template-columns: minmax(160px,1fr) 170px 150px 130px 120px auto; gap: 8px; align-items: center; margin-top: 10px; }
.getvoices-toolbar input, .getvoices-toolbar select { width: 100%; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); padding: 9px 12px; }
.getvoices-summary { display: grid; grid-template-columns: repeat(4, minmax(130px,1fr)); gap: 8px; }
.getvoices-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px,1fr)); gap: 12px; }
.voice-source-card { border: 1px solid var(--border); border-radius: 7px; background: var(--surface); padding: 12px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.voice-source-head { display: flex; gap: 12px; align-items: flex-start; min-width: 0; }
.voice-source-thumb { width: 72px; height: 72px; border-radius: 7px; object-fit: cover; background: var(--bg); border: 1px solid var(--border); flex: 0 0 auto; }
.voice-source-title { min-width: 0; flex: 1; }
.voice-source-title strong { display: block; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voice-source-title span { display: block; color: var(--subtext); font-size: 12px; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voice-source-desc { color: var(--subtext); font-size: 13px; line-height: 1.4; min-height: 2.8em; }
.voice-source-card audio { width: 100%; min-height: 32px; }
.voice-source-actions { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }
.voice-source-actions a, .voice-source-actions button { font-size: 12px; padding: 7px 9px; min-height: 32px; }
.voice-source-pill { border: 1px solid var(--border); color: var(--subtext); border-radius: 999px; padding: 3px 7px; font-size: 12px; }
.vs-import-footer { display: flex; justify-content: flex-end; padding-top: 4px; margin-top: -4px; border-top: 1px solid var(--border); }
.vs-import-footer .btn-primary { font-size: 12px; padding: 7px 12px; }
/* ── Integrations ───────────────────────────────────────────────────────── */
.integration-toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.integration-grid { display: flex; flex-direction: column; gap: 12px; }
.integration-card { border: 1px solid var(--border); border-radius: 6px; background: var(--surface); padding: 13px; display: flex; flex-direction: column; gap: 10px; width: 100%; }
.integration-card h3 { font-size: 15px; color: var(--text); margin: 0; display: flex; align-items: center; gap: 7px; cursor: pointer; user-select: none; }
.integration-card h3:hover { opacity: .8; }
.icard-logo { width: 16px; height: 16px; flex-shrink: 0; border-radius: 2px; object-fit: contain; }
.icard-icon { font-size: 16px; flex-shrink: 0; color: var(--accent); line-height: 1; }
.icard-chev { display: inline-flex; align-items: center; justify-content: center; margin-left: auto; flex-shrink: 0; width: 16px; height: 16px; border-radius: 4px; background: var(--panel); border: 1px solid var(--border); color: var(--accent); font-size: 10px; line-height: 1; transition: transform .2s; }
.icard-chev::before { content: '▾'; }
.integration-card.icard-closed .icard-chev { transform: rotate(-90deg); }
.icard-body { display: flex; flex-direction: column; gap: 10px; }
.integration-card p { font-size: 13px; color: var(--subtext); line-height: 1.5; margin: 0; }
.integration-card pre { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; color: var(--text); padding: 10px 12px; font-size: 12px; line-height: 1.45; overflow: auto; min-height: 118px; max-height: 360px; white-space: pre-wrap; }
.integration-card code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background: none; padding: 0; border-radius: 0; }
.integration-card-wide { border-left: 3px solid var(--accent); }
.integration-card-wide pre { max-height: 480px; }
.btn-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* ── Routing ────────────────────────────────────────────────────────────── */
.routing-toolbar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.routing-grid { display: grid; grid-template-columns: 42px minmax(104px,.7fr) minmax(74px,.38fr) minmax(118px,.5fr) minmax(112px,.6fr) minmax(140px,1fr) 96px minmax(120px,.65fr) minmax(120px,.65fr) 42px; gap: 8px; align-items: center; }
/* Input voice holds short tokens (default, DE_M) so it can be narrow; the
language cell now carries a flag plus a code and needs the room instead. */
.route-speed-cell { display: flex; align-items: center; gap: 4px; }
.route-speed-cell input { width: 100%; min-width: 0; text-align: center; }
.route-speed-preview { flex-shrink: 0; width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }
.routing-header { padding: 8px 10px 10px; border-bottom: 1px solid var(--border); }
.routing-header div { font-size: 14px; font-weight: 700; color: var(--subtext); text-transform: uppercase; letter-spacing: .07em; }
.routing-row { border: 1px solid var(--border); border-radius: 6px; background: var(--surface); padding: 8px 10px; }
.routing-row input, .routing-row select { width: 100%; min-width: 0; background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 7px 8px; font-size: 13px; }
.route-sound-cell { display: grid; grid-template-columns: minmax(0,1fr) auto auto; gap: 5px; align-items: center; }
.route-sound-cell .route-sound-upload, .route-sound-cell .route-sound-pick { min-height: 32px; padding: 6px 8px; font-size: 12px; }
.routing-row .toggle { justify-self: center; }
.routing-delete { width: 34px; height: 32px; padding: 0; }
.routing-help { border: 1px solid var(--border); border-radius: 6px; background: rgba(37,99,235,.05); padding: 12px; color: var(--subtext); font-size: 13px; line-height: 1.55; }
.routing-url-warning { display: none; margin-top: 7px; color: var(--yellow); }
.routing-url-warning.show { display: block; }
.routing-test-row { margin-top: 12px; display: grid; grid-template-columns: minmax(120px,.35fr) minmax(110px,.3fr) minmax(220px,1fr) auto; gap: 8px; align-items: stretch; }
.routing-test-row input, .routing-test-row textarea { width: 100%; min-width: 0; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 8px 10px; font-size: 13px; font-family: inherit; }
.routing-test-row textarea { min-height: 38px; resize: vertical; }
.routing-test-result { margin-top: 8px; font-size: 13px; color: var(--subtext); line-height: 1.45; }
.routing-test-result.warn { color: var(--yellow); }
.routing-test-result.ok { color: var(--green); }
.routing-log-head { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:wrap; }
.routing-log-actions { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.routing-log-filter { min-height:36px; border:1px solid var(--border); border-radius:6px; background:var(--panel); color:var(--text); padding:0 10px; font:inherit; min-width:170px; }
.routing-log-list { display:flex; flex-direction:column; gap:7px; max-height:340px; overflow:auto; padding-right:4px; }
.routing-log-empty { color:var(--subtext); font-size:13px; padding:10px; border:1px dashed var(--border); border-radius:6px; background:var(--panel); }
.routing-log-entry { display:grid; grid-template-columns: 78px 92px minmax(120px,.75fr) minmax(180px,1.1fr) minmax(150px,.8fr) minmax(220px,1.2fr); gap:8px; align-items:center; border:1px solid var(--border); border-radius:6px; background:var(--surface); padding:8px 10px; font-size:12px; min-width: 860px; }
.routing-log-entry .log-time { color:var(--subtext); font-family:monospace; }
.routing-log-entry .log-app, .routing-log-entry .log-voice { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.routing-log-entry .log-meta, .routing-log-entry .log-text { color:var(--subtext); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.routing-log-badge { justify-self:start; border:1px solid var(--border); border-radius:999px; padding:3px 8px; font-size:11px; font-weight:800; text-transform:uppercase; letter-spacing:.06em; color:var(--subtext); background:rgba(37,99,235,.06); }
.routing-log-entry.status-ok .routing-log-badge, .routing-log-entry.status-matched .routing-log-badge, .routing-log-entry.status-streaming .routing-log-badge { color:var(--green); }
.routing-log-entry.status-no_match .routing-log-badge { color:var(--yellow); }
.routing-log-entry.status-error .routing-log-badge { color:var(--red); }
.routing-log-scroll { overflow-x:auto; }
.routing-sound-browser-head { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.routing-sound-browser-actions { display:flex; gap:8px; flex-wrap:wrap; }
.routing-sound-list { display:flex; flex-direction:column; gap:6px; max-height:320px; overflow:auto; padding-right:4px; }
.routing-sound-search { width:100%; background:var(--panel); border:1px solid var(--border); color:var(--text); border-radius:6px; padding:8px 10px; }
.routing-sound-item { display:grid; grid-template-columns:44px minmax(220px,1fr) 90px 96px; gap:8px; align-items:center; border:1px solid var(--border); background:var(--surface); border-radius:6px; padding:8px; }
.routing-sound-item .sound-path { overflow:hidden; white-space:nowrap; text-overflow:ellipsis; font-family:monospace; font-size:12px; }
.routing-sound-item .sound-meta { color:var(--subtext); font-size:12px; }
.routing-sound-item button { min-height:32px; padding:6px 9px; font-size:12px; }
.routing-sound-preview { width:100%; margin-top:8px; }
/* ── Section dividers between subsections ───────────────────────────────── */
.subsection-head {
display: flex; align-items: center; gap: 8px;
padding: 16px 0 8px; border-bottom: 1px solid var(--border); margin-bottom: 12px;
}
.subsection-head h3 {
font-size: 14px; font-weight: 700; color: var(--subtext);
text-transform: uppercase; letter-spacing: .06em; margin: 0;
}
/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
.vl-grid { grid-template-columns: 1fr; }
.getvoices-source-editor, .getvoices-toolbar, .getvoices-summary { grid-template-columns: 1fr; }
.getvoices-source-buttons { flex-direction: row; min-width: 0; }
/* .design-sample-grid's real mobile override lives in voice-design.css --
that file loads after this one and re-declares the same selector
unscoped, so a copy here would always lose the cascade. */
.qwen-sample-actions { justify-content: flex-start; }
.design-preset-row, .routing-grid { grid-template-columns: 1fr; }
/* minmax(120px,...) minmax(110px,...) minmax(220px,...) auto needs 450px+
just for its minimums -- "Test route" and the textarea ran off-screen. */
.routing-test-row { grid-template-columns: 1fr; }
}
/* Mobile top bar — hidden on desktop */
#mobile-topbar {
display: none;
}
/* Sidebar backdrop (mobile drawer overlay) */
#sidebar-backdrop {
display: none;
position: fixed; inset: 0; z-index: 199;
background: rgba(0,0,0,0.45);
backdrop-filter: blur(2px);
}
#sidebar-backdrop.open { display: block; }
/* ── Mobile (≤ 767px) ─────────────────────────────────────────────────────── */
@media (max-width: 767px) {
/* Top bar */
#mobile-topbar {
display: flex; align-items: center; gap: 10px;
height: 52px; padding: 0 14px;
background: var(--surface); border-bottom: 1px solid var(--border);
position: sticky; top: 0; z-index: 100;
flex-shrink: 0;
}
body { display: flex; flex-direction: column; }
#app-shell { flex: 1; overflow: hidden; }
#sidebar-toggle {
background: none; border: 1px solid var(--border);
border-radius: 7px; width: 36px; height: 36px;
display: flex; align-items: center; justify-content: center;
cursor: pointer; color: var(--text); font-size: 18px; flex-shrink: 0;
}
#sidebar-toggle:active { background: var(--panel); }
.mobile-brand { font-size: 15px; font-weight: 800; color: var(--accent); }
/* Sidebar: slide-in drawer */
#sidebar {
position: fixed; top: 0; left: -240px; bottom: 0;
width: 240px !important; z-index: 200;
transition: left 0.22s ease;
box-shadow: 4px 0 24px rgba(0,0,0,0.18);
overflow-y: auto;
}
#sidebar.open { left: 0; }
/* Main content full width, top-padded by topbar height */
#main-content { padding: 0 12px 60px; }
/* Section headings -- every section actually uses .section-head, not
.section-header (the selector this rule shipped with, which matched
nothing); its icon/title/action row never wrapped on a narrow screen
as a result, pushing "+ New voice" and similar buttons off-screen
with no way to reach them. */
.section-head { flex-wrap: wrap; row-gap: 8px; }
.section-head-actions { margin-left: 0; }
.section-search { width: 100% !important; max-width: 100%; box-sizing: border-box; }
/* Toast: full width on small screens */
#toast { left: 50%; right: auto; max-width: calc(100vw - 24px); min-width: calc(100vw - 24px); }
.toast-item { max-width: 100%; }
/* ── Voice workbench ──────────────────────────────────────────────────── */
.voices-workbench {
flex-direction: column;
height: auto !important;
min-height: 0 !important;
}
.voices-list-pane {
width: 100% !important;
flex-shrink: 0;
}
.vl-card-list {
max-height: 55vh;
}
.voices-inspector-pane {
flex: none;
min-height: 60vh;
}
/* When a voice is selected on mobile, hide the list and show inspector full-height */
.voices-workbench.mobile-inspector-open .voices-list-pane { display: none; }
.voices-workbench.mobile-inspector-open .voices-inspector-pane { min-height: calc(100dvh - 52px); }
/* Inspector back button (injected by JS) */
.insp-mobile-back {
display: flex; align-items: center; gap: 6px;
padding: 10px 14px; font-size: 13px; font-weight: 600;
color: var(--accent); cursor: pointer;
border-bottom: 1px solid var(--border);
background: var(--surface);
}
.insp-mobile-back .mdi { font-size: 18px; }
/* ── Conversation ─────────────────────────────────────────────────────── */
.conv-config-row { flex-direction: column; gap: 10px; }
.conv-config-group--actions { margin-left: 0; }
.conv-url-inp { width: 100% !important; box-sizing: border-box; }
.conv-main { flex-direction: column; }
.conv-stats-panel { width: 100% !important; flex-shrink: 0; }
/* The text field, send/mic buttons, noise-gate row and three toggle
labels were all one non-wrapping flex row -- the toggles ran off
the right edge with no way to reach them. Text input gets its own
full-width line; everything else wraps onto the ones below it. */
.conv-text-row { flex-wrap: wrap; }
.conv-text-inp { flex: 1 1 100%; min-width: 0; }
/* ── Routing log ──────────────────────────────────────────────────────── */
.routing-log-entry {
min-width: 0 !important;
grid-template-columns: auto 1fr !important;
grid-template-rows: auto auto auto;
}
.routing-log-entry .log-duration,
.routing-log-entry .log-meta,
.routing-log-entry .log-text { display: none; }
/* ── Try It Out ───────────────────────────────────────────────────────── */
.preview-match-panel { grid-template-columns: 1fr !important; }
/* .fx-sliders shrinks (flex-shrink:1) to fit next to its checkbox toggle
on the same line before .fx-row's own flex-wrap ever triggers -- its
nowrap labels then overflow the squeezed container instead of the row
ever dropping them to their own line. Forcing a full-width basis is
what actually makes that wrap happen. */
.fx-sliders { flex-basis: 100% !important; }
.fx-sliders input[type=range] { width: 84px !important; }
/* ── Clone / Design section toolbar ──────────────────────────────────── */
.vl-toolbar { gap: 5px; }
/* ── Voice inspector: synth-mode segmented control ──────────────────────
"Preview text" / "Reference transcript" side by side never fit next to
the "Synth uses" label at this width -- the row simply ran off-screen
with no way to reach the second button (body's overflow-x: hidden
clips it, so it wasn't merely scrollable, it was unreachable). Wrap
the label onto its own line and let the segmented control take the
full width below it, each button sharing it evenly. */
.vl-synth-mode-row { flex-wrap: wrap; }
.vl-synth-seg { flex: 1 1 100%; }
.vl-synth-seg-btn { flex: 1; text-align: center; }
/* ── Settings ─────────────────────────────────────────────────────────── */
.settings-grid { grid-template-columns: 1fr !important; }
.settings-cluster-grid { grid-template-columns: 1fr !important; }
/* ── Language Models / Engines ───────────────────────────────────────── */
/* minmax(440px/380px, 1fr) cannot fit even one column under ~400-460px --
every card in these grids ran off-screen rather than stacking. */
/* A 1fr track still won't shrink below a grid item's own content-based
minimum (grid items default to min-width:auto) -- long unbroken card
content (an API-key row, a stats line) was the real remaining floor. */
.llm-service-grid, .llm-local-grid, .dc-grid { grid-template-columns: 1fr !important; }
.llm-service-grid > *, .llm-local-grid > *, .dc-grid > * { min-width: 0 !important; }
/* ── Generic helpers ──────────────────────────────────────────────────── */
.vl-grid { grid-template-columns: 1fr; }
.section-toolbar { flex-wrap: wrap; gap: 6px; }
select, input[type="text"], input[type="url"], input[type="number"], textarea {
font-size: 16px; /* prevent iOS auto-zoom */
}
}
@media (max-width: 1100px) {
.library-control-panel { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.library-insights { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.settings-cluster-grid { grid-template-columns: 1fr; }
.lib-add-input-grid, .lib-add-mic-row { grid-template-columns: 1fr; }
}
/* ── Voices empty state ──────────────────────────────────────────────────── */
.voices-empty-state { padding: 32px 8px; }
.voices-empty-cases {
display: flex; align-items: stretch; gap: 0;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); overflow: hidden;
}
.voices-empty-case {
flex: 1; padding: 28px 24px; display: flex; flex-direction: column; gap: 10px;
}
.voices-empty-case:first-child { border-right: 1px solid var(--border); }
.voices-empty-case-icon { font-size: 32px; line-height: 1; }
.voices-empty-case h4 { font-size: 15px; font-weight: 700; color: var(--text); margin: 0; }
.voices-empty-case p { font-size: 13px; line-height: 1.6; color: var(--subtext); margin: 0; }
.voices-empty-case code {
background: var(--panel); border: 1px solid var(--border);
border-radius: 4px; padding: 1px 5px; font-size: 12px;
}
.voices-empty-divider {
display: flex; align-items: center; justify-content: center;
width: 40px; flex-shrink: 0;
font-size: 14px; font-weight: 700; color: var(--subtext);
text-transform: uppercase; letter-spacing: .08em;
background: var(--panel); border-left: 1px solid var(--border); border-right: 1px solid var(--border);
}
.voices-folder-row { display: flex; gap: 8px; margin-top: 4px; }
.voices-folder-input {
flex: 1; min-width: 0; background: var(--bg); border: 1px solid var(--border);
border-radius: var(--radius); padding: 8px 10px; font-size: 13px;
color: var(--text); font-family: monospace;
}
.voices-folder-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
.voices-empty-hint { font-size: 14.5px; color: var(--subtext); opacity: .75; line-height: 1.7; margin-top: 2px; }
/* Directory browser */
.vef-dir-browser { margin-top: 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); overflow: hidden; }
.vef-breadcrumb { display: flex; align-items: center; flex-wrap: wrap; gap: 0; padding: 6px 10px; background: var(--panel); border-bottom: 1px solid var(--border); font-size: 12px; }
.vef-crumb-btn { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 12px; padding: 1px 3px; font-family: monospace; }
.vef-crumb-btn:hover { text-decoration: underline; }
.vef-crumb-cur { font-family: monospace; font-size: 12px; font-weight: 700; color: var(--text); padding: 1px 3px; }
.vef-sep { color: var(--subtext); font-size: 12px; padding: 0 1px; }
.vef-dir-list { max-height: 160px; overflow-y: auto; padding: 4px 0; }
.vef-dir-item { display: flex; align-items: center; gap: 6px; width: 100%; text-align: left; padding: 5px 12px; font-size: 12px; font-family: monospace; background: none; border: none; color: var(--text); cursor: pointer; transition: background .1s; }
.vef-dir-item:hover { background: var(--panel); color: var(--accent); }
.vef-loading, .vef-empty, .vef-error { display: block; padding: 12px 12px; font-size: 12px; color: var(--subtext); }
.vef-error { color: #e53e3e; }
.vef-browser-actions { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-top: 1px solid var(--border); background: var(--panel); }
.vef-selected-path { flex: 1; font-family: monospace; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--accent); }
.vef-browser-actions .btn-primary { font-size: 12px; padding: 5px 12px; flex-shrink: 0; }
.voices-empty-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.voices-empty-action-btn { width: 100%; }
/* ── Cross-workflow pipeline stepper (Reader/Casting/Characters/Rehearser) ──
PDF → Text → Cast Audiobook → Cast Characters (optional) → Script Rehearser
→ Generate MP3s → Audiobook. Every reachable stop is clickable in either
direction; state lives wherever it was created (readerState/_audiobook/
rehState), so jumping around never destroys it. */
.wf-stepper { display: flex; flex-direction: column; gap: 10px; padding: 14px 20px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 14px; }
.wf-stepper-row1 { display: flex; align-items: center; gap: 0; }
.wf-stepper-row2 { display: flex; align-items: flex-start; gap: 0; overflow-x: auto; padding-top: 10px; border-top: 1px solid var(--border); }
.wf-nav-btn {
align-self: center; display: inline-flex; align-items: center; justify-content: center;
width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
border: 1px solid var(--border); background: var(--surface); color: var(--text);
cursor: pointer; font-size: 16px; margin: 0 6px;
}
.wf-nav-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); background: rgba(37,99,235,.08); }
.wf-nav-btn:disabled { opacity: .35; cursor: not-allowed; }
.wf-stepper-row2 .wf-nav-prev { margin: 0 10px 0 0; }
.wf-stepper-row2 .wf-nav-next { margin-left: auto; }
.wf-stepper-title { align-self: center; font-weight: 700; color: var(--text); font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wf-step {
display: flex; flex-direction: column; align-items: center; gap: 5px;
background: none; border: none; padding: 2px 16px; border-radius: 10px; cursor: pointer;
white-space: nowrap; color: var(--subtext); font-size: 11.5px; font-weight: 600;
transition: background .15s, color .15s; flex-shrink: 0;
}
.wf-step:hover:not(:disabled) { background: rgba(37,99,235,.08); color: var(--accent); }
.wf-step:disabled { opacity: .4; cursor: not-allowed; }
.wf-step-num {
display: inline-flex; align-items: center; justify-content: center;
width: 30px; height: 30px; border-radius: 50%;
background: var(--surface); border: 2px solid var(--border); color: var(--subtext);
font-size: 13px; font-weight: 800; flex-shrink: 0;
transition: background .15s, border-color .15s, color .15s, transform .15s;
}
.wf-step.is-done { color: var(--text); }
.wf-step.is-done .wf-step-num { background: rgba(37,99,235,.12); border-color: var(--accent); color: var(--accent); }
.wf-step.is-current { color: var(--accent); }
.wf-step.is-current .wf-step-num {
background: var(--accent); border-color: var(--accent); color: #fff;
transform: scale(1.15); box-shadow: 0 0 0 4px rgba(37,99,235,.16);
}
.wf-step.is-optional .wf-step-num { border-style: dashed; }
.wf-step small { display: block; font-weight: 500; font-size: 9.5px; opacity: .7; margin-top: -2px; }
/* Connecting line between steps, like a wizard progress rail. */
.wf-step-arrow { color: var(--border); font-size: 20px; flex-shrink: 0; margin: 0 -3px; align-self: flex-start; padding-top: 4px; }
.wf-step-arrow.is-done { color: var(--accent); opacity: .5; }
/* ── Voices workbench ────────────────────────────────────────────────────── */
.voices-workbench {
display: flex; height: calc(100vh - 148px); min-height: 420px;
gap: 10px; background: transparent; overflow: visible;
}
/* List pane — flex column wrapper; visual card appearance is on .vl-card children */
.voices-list-pane {
width: 380px; flex-shrink: 0;
display: flex; flex-direction: column; gap: 8px;
overflow: visible;
}
/* The two cards inside the list pane */
.vl-card {
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); overflow: hidden;
box-shadow: var(--shadow);
}
.vl-card-list {
display: flex; flex-direction: column;
flex: 1; min-height: 0; overflow: hidden;
}
.vl-toolbar {
display: flex; flex-wrap: wrap; gap: 4px;
padding: 8px 10px 7px; border-bottom: 1px solid var(--border);
}
.vl-tb-btn { padding: 3px 8px !important; font-size: 12px !important; flex: 0 0 auto; }
.vl-filters {
display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
padding: 7px 10px; border-bottom: 1px solid var(--border);
}
.vl-search {
flex: 1; min-width: 60px; padding: 5px 8px; font-size: 12.5px;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--bg); color: var(--text);
}
.vl-search input::placeholder {
color: var(--placehld);
}
.vl-search:focus { outline: none; border-color: var(--accent); }
.vl-filters select {
padding: 4px 5px; font-size: 12px; border: 1px solid var(--border);
border-radius: var(--radius); background: var(--bg); color: var(--text); max-width: 80px;
}
.vl-disabled-label { font-size: 14.5px; color: var(--subtext); white-space: nowrap; cursor: pointer; gap: 3px; display: flex; align-items: center; }
/* Sort bar */
.vl-sort-bar {
display: flex; align-items: center; gap: 5px;
padding: 5px 10px; border-bottom: 1px solid var(--border);
background: var(--panel);
}
/* Search fills the left; the Sort controls sit on the right */
.vl-search-main { flex: 1; min-width: 80px; }
.vl-sort-label {
font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
color: var(--subtext); flex-shrink: 0; margin-right: 1px; margin-left: auto;
}
#voice-sort-field {
flex: 0 0 auto; padding: 3px 6px; font-size: 12px;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text); cursor: pointer;
min-width: 0;
}
#voice-sort-field:focus { outline: none; border-color: var(--accent); }
.vl-sort-dir-btn {
flex-shrink: 0; width: 26px; height: 26px; padding: 0;
display: flex; align-items: center; justify-content: center;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--subtext); cursor: pointer;
font-size: 14px; transition: background .1s, color .1s;
}
.vl-sort-dir-btn:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.vl-sort-dir-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
#voice-list { flex: 1; overflow-y: auto; min-height: 0; }
/* Virtual tag folders in the voice list */
.vl-tag-group { border-bottom: 1px solid var(--border); }
.vl-tag-head {
width: 100%; display: flex; align-items: center; gap: 7px; padding: 8px 12px;
background: var(--panel); border: none; border-top: 1px solid var(--border);
color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
position: sticky; top: 0; z-index: 2; font-family: inherit; text-align: left;
}
.vl-tag-head:hover { background: var(--border); }
.vl-tag-head .mdi { font-size: 16px; color: var(--accent); flex-shrink: 0; }
.vl-tag-caret { color: var(--subtext) !important; font-size: 15px !important; }
.vl-tag-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vl-tag-count { font-size: 11px; font-weight: 700; color: var(--subtext); background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 1px 8px; }
.vl-tag-body { display: flex; flex-direction: column; }
/* ── Voice groups bar ──────────────────────────────────────────────────── */
/* ── Bulk-edit toolbar ──────────────────────────────────────────────────── */
.vl-bulk-bar {
display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
padding: 7px 10px; border-bottom: 2px solid rgba(37,99,235,.35);
background: rgba(37,99,235,.06); position: sticky; top: 0; z-index: 10;
}
.vl-bulk-bar[hidden] { display: none; }
.vl-bulk-count {
font-size: 12px; font-weight: 700; color: var(--accent); white-space: nowrap; min-width: 64px;
}
.vl-bulk-btn {
display: inline-flex; align-items: center; gap: 4px;
font-size: 11px; padding: 3px 9px; border-radius: 6px;
border: 1px solid var(--border); background: var(--card-bg, var(--panel));
color: var(--text); cursor: pointer; white-space: nowrap; transition: background .12s;
}
.vl-bulk-btn:hover { background: var(--panel); border-color: var(--accent); }
.vl-bulk-danger { color: var(--red, #ef4444); border-color: rgba(239,68,68,.3); }
.vl-bulk-danger:hover { background: rgba(239,68,68,.1); border-color: var(--red, #ef4444); }
.vl-bulk-sep { width: 1px; height: 18px; background: var(--border); margin: 0 2px; flex-shrink: 0; }
.vl-bulk-tag-inp, .vl-bulk-rating-sel {
height: 26px; padding: 0 8px; border: 1px solid var(--accent); border-radius: 6px;
background: var(--input-bg, var(--panel)); color: var(--text); font-size: 12px; outline: none;
}
/* Bulk delete confirmation — centered modal */
.vl-bdc-overlay {
position: fixed; inset: 0; z-index: 2000; background: rgba(0,0,0,.45);
display: flex; align-items: center; justify-content: center; padding: 20px;
animation: reh-cdp-in .12s ease-out;
}
.vl-bdc-modal {
background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
box-shadow: 0 18px 50px rgba(0,0,0,.3); padding: 20px; width: 440px; max-width: 100%;
max-height: 82vh; display: flex; flex-direction: column; gap: 12px;
}
.vl-bdc-title { font-size: 17px; font-weight: 800; color: var(--text); display: flex; align-items: center; gap: 9px; }
.vl-bdc-title .mdi { color: var(--red, #ef4444); font-size: 22px; }
.vl-bdc-sub { font-size: 13px; color: var(--subtext); margin: 0; line-height: 1.45; }
.vl-bdc-list { display: flex; flex-wrap: wrap; gap: 5px; overflow-y: auto; max-height: 220px; padding: 2px; }
.vl-bdc-id {
font-size: 12px; font-family: monospace; padding: 2px 8px; border-radius: 5px;
background: rgba(239,68,68,.1); color: var(--red,#ef4444); border: 1px solid rgba(239,68,68,.25);
white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}
.vl-bdc-more { font-size: 12px; color: var(--subtext); align-self: center; padding: 0 4px; }
.vl-bdc-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.vl-bdc-actions button {
padding: 9px 16px; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer;
font-family: var(--font); border: 1px solid var(--border); background: var(--panel); color: var(--text);
}
.vl-bdc-cancel:hover { border-color: var(--accent); }
.vl-bdc-go { background: var(--red, #ef4444) !important; color: #fff !important; border-color: var(--red, #ef4444) !important; display: inline-flex; align-items: center; gap: 6px; }
.vl-bdc-go:hover { filter: brightness(.95); }
.vl-bdc-go:disabled { opacity: .75; cursor: default; }
@media (max-width: 600px) { .vl-bdc-actions button { flex: 1; } }
/* Bulk checkbox on each row */
.vl-bulk-cb {
width: 15px; height: 15px; cursor: pointer; flex-shrink: 0; margin-right: 4px;
accent-color: var(--accent); align-self: center;
}
.vl-row.vl-bulk-selected { background: rgba(37,99,235,.06); }
/* ── Benchmark statuses ──────────────────────────────────────────────────── */
.vl-row.benchmarking-pending { background: rgba(245, 158, 11, 0.08); border-color: rgba(245, 158, 11, 0.4); transition: background 0.3s; }
.vl-row.benchmarking-active { background: rgba(37, 99, 235, 0.12); border-color: var(--accent); box-shadow: 0 0 0 2px rgba(37,99,235,0.2); transition: background 0.3s; }
.vl-row.benchmarking-done { background: rgba(34, 197, 94, 0.08); border-color: rgba(34, 197, 94, 0.4); transition: background 0.8s; }
[data-theme="dark"] .vl-row.benchmarking-pending { background: rgba(245, 158, 11, 0.15); border-color: rgba(245, 158, 11, 0.5); }
[data-theme="dark"] .vl-row.benchmarking-active { background: rgba(37, 99, 235, 0.25); box-shadow: 0 0 0 2px rgba(37,99,235,0.4); }
[data-theme="dark"] .vl-row.benchmarking-done { background: rgba(34, 197, 94, 0.15); border-color: rgba(34, 197, 94, 0.5); }
.voice-groups-bar {
display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
padding: 7px 10px; border-bottom: 1px solid var(--border);
background: rgba(245,158,11,.05);
}
.vg-label { font-size: 11px; font-weight: 700; color: var(--subtext); display: inline-flex; align-items: center; gap: 4px; margin-right: 4px; }
.vg-chip {
display: inline-flex; align-items: center; gap: 5px;
font-size: 12px; padding: 3px 6px 3px 10px; border-radius: 12px;
background: var(--card-bg, var(--panel)); border: 1px solid var(--border);
color: var(--text); cursor: pointer; transition: border-color .15s, background .15s;
}
.vg-chip:hover { border-color: #f59e0b; }
.vg-chip.active { border-color: #f59e0b; background: rgba(245,158,11,.12); font-weight: 600; }
.vg-count { font-size: 10px; background: rgba(0,0,0,.1); border-radius: 8px; padding: 0 5px; font-weight: 700; }
.vg-del {
border: none; background: none; cursor: pointer; color: var(--subtext);
font-size: 15px; line-height: 1; padding: 0 2px; border-radius: 4px;
}
.vg-del:hover { color: var(--red, #ef4444); background: rgba(239,68,68,.12); }
.vg-clear { border: none; background: none; cursor: pointer; color: var(--accent); font-size: 12px; font-weight: 600; padding: 2px 8px; }
.vl-footer {
padding: 7px 10px; border-top: 1px solid var(--border);
font-size: 14.5px; color: var(--subtext);
display: flex; align-items: center; justify-content: space-between; gap: 6px;
}
.vl-add-btn { padding: 4px 9px !important; font-size: 11.5px !important; }
/* Compact voice row — override original card-style .vl-row */
.voices-list-pane .vl-row {
display: flex !important; flex-direction: row !important; align-items: center !important;
gap: 9px !important; padding: 7px 10px !important; cursor: pointer;
border: none !important; border-left: 3px solid transparent !important;
border-bottom: 1px solid var(--border) !important;
border-radius: 0 !important; box-shadow: none !important;
transform: none !important; transition: background .1s; user-select: none;
background: var(--surface) !important;
}
.voices-list-pane .vl-row:last-child { border-bottom: none !important; }
.voices-list-pane .vl-row:hover { background: var(--panel) !important; }
.voices-list-pane .vl-row.vr-selected { background: rgba(37,99,235,.07) !important; border-left-color: var(--accent) !important; }
.voices-list-pane .vl-row.benchmarking-pending { background: rgba(245, 158, 11, 0.08) !important; border-left-color: rgba(245, 158, 11, 0.8) !important; }
.voices-list-pane .vl-row.benchmarking-active { background: rgba(37, 99, 235, 0.15) !important; border-left-color: var(--accent) !important; }
.voices-list-pane .vl-row.benchmarking-done { background: rgba(34, 197, 94, 0.08) !important; border-left-color: rgba(34, 197, 94, 0.8) !important; }
[data-theme="dark"] .voices-list-pane .vl-row.benchmarking-pending { background: rgba(245, 158, 11, 0.15) !important; }
[data-theme="dark"] .voices-list-pane .vl-row.benchmarking-active { background: rgba(37, 99, 235, 0.25) !important; }
[data-theme="dark"] .voices-list-pane .vl-row.benchmarking-done { background: rgba(34, 197, 94, 0.15) !important; }
.voices-list-pane .vl-row.vr-disabled { opacity: .5; }
/* Hide everything except the compact div */
.voices-list-pane .vl-row .vr-main-row,
.voices-list-pane .vl-row .vr-detail-row,
.voices-list-pane .vl-row .vr-optimizer { display: none !important; }
/* Compact content block */
.vl-compact { display: flex; align-items: center; gap: 9px; width: 100%; min-width: 0; }
.vl-compact .vr-play-group { display: flex; gap: 4px; flex-shrink: 0; }
.vl-compact .vr-play-group button {
width: 26px; height: 26px; border-radius: 50%;
border: none; font-size: 9px; display: flex; align-items: center; justify-content: center;
padding: 0; cursor: pointer; transition: filter .15s;
}
.vl-compact .play-btn-orig { background: var(--accent); color: #fff; }
.vl-compact .play-btn-synth { background: var(--teal); color: #fff; }
.vl-compact .vr-play-group button:hover { filter: brightness(1.12); }
/* Avatar: rounded square, supports photo / flag-icon / initial */
.vl-avatar {
width: 42px; height: 42px; border-radius: var(--radius); flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
overflow: hidden;
}
.vl-avatar-photo { padding: 0; }
.vl-avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius); }
.vl-avatar-flag { background: transparent; }
.vl-avatar-flag .fi { display: block; width: 100%; height: 100%; background-size: cover; background-position: center; border-radius: var(--radius); }
.vl-avatar-initial { background: transparent; }
.vl-avatar-letter { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; font-size: 17px; font-weight: 800; border-radius: var(--radius); }
/* Voice info block (name + type badge + gender chip) */
.vl-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.vl-name { font-size: 12.5px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vl-row.vr-selected .vl-name { color: var(--accent); }
.vl-meta { display: flex; align-items: center; gap: 6px; }
/* Type label — no background, just colored text */
.vl-type-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; }
.vl-type-clone { color: var(--accent); }
.vl-type-design { color: var(--mauve); }
/* Separator dot between type and gender */
.vl-type-label + .vl-gender-label::before { content: '·'; color: var(--border); margin-right: 6px; font-weight: 400; }
/* Gender label — no background, just colored symbol + text */
.vl-gender-letter {
display: inline-flex; align-items: center; justify-content: center;
width: 16px; height: 16px; border-radius: 4px;
font-weight: 800; font-size: 11px;
}
.vl-gender-letter.g-f { background: rgba(236, 72, 153, 0.15); color: #ec4899; }
.vl-gender-letter.g-m { background: rgba(59, 130, 246, 0.15); color: #3b82f6; }
.vl-gender-letter.g-n { background: rgba(156, 163, 175, 0.15); color: #9ca3af; }
.vl-flag { font-size: 14px; color: var(--subtext); }
.vl-meta .vr-rating {
font-size: 13px;
min-height: unset;
gap: 0;
}
/* Benchmark speed chip — compact list row + inspector header */
.vl-meta .vl-bench-chip { margin-left: 2px; }
.vl-bench-chip {
display: inline-flex; align-items: center; gap: 2px;
font-size: 10px; font-weight: 600; font-variant-numeric: tabular-nums;
padding: 1px 5px; border-radius: 4px;
background: rgba(20,184,166,.12); color: var(--subtext);
}
.vl-bench-chip .mdi { font-size: 10px; }
.insp-bench-chip {
display: inline-flex; align-items: center; gap: 3px;
font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
color: var(--subtext);
}
.insp-bench-chip .mdi { font-size: 11px; }
.bench-ok { color: var(--green, #22c55e) !important; }
.bench-warn{ color: var(--yellow, #eab308) !important; }
.bench-bad { color: var(--red, #ef4444) !important; }
.vl-bench-chip.bench-ok { background: rgba(34,197,94,.1); }
.vl-bench-chip.bench-warn{ background: rgba(234,179,8,.1); }
.vl-bench-chip.bench-bad { background: rgba(239,68,68,.1); }
.vl-dbfs { display: none; }
/* Table View mode */
.vl-tbl-lang, .vl-tbl-gender, .vl-tbl-type, .vl-tbl-bench, .vl-tbl-dbfs, .vl-tbl-len, .vl-tbl-dur, .vl-tbl-factor, .vl-tbl-time, .vl-tbl-wpm, .vl-tbl-rating, .vl-tbl-source, .vl-tbl-seed, .vl-tbl-note, .vl-tbl-tag, .vl-tbl-active { display: none; }
/* len, dur, time hidden in table view — full detail lives in Setup → Benchmark */
.vl-table-header { display: none; }
.voices-workbench.table-view .voices-list-pane { width: 100% !important; max-width: 100%; }
.voices-workbench.table-view .voices-inspector-pane { display: none !important; }
.voices-workbench.table-view .vl-table-header {
display: grid;
grid-template-columns: 24px 32px 60px minmax(140px, 1.2fr) 55px 65px 55px 55px 50px 65px 55px 85px 65px minmax(80px, 1fr) minmax(120px, 1fr) 50px;
gap: 8px;
align-items: center;
padding: 8px 10px;
font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--subtext);
border-bottom: 1px solid var(--border);
background: var(--surface);
position: sticky; top: 0; z-index: 5;
}
.vl-th-sortable { cursor: pointer; display: flex; align-items: center; gap: 3px; transition: color .15s; }
.vl-th-sortable:hover { color: var(--text); }
.vl-th-sortable .mdi { font-size: 12px; opacity: .6; }
.vl-th-sortable:hover .mdi { opacity: 1; color: var(--accent); }
.vl-th-info { font-size: 11px !important; opacity: .5; cursor: help; margin-left: 1px; }
.vl-th-info:hover { opacity: 1; color: var(--accent); }
.voices-workbench.table-view .vl-compact {
display: grid;
grid-template-columns: 24px 32px 60px minmax(140px, 1.2fr) 55px 65px 55px 55px 50px 65px 55px 85px 65px minmax(80px, 1fr) minmax(120px, 1fr) 50px;
gap: 8px;
align-items: center;
}
.voices-workbench.table-view .vl-bulk-cb { order: 0; margin: 0; justify-self: center; }
.voices-workbench.table-view .vl-info { display: contents; }
.voices-workbench.table-view .vl-meta { display: none; }
.voices-workbench.table-view .vl-avatar { order: 1; width: 32px; height: 32px; }
.voices-workbench.table-view .vr-play-group { order: 2; flex-shrink: 0; }
.voices-workbench.table-view .vl-name,
.voices-workbench.table-view .vl-name-input { order: 3; display: block; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
.voices-workbench.table-view .vl-tbl-lang { display: block; order: 4; font-size: 12px; }
.voices-workbench.table-view .vl-tbl-gender { display: block; order: 5; font-size: 12px; }
.voices-workbench.table-view .vl-tbl-factor { display: block; order: 6; font-size: 12px; font-family: monospace; font-weight: 600; }
.voices-workbench.table-view .vl-tbl-wpm { display: block; order: 7; font-size: 12px; font-family: monospace; }
.voices-workbench.table-view .vl-tbl-seed { display: block; order: 8; font-size: 12px; font-family: monospace; }
.voices-workbench.table-view .vl-tbl-dbfs { display: block; order: 9; font-size: 12px; font-family: monospace; }
.voices-workbench.table-view .vl-tbl-type { display: block; order: 10; font-size: 12px; }
.voices-workbench.table-view .vl-tbl-source { display: block; order: 11; font-size: 12px; overflow: hidden; text-overflow: ellipsis; }
.voices-workbench.table-view .vl-tbl-rating { display: flex; order: 12; font-size: 14px; color: var(--subtext); }
.voices-workbench.table-view .vl-tbl-rating .star.on { color: #f59e0b; }
.voices-workbench.table-view .vl-tbl-tag { display: block; order: 13; font-size: 12px; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
.voices-workbench.table-view .vl-tbl-note { display: block; order: 14; font-size: 12px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: italic; }
.voices-workbench.table-view .vl-tbl-active { display: block; order: 15; font-size: 16px; text-align: center; }
.voices-workbench.table-view .vl-tbl-factor.bench-ok { color: var(--success, #16a34a); }
.voices-workbench.table-view .vl-tbl-factor.bench-warn { color: #d97706; }
.voices-workbench.table-view .vl-tbl-factor.bench-bad { color: var(--error, #dc2626); }
.voices-workbench.table-edit-mode .vl-compact {
background: rgba(37,99,235,0.03);
border-bottom: 1px solid var(--border);
}
.vl-inline-edit {
background: var(--surface-light);
border: 1px solid var(--border);
color: var(--text);
font-family: inherit;
font-size: 12px;
padding: 2px 4px;
border-radius: 4px;
outline: none;
transition: border-color 0.15s;
}
.vl-inline-edit:focus {
border-color: var(--accent);
}
.vl-inline-edit.vl-name-input {
font-size: 13px;
font-weight: 600;
width: 100%;
}
/* Synth mode panel (segmented control + preview input) */
.vl-synth-panel { background: var(--surface); }
.vl-synth-mode-row { display: flex; align-items: center; gap: 7px; padding: 5px 8px 5px; }
.vl-synth-icon { font-size: 9px; color: var(--teal); flex-shrink: 0; }
.vl-synth-label { font-size: 14px; font-weight: 700; color: var(--subtext); white-space: nowrap; flex-shrink: 0; }
.vl-synth-seg { display: flex; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; flex-shrink: 0; }
.vl-synth-seg-btn {
background: var(--panel); border: none; padding: 3px 9px;
font-size: 14.5px; font-weight: 600; color: var(--subtext);
cursor: pointer; transition: background .12s, color .12s; white-space: nowrap;
border-right: 1px solid var(--border);
}
.vl-synth-seg-btn:last-child { border-right: none; }
.vl-synth-seg-btn.active { background: var(--teal); color: #fff; }
.vl-synth-seg-btn:not(.active):hover { background: var(--border); color: var(--text); }
.vl-preview-text-wrap { padding: 0 8px 6px; }
.vl-preview-row { display: flex; align-items: flex-start; gap: 6px; }
.vl-preview-lang-btn {
flex-shrink: 0; width: 34px; height: 34px; margin-top: 1px;
border: 1px solid var(--border); border-radius: 6px;
background: var(--surface); padding: 0; cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: border-color .15s, box-shadow .15s;
}
.vl-preview-lang-btn:hover { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(37,99,235,.12); filter: none; }
.vl-preview-lang-btn .fi { width: 22px; height: 16px; background-size: cover; background-position: center; border-radius: 2px; display: block; }
.vl-preview-input {
flex: 1; min-width: 0; display: block; box-sizing: border-box;
font-size: 16px; line-height: 1.5;
background: var(--bg); border: 1px solid var(--border); border-radius: 5px;
color: var(--text); padding: 5px 7px; font-family: var(--font);
resize: vertical; min-height: 42px;
}
.vl-preview-input:focus { outline: none; border-color: var(--accent); }
.vl-preview-text-wrap.hidden { display: none; }
/* Inspector pane */
.voices-inspector-pane {
flex: 1; min-width: 0;
background: var(--bg);
display: flex; flex-direction: column; overflow: hidden;
}
.inspector-placeholder {
height: 100%; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 10px;
color: var(--placehld); text-align: center; padding: 24px;
}
.inspector-placeholder span { font-size: 40px; opacity: .4; }
.inspector-placeholder p { font-size: 13px; line-height: 1.6; color: var(--subtext); }
/* ── Inspector header ────────────────────────────────────────────────────── */
.inspector-header {
background: var(--surface);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
border-top-left-radius: var(--radius);
border-top-right-radius: var(--radius);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
margin-right: 30px; /* cause of the scrollbar */
}
/* Header top: [avatar 72px] + [title-stack flex:1] */
.insp-hd-top {
display: flex; align-items: flex-start; gap: 12px;
padding: 12px 14px 8px;
}
/* Avatar — compact square */
.inspector-avatar {
width: 120px; height: 120px; border-radius: var(--radius); flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-size: 26px; font-weight: 700; color: #fff; overflow: hidden;
}
.insp-avatar-photo { padding: 0; }
.insp-avatar-img { width: 100%; height: 100%; object-fit: cover; }
.inspector-avatar .fi { display: block; width: 100%; height: 100%; background-size: cover; background-position: center; }
.insp-avatar-clickable { cursor: pointer; transition: opacity .15s; }
.insp-avatar-clickable:hover { opacity: .75; }
/* Title stack — all right-side rows stacked vertically */
.insp-title-stack { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; padding-top: 1px; }
/* Row 1: name + save button */
.insp-hd-row1 { display: flex; align-items: center; gap: 8px; }
.insp-disp-name {
flex: 1; min-width: 0;
font-size: 18px; font-weight: 600; color: var(--text); margin: 0; line-height: 1.3;
cursor: default; user-select: text; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.insp-disp-name:hover { color: var(--accent); }
.insp-name-edit {
flex: 1; min-width: 0;
font-size: 16px; font-weight: 600; color: var(--text);
border: none; border-bottom: 2px solid var(--accent); background: transparent;
outline: none; padding: 0; line-height: 1.3;
}
.insp-actions-save { flex-shrink: 0; }
/* Row 2: voice ID + copy + active toggle */
.insp-hd-row2 { display: flex; align-items: center; gap: 5px; }
.insp-id-block { display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0; }
.insp-full-id {
font-size: 14px; color: var(--subtext); font-family: monospace; font-weight: 400;
cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.insp-full-id:hover { color: var(--accent); text-decoration: underline dotted; }
.insp-copy-id-btn, .insp-edit-id-btn {
background: none; border: 1px solid var(--border); color: var(--subtext);
font-size: 9px; cursor: pointer; padding: 1px 4px; border-radius: 3px;
transition: color .15s, border-color .15s; flex-shrink: 0; white-space: nowrap;
}
.insp-copy-id-btn:hover, .insp-edit-id-btn:hover { color: var(--accent); border-color: var(--accent); }
.insp-edit-id-btn .mdi { font-size: 11px; }
/* ── Clone: transcription in-progress feedback ────────────────────────────── */
@keyframes clone-tr-pulse {
0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 30%, transparent); }
50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 8%, transparent); }
}
#transcript-area.transcribing {
border-color: var(--accent) !important;
animation: clone-tr-pulse 1.2s ease-in-out infinite;
}
.clone-tr-status { font-size: 13px; display: inline-flex; align-items: center; gap: 6px; }
.clone-tr-status.working { color: var(--accent); font-weight: 600; }
.clone-tr-status.done { color: var(--green); font-weight: 600; }
.clone-tr-status.error { color: var(--red); }
.clone-tr-status .mdi { font-size: 15px; }
.insp-actions-active { display: flex; align-items: center; flex-shrink: 0; }
.insp-actions-active .vr-detail-active { display: contents; align-items: center; gap: 5px; }
.insp-actions-active .vr-detail-active > label:first-child { padding-right: 10px; font-weight: 500; color: var(--subtext); }
.insp-actions-active .toggle { width: 32px; height: 18px; }
.insp-actions-active .t-slider::before { height: 12px; width: 12px; left: 3px; bottom: 3px; }
.insp-actions-active .toggle input:checked + .t-slider::before { transform: translateX(14px); }
/* Divider between ID row and subtitle */
.insp-hd-divider { height: 1px; background: var(--border); margin: 2px 0; }
/* Note + delete bottom row */
.insp-note-delete-row { display: flex; align-items: center; min-width: 0; }
.insp-note-slot { flex: 1; min-width: 0; display: flex; }
.insp-note-slot .vr-note { display: flex; flex: 1; }
.insp-note-slot .vr-note label { display: none; }
.insp-note-slot .vr-note .vr-inline { display: flex; flex: 1; }
.insp-note-slot .vr-note .vr-inline input {
width: 100%; padding: 2px 0; font-size: 14px; font-style: italic; font-family: inherit;
border: none; background: transparent; color: var(--text); outline: none; transition: color .15s;
}
.insp-note-slot .vr-note .vr-inline input::placeholder { color: var(--placehld); opacity: .6; }
.insp-note-slot .vr-note .vr-inline input:focus { font-style: normal; }
.insp-note-slot .ref-transcribe-btn { display: none !important; }
.insp-actions-delete { flex-shrink: 0; display: flex; align-items: center; padding-left: 20px; margin-right: 20px }
.insp-actions-delete .vr-detail-delete { display: flex; align-items: center; }
.insp-actions-delete .delete-btn {
background: none; border: none; color: var(--subtext); font-size: 10.5px;
cursor: pointer; padding: 0; text-decoration: underline dotted;
text-underline-offset: 2px; transition: color .15s; white-space: nowrap;
}
.insp-actions-delete .delete-btn:hover { color: var(--red); }
.insp-actions-delete .delete-confirm {
position: static; min-width: auto; max-width: none; box-shadow: none;
display: none; align-items: center; gap: 4px; font-size: 10.5px;
}
.insp-actions-delete .vr-detail-delete.delete-pending .delete-confirm { display: flex; }
.insp-actions-delete .vr-detail-delete.delete-pending .delete-btn { display: none; }
/* Subtitle: pipe-separated info bar */
.insp-subtitle {
display: flex; align-items: center; gap: 0; overflow: hidden;
}
.insp-subtitle > * {
padding: 0 6px; flex-shrink: 0;
border-right: 1px solid var(--border);
white-space: nowrap; line-height: 1;
}
.insp-subtitle > *:first-child { padding-left: 0; }
.insp-subtitle > *:last-child { border-right: none; flex: 1; flex-shrink: 1; min-width: 0; }
/* Flag (small inline icon, dblclick → picker) */
.insp-flag { display: flex; align-items: center; cursor: pointer; gap: 3px; }
.insp-flag-icon { display: flex; align-items: center; line-height: 1; }
.insp-flag-icon .fi { width: 22px; height: 16px; background-size: cover; background-position: center; border-radius: 2px; display: inline-block; flex-shrink: 0; }
.insp-flag-sel {
font-size: 14px; padding: 1px 4px; border: 1px solid var(--accent);
border-radius: 4px; background: var(--surface); color: var(--text); outline: none;
}
/* Lang wrap — dblclick to edit language */
.insp-lang-wrap { display: flex; align-items: center; cursor: default; }
.insp-lang-code { font-size: 14.5px; font-weight: 600; color: var(--subtext); }
.insp-lang-sel {
font-size: 14px; padding: 1px 4px; border: 1px solid var(--accent);
border-radius: 4px; background: var(--surface); color: var(--text); outline: none;
}
/* Gender label — click to cycle */
.insp-gender-label {
font-size: 14.5px; color: var(--subtext); cursor: pointer; user-select: none;
}
.insp-gender-label:hover { color: var(--text); }
/* Stars */
.insp-stars-wrap { display: flex; align-items: center; gap: 2px; cursor: pointer; }
.insp-stars { display: flex; gap: 0; }
.insp-star { font-size: 12px; color: var(--border); cursor: pointer; transition: color .1s; line-height: 1; }
.insp-star.on { color: #f59e0b; }
.insp-rating-label { font-size: 10px; color: var(--subtext); font-weight: 600; opacity: .75; }
/* Tag input — inline last item in subtitle */
.insp-tag-input {
border: none; background: transparent; color: var(--subtext);
font-size: 14.5px; font-family: inherit; outline: none;
padding: 0 6px; min-width: 50px;
transition: background .15s, color .15s;
}
.insp-tag-input::placeholder { color: var(--placehld); opacity: .5; font-style: italic; }
.insp-tag-input:hover { color: var(--text); }
.insp-tag-input:focus { background: var(--panel); color: var(--text); }
/* Tag autocomplete dropdown */
.tag-suggest {
position: fixed; z-index: 9998;
background: var(--surface); border: 1px solid var(--border);
border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.12);
max-height: 220px; overflow-y: auto; padding: 3px 0;
}
.tag-suggest-item {
display: block; width: 100%; text-align: left;
padding: 5px 12px; font-size: 12px; font-family: inherit;
background: none; border: none; color: var(--text);
cursor: pointer; white-space: nowrap; border-radius: 0;
transition: background .1s;
}
.tag-suggest-item:hover { background: var(--panel); filter: none; }
.insp-save-btn { white-space: nowrap; font-size: 12px; padding: 4px 10px; }
/* ── Searchable picker (flag / language) ─────────────────────────────────── */
.insp-picker {
position: fixed; z-index: 9999;
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: 0 4px 20px rgba(0,0,0,0.14);
width: 244px; max-height: 290px;
display: flex; flex-direction: column; overflow: hidden;
}
.insp-picker-search {
padding: 8px 10px; border: none; border-bottom: 1px solid var(--border);
font-size: 12px; font-family: inherit; background: var(--panel);
color: var(--text); outline: none; flex-shrink: 0;
}
.insp-picker-search::placeholder { color: var(--placehld); opacity: .65; }
.insp-picker-list { flex: 1; overflow-y: auto; padding: 3px 0; }
.insp-picker-item {
display: flex; align-items: center; width: 100%; gap: 8px;
padding: 5px 10px; background: none; border: none; border-radius: 0;
font-size: 12px; font-family: inherit; color: var(--text);
cursor: pointer; text-align: left; white-space: nowrap;
transition: background .1s;
}
.insp-picker-item:hover { background: var(--panel); filter: none; }
.insp-picker-item .ipi-code {
font-family: monospace; font-weight: 700; font-size: 14px;
color: var(--accent); min-width: 28px; flex-shrink: 0;
}
.insp-picker-empty { padding: 10px; font-size: 12px; color: var(--subtext); text-align: center; }
/* ── Inspector body ───────────────────────────────────────────────────────── */
.inspector-body { display: flex; flex-direction: column; gap: 10px; flex: 1; overflow-y: auto;}
/* Optimizer: grid becomes transparent so opt-groups become flex children */
.inspector-body .vr-optimizer { display: block !important; }
.inspector-body .optimizer-grid { display: contents; }
.inspector-body .opt-status { display: none !important; }
/* Each opt-group as a collapsible card — same visual language as .card */
.inspector-body .opt-group {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
/* no overflow:hidden here — it clips title text at rounded corners */
}
/* Title row — mirrors .card-collapse-h2 */
.inspector-body .opt-group-title {
display: flex; align-items: center; gap: 8px;
padding: 12px 14px; font-size: 11px; font-weight: 700; letter-spacing: .08em;
text-transform: uppercase; color: var(--subtext);
cursor: pointer; user-select: none; transition: background .15s;
border-radius: calc(var(--radius) - 1px); /* match inner corner */
}
.inspector-body .opt-group-title:hover { background: var(--panel); }
.inspector-body .opt-group.open > .opt-group-title {
border-bottom: 1px solid var(--border);
border-bottom-left-radius: 0; border-bottom-right-radius: 0;
}
/* Chevron — identical to .card-chev */
.opt-chevron {
display: inline-block; flex-shrink: 0; width: 16px; height: 16px;
border-radius: 4px; background: var(--panel); border: 1px solid var(--border);
color: var(--accent); font-size: 10px; line-height: 16px; text-align: center;
transition: transform .2s;
}
.opt-chevron::before { content: '▾'; }
.inspector-body .opt-group:not(.open) .opt-chevron { transform: rotate(-90deg); }
.inspector-body .opt-group.open .opt-chevron { transform: none; }
/* Title text fills the rest of the row */
.opt-title-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Subtitle — visible only when expanded, indented to align with title text */
.inspector-body .opt-group-subtitle {
font-size: 12px; color: var(--subtext); padding: 0 14px 10px 38px; line-height: 1.5;
}
.inspector-body .opt-group:not(.open) > .opt-group-subtitle { display: none; }
/* Body — hidden when collapsed */
.opt-group-body { overflow: hidden; }
.inspector-body .opt-group:not(.open) > .opt-group-body { display: none; }
.opt-group-footer { display: flex; justify-content: flex-end; padding: 8px 14px 12px; }
.inspector-body .opt-group canvas.opt-wave { display: block; width: 100%; height: 72px; background: var(--bg); }
.inspector-body .opt-group .opt-group-body > .opt-controls { padding: 10px 14px; display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.inspector-body .opt-group .opt-group-body > textarea {
display: block; width: 100%; box-sizing: border-box; padding: 10px 14px; margin: 0;
background: transparent; border: none; outline: none; resize: vertical;
font-size: 16px; color: var(--text); font-family: inherit; min-height: 80px;
}
/* Section order */
.inspector-body .opt-trim-panel { order: 10; }
.inspector-body .opt-maintenance { order: 20; }
.inspector-body .opt-text-panel { order: 30; }
.inspector-body .opt-compare-panel { order: 40; }
.inspector-body .opt-style-panel { order: 50; }
/* vr-main-row in inspector — metadata grid (lang, gender, rating, rename) */
.inspector-body .vr-main-row {
order: 55;
display: flex !important; flex-wrap: wrap; gap: 8px; align-items: center;
padding: 10px 14px;
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
}
.inspector-body .vr-main-row .vr-photo,
.inspector-body .vr-main-row .vr-type,
.inspector-body .vr-main-row .vr-length,
.inspector-body .vr-main-row .vr-db,
.inspector-body .vr-main-row .vr-bench,
.inspector-body .vr-main-row .vr-edit,
.inspector-body .vr-main-row .vr-play-group { display: none !important; }
.inspector-body .vr-main-row .vr-identity { display: flex; gap: 8px; align-items: center; flex: 1; min-width: 0; }
.inspector-body .vr-main-row .vr-rating { display: flex; gap: 2px; align-items: center; }
/* vr-detail-row in inspector — Note only (transcript is in opt-text-panel) */
.inspector-body .vr-detail-row {
order: 60;
display: flex !important; flex-direction: column; gap: 0;
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden;
}
.inspector-body .vr-detail-row .vr-detail-active,
.inspector-body .vr-detail-row .vr-detail-delete { display: none !important; }
.inspector-body .vr-detail-row .vr-ref { display: none !important; }
.inspector-body .vr-note, .inspector-body .vr-source { padding: 10px 14px; display: flex; flex-direction: column; gap: 5px; }
.inspector-body .vr-note label, .inspector-body .vr-source label {
font-size: 10px; font-weight: 700; color: var(--subtext);
text-transform: uppercase; letter-spacing: .07em;
}
.inspector-body .vr-note input, .inspector-body .vr-source input {
background: transparent; border: none; outline: none;
font-size: 13.5px; color: var(--text); width: 100%; padding: 0;
}
.inspector-body .vr-inline { display: flex; align-items: center; gap: 8px; }
.opt-group-meta {
font-size: 14px; font-weight: 600; color: var(--accent);
text-transform: none; letter-spacing: 0; flex-shrink: 0;
}
/* vr-main-row in inspector: always hidden (metadata shown in header grid) */
.inspector-body .vr-main-row { display: none !important; }
.inspector-avatar.drag-over {
opacity: 0.8;
outline: 3px dashed var(--accent);
outline-offset: -4px;
transition: all 0.2s;
}
.vl-avatar.drag-over {
opacity: 0.8;
outline: 2px dashed var(--accent);
outline-offset: -2px;
transition: all 0.2s;
}
/* ── AI Backends / LLMs section ──────────────────────────────────────────── */
/* Category pill tabs */
.llm-cat-tabs {
display: flex; gap: 6px; margin-bottom: 22px; flex-wrap: wrap;
}
.llm-cat-tab {
padding: 6px 18px; font-size: 13px; font-weight: 600;
border: 1.5px solid var(--border); border-radius: 20px;
background: var(--surface); color: var(--subtext);
cursor: pointer; transition: all .15s; line-height: 1.4;
}
.llm-cat-tab:hover { border-color: var(--accent); color: var(--accent); filter: none; }
.llm-cat-tab.active {
background: var(--accent); color: var(--on-accent);
border-color: var(--accent); box-shadow: 0 2px 10px rgba(37,99,235,.28);
}
/* Animated section reveal */
.llm-section { animation: llm-fadein .18s ease; }
@keyframes llm-fadein { from { opacity:0; transform:translateY(5px); } to { opacity:1; transform:none; } }
/* Section header row */
.llm-sec-header {
display: flex; align-items: flex-start; justify-content: space-between;
gap: 16px; margin-bottom: 18px; flex-wrap: wrap;
}
.engines-page-head {
align-items: stretch;
flex-direction: column;
gap: 12px;
padding: 18px 20px;
}
.engines-head-main {
display: flex;
align-items: center;
gap: 14px;
min-width: 0;
}
.engines-head-context {
align-items: center;
justify-content: space-between;
gap: 16px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.engines-context-copy {
min-width: 0;
}
.engines-context-copy .llm-sec-note {
max-width: none;
}
.engines-context-actions {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
justify-content: flex-end;
flex-shrink: 0;
}
@media (max-width: 900px) {
.engines-head-context {
align-items: flex-start;
flex-direction: column;
}
.engines-context-actions {
justify-content: flex-start;
}
}
.llm-sec-title { font-size: 15px; font-weight: 700; color: var(--text); margin: 0 0 4px; }
.llm-sec-note { font-size: 13px; color: var(--subtext); margin: 0; line-height: 1.5; max-width: 640px; }
.llm-free-badge {
font-size: 14px; font-weight: 700; letter-spacing: .02em;
color: #166534; background: rgba(22,163,74,.10); border: 1px solid rgba(22,163,74,.22);
border-radius: 12px; padding: 3px 12px; white-space: nowrap; flex-shrink: 0; align-self: flex-start;
}
.llm-free-local { color: #115E59; background: rgba(13,148,136,.10); border-color: rgba(13,148,136,.22); }
/* ── Active Language Model (global picker) ─────────────── */
.llm-active-panel {
padding: 16px 18px; margin-bottom: 18px;
border: 1px solid rgba(13,148,136,.30);
background: linear-gradient(135deg, rgba(13,148,136,.06), transparent 60%);
}
.llm-active-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 14px; }
.llm-active-icon {
display: inline-flex; align-items: center; justify-content: center;
width: 32px; height: 32px; border-radius: 9px; flex-shrink: 0;
color: var(--teal); background: rgba(13,148,136,.12); font-size: 18px;
}
.llm-active-title { font-size: 14px; font-weight: 700; color: var(--text); margin: 0 0 2px; }
.llm-active-sub { font-size: 12px; color: var(--subtext); margin: 0; line-height: 1.45; }
.llm-active-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.llm-active-lbl {
display: inline-flex; align-items: center; gap: 5px;
font-size: 12px; font-weight: 600; color: var(--subtext); white-space: nowrap;
}
.llm-active-controls select { height: 32px; min-width: 160px; max-width: 260px; }
.llm-active-url-inp { height: 32px; min-width: 260px; max-width: 420px; flex: 1 1 260px; }
.llm-active-status { font-size: 12px; color: var(--subtext); margin-left: 4px; }
.llm-active-status.ok { color: var(--green); }
.llm-active-status.err { color: var(--red); }
/* ── Cloud service cards grid ─────────────────────────── */
.llm-service-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(440px, 1fr)); gap: 14px;
margin-bottom: 8px;
}
.llm-card {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
padding: 16px 18px; display: flex; flex-direction: column; gap: 11px;
transition: box-shadow .2s, border-color .2s, transform .15s;
}
.llm-card:hover { box-shadow: 0 4px 18px rgba(37,99,235,.11); border-color: rgba(37,99,235,.28); transform: translateY(-1px); }
.llm-card-highlight {
border-color: var(--accent); border-width: 1.5px;
background: linear-gradient(135deg, rgba(37,99,235,.03) 0%, var(--surface) 100%);
}
/* Card head: icon bubble + name block + tier badge */
.llm-card-head { display: flex; align-items: center; gap: 11px; }
.llm-card-icon {
font-size: 20px; flex-shrink: 0; line-height: 1;
width: 42px; height: 42px; border-radius: 10px;
display: flex; align-items: center; justify-content: center;
background: var(--panel); border: 1px solid var(--border);
}
.llm-card-name { font-size: 14px; font-weight: 700; color: var(--text); line-height: 1.2; }
.llm-card-sub { font-size: 14px; color: var(--subtext); margin-top: 2px; line-height: 1.35; }
.llm-tier-badge {
margin-left: auto; flex-shrink: 0;
font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
padding: 3px 9px; border-radius: 10px;
}
.llm-tier-free { color: var(--green); background: rgba(22,163,74,.10); border: 1px solid rgba(22,163,74,.22); }
.llm-tier-demo { color: var(--yellow); background: rgba(217,119,6,.10); border: 1px solid rgba(217,119,6,.22); }
.llm-tier-paid { color: var(--mauve); background: rgba(124,58,237,.10); border: 1px solid rgba(124,58,237,.22); }
/* Quick-stat chips */
.llm-card-stats { display: flex; gap: 5px; flex-wrap: wrap; }
.llm-card-stats span {
font-size: 14px; color: var(--subtext);
background: var(--panel); border: 1px solid var(--border);
padding: 2px 9px; border-radius: 10px; white-space: nowrap;
}
/* API key row */
.llm-field-row { display: flex; align-items: center; gap: 7px; }
.llm-label { font-size: 14px; font-weight: 600; color: var(--subtext); white-space: nowrap; flex-shrink: 0; }
.llm-input {
flex: 1; min-width: 0; font-size: 12px; font-family: monospace;
padding: 5px 10px; border: 1px solid var(--border); border-radius: 6px;
background: var(--panel); color: var(--text); outline: none; transition: border-color .15s, background .15s;
}
.llm-input:focus { border-color: var(--accent); background: var(--surface); box-shadow: 0 0 0 3px rgba(37,99,235,.10); }
.llm-link {
font-size: 14px; color: var(--accent); text-decoration: none; white-space: nowrap;
flex-shrink: 0; font-weight: 600; transition: opacity .15s;
}
.llm-link:hover { opacity: .75; }
/* Endpoint display */
.llm-endpoint {
display: flex; align-items: center; gap: 8px;
padding: 5px 10px; background: var(--panel); border-radius: 6px;
border: 1px solid var(--border); font-size: 14px; overflow: hidden;
}
.llm-endpoint-label { color: var(--subtext); font-weight: 600; white-space: nowrap; flex-shrink: 0; }
.llm-endpoint code {
font-family: monospace; font-size: 14px; color: var(--teal);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
/* Model tags */
.llm-models { display: flex; gap: 5px; flex-wrap: wrap; }
.llm-model-tag {
font-size: 10.5px; font-family: monospace; color: var(--accent);
background: rgba(37,99,235,.07); border: 1px solid rgba(37,99,235,.18);
padding: 2px 8px; border-radius: 4px; white-space: nowrap;
}
/* Info / tip box */
.llm-info-box {
font-size: 12px; color: var(--subtext); line-height: 1.55;
background: var(--panel); border-radius: 7px; padding: 10px 13px;
border-left: 3px solid var(--yellow);
}
.llm-link-inline { color: var(--accent); text-decoration: none; font-weight: 600; }
.llm-link-inline:hover { text-decoration: underline; }
.llm-info-note { font-size: 14px; color: var(--subtext); font-style: italic; }
.llm-info-note code { font-family: monospace; color: var(--teal); font-style: normal; }
/* ── Local services ────────────────────────────────────── */
.llm-local-cat {
font-size: 14px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
color: var(--subtext); margin: 0 0 10px;
padding-bottom: 7px; border-bottom: 1px solid var(--border);
}
.llm-local-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 14px;
margin-bottom: 6px;
}
.llm-local-card {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
padding: 14px 16px; display: flex; flex-direction: column; gap: 9px;
transition: box-shadow .2s, border-color .2s, background .2s;
}
.llm-local-card:hover { box-shadow: 0 4px 16px rgba(13,148,136,.12); border-color: rgba(13,148,136,.35); }
.llm-local-card-running { border-color: var(--teal); background: rgba(13,148,136,.025); }
.llm-local-card-online { border-color: rgba(22,163,74,.6); background: rgba(22,163,74,.04); }
.llm-local-card-offline { border-color: rgba(220,38,38,.4); background: rgba(220,38,38,.03); }
.llm-local-head { display: flex; align-items: center; gap: 8px; }
.llm-local-icon { font-size: 20px; flex-shrink: 0; width: 26px; text-align: center; line-height: 1; }
.llm-local-name { font-size: 13.5px; font-weight: 700; color: var(--text); flex: 1; min-width: 0; }
.llm-local-compat {
font-size: 10px; font-weight: 600; color: var(--subtext);
background: var(--panel); border: 1px solid var(--border);
padding: 2px 8px; border-radius: 10px; white-space: nowrap;
}
.llm-compat-detected {
color: #115E59; background: rgba(13,148,136,.10); border-color: rgba(13,148,136,.28);
}
.llm-compat-running {
color: var(--green, #16a34a); background: rgba(22,163,74,.10); border-color: rgba(22,163,74,.30);
}
.llm-compat-stopped {
color: var(--red, #dc2626); background: rgba(220,38,38,.08); border-color: rgba(220,38,38,.25);
}
.llm-local-desc { font-size: 12px; color: var(--subtext); line-height: 1.5; margin: 0; }
.llm-local-url {
display: flex; align-items: center; gap: 7px; flex-wrap: nowrap;
font-size: 12px; font-weight: 600; color: var(--subtext);
background: var(--panel); padding: 4px 9px; border-radius: 5px; border: 1px solid var(--border);
transition: border-color .15s;
}
.llm-local-url:focus-within { border-color: var(--accent); }
.llm-local-url code { font-family: monospace; font-size: 14px; color: var(--teal); }
.llm-local-url-label { white-space: nowrap; flex-shrink: 0; }
.llm-local-url-inp {
flex: 1; min-width: 0; font-family: monospace; font-size: 13px; color: var(--teal);
background: transparent; border: none; outline: none; padding: 0;
}
.llm-local-url-inp::placeholder { color: var(--teal); opacity: .55; }
/* Code snippet block with dark theme */
.llm-local-snippet { background: #1b1f2e; border-radius: 8px; overflow: hidden; }
.llm-snippet-bar {
display: flex; align-items: center; justify-content: space-between;
padding: 5px 11px; background: rgba(255,255,255,.04); border-bottom: 1px solid rgba(255,255,255,.06);
font-size: 10.5px; color: rgba(255,255,255,.4); font-weight: 600; letter-spacing: .02em;
cursor: pointer; user-select: none; transition: background .12s;
}
.llm-snippet-bar:hover { background: rgba(255,255,255,.08); }
.llm-snip-chev { color: rgba(255,255,255,.45); margin-right: 5px; font-size: 9px; flex-shrink: 0; }
.llm-copy-btn {
font-size: 10px; padding: 2px 9px; border-radius: 4px;
background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.18);
color: rgba(255,255,255,.65); cursor: pointer; transition: background .15s; font-family: inherit;
}
.llm-copy-btn:hover { background: rgba(255,255,255,.2); filter: none; }
.llm-local-snippet pre {
margin: 0; padding: 10px 12px; color: #9ecfb0; font-family: monospace;
font-size: 14px; line-height: 1.65; overflow-x: auto; white-space: pre;
}
.llm-local-link {
font-size: 14.5px; color: var(--accent); text-decoration: none; font-weight: 600;
align-self: flex-start;
}
.llm-local-link:hover { text-decoration: underline; }
/* Metric chips inside AI Backend cards */
.llm-local-metrics { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 4px; }
.llm-metric-chip {
font-size: 10px; padding: 1px 6px; border-radius: 4px;
border: 1px solid rgba(99,102,241,.3); background: rgba(99,102,241,.07);
color: #1D4ED8; white-space: nowrap;
}
/* ── Engine card — unified control bar ──────────────────────────────────── */
.llm-local-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* Single row that holds Connect + Docker controls + Use-as in left→right order */
.dc-controls-row {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.dc-ctrl-group { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
/* ── Connect / Disconnect — primary CTA, prominent blue ─────────────────── */
.llm-local-ping {
padding: 5px 12px; font-size: 11.5px; font-weight: 700; border-radius: 5px;
border: 1.5px solid #2563eb; background: #2563eb; color: #fff;
cursor: pointer; font-family: inherit;
display: inline-flex; align-items: center; gap: 5px;
white-space: nowrap; flex-shrink: 0;
transition: background .15s, border-color .15s, box-shadow .15s;
}
.llm-local-ping:hover:not(:disabled) {
background: #1d4ed8; border-color: #1d4ed8;
box-shadow: 0 2px 8px rgba(37,99,235,.35);
}
.llm-local-ping:disabled { opacity: .5; cursor: default; }
.llm-local-ping.ok {
background: rgba(22,163,74,.1); border-color: rgba(22,163,74,.55); color: #16a34a;
}
.llm-local-ping.ok:hover:not(:disabled) {
background: rgba(220,38,38,.07); border-color: var(--red); color: var(--red);
}
.llm-local-ping.err { border-color: var(--red); color: var(--red); background: rgba(220,38,38,.06); }
/* ── Docker action buttons (Stop / Start / Restart) ─────────────────────── */
.llm-use-btn {
font-size: 11.5px; padding: 5px 10px; border-radius: 5px;
border: 1.5px solid rgba(13,148,136,.4); background: rgba(13,148,136,.07);
color: #115E59; cursor: pointer; font-family: inherit; font-weight: 600;
transition: background .15s, border-color .15s;
display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; flex-shrink: 0;
}
.llm-use-btn:hover:not(:disabled) { background: rgba(13,148,136,.15); border-color: var(--teal); }
.llm-use-btn:active { background: rgba(13,148,136,.25); }
.llm-use-btn:disabled { opacity: .5; cursor: default; }
/* ── "Use as TTS / STT" — activate action, right-aligned, clearly distinct ─ */
.dc-use-btn {
margin-left: auto;
padding: 5px 12px; font-size: 11.5px; font-weight: 700; border-radius: 5px;
border: 1.5px solid #2563eb; background: #2563eb;
color: #fff; cursor: pointer; font-family: inherit;
display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; flex-shrink: 0;
transition: background .15s, border-color .15s, box-shadow .15s;
}
.dc-use-btn:hover:not(:disabled) {
background: #1d4ed8; border-color: #1d4ed8;
box-shadow: 0 2px 8px rgba(37,99,235,.35);
}
.dc-use-btn.active {
background: rgba(13,148,136,.22); border-color: var(--teal);
box-shadow: 0 0 0 2px rgba(13,148,136,.18);
}
.dc-use-btn:disabled { opacity: .5; cursor: default; }
/* Password show/hide toggle */
.llm-eye-btn {
background: none; border: 1px solid var(--border); border-radius: 5px;
padding: 3px 6px; font-size: 13px; cursor: pointer; color: var(--subtext);
flex-shrink: 0; transition: border-color .15s, opacity .15s; line-height: 1; opacity: .55;
}
.llm-eye-btn:hover { border-color: var(--accent); opacity: 1; filter: none; }
.llm-eye-btn.active { opacity: 1; border-color: var(--accent); }
/* "Key saved" indicator inside card head */
.llm-saved-badge {
margin-left: auto; font-size: 10px; font-weight: 700; letter-spacing: .02em;
color: var(--green); background: rgba(22,163,74,.10); border: 1px solid rgba(22,163,74,.22);
border-radius: 10px; padding: 2px 9px; white-space: nowrap; flex-shrink: 0;
}
/* Override margin-left:auto on tier badge when saved badge is also present */
.llm-card-head .llm-tier-badge { margin-left: auto; }
.llm-card-head .llm-saved-badge { margin-left: 0; }
/* How-to tip panel */
.llm-local-howto {
display: flex; align-items: flex-start; gap: 14px; margin-top: 20px;
background: var(--panel); border-radius: var(--radius); padding: 16px 18px;
border-left: 4px solid var(--accent);
}
.llm-howto-icon { font-size: 22px; flex-shrink: 0; margin-top: 1px; }
.llm-howto-body { font-size: 13px; line-height: 1.55; color: var(--text); }
.llm-howto-body strong { display: block; margin-bottom: 5px; }
.llm-howto-body p { margin: 0; color: var(--subtext); }
.llm-howto-body em { font-style: normal; font-weight: 600; color: var(--text); }
/* ── Add Custom Engine dialog ─────────────────────────────────────────────── */
.add-engine-dlg {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
padding: 0; width: min(460px, 94vw); box-shadow: 0 8px 32px rgba(0,0,0,.28);
color: var(--text);
}
.add-engine-dlg::backdrop { background: rgba(0,0,0,.45); }
.add-engine-form { padding: 22px 24px; display: flex; flex-direction: column; gap: 14px; }
.add-engine-title { margin: 0 0 2px; font-size: 15px; font-weight: 700; }
.add-engine-field { display: flex; flex-direction: column; gap: 5px; }
.add-engine-field label { font-size: 12px; font-weight: 600; color: var(--subtext); }
.add-engine-opt { font-weight: 400; opacity: .65; }
.add-engine-field input, .add-engine-field select {
padding: 7px 10px; border: 1px solid var(--border); border-radius: 5px;
background: var(--bg); color: var(--text); font-family: inherit; font-size: 13px;
transition: border-color .15s;
}
.add-engine-field input:focus, .add-engine-field select:focus {
outline: none; border-color: var(--accent);
}
.add-engine-actions { display: flex; gap: 8px; justify-content: flex-end; padding-top: 4px; }
/* Delete button variant */
.dc-delete-btn { border-color: rgba(220,38,38,.35) !important; color: var(--red, #dc2626) !important; background: rgba(220,38,38,.05) !important; }
.dc-delete-btn:hover { background: rgba(220,38,38,.12) !important; border-color: var(--red, #dc2626) !important; }
/* ── ElevenLabs Voice Browser ──────────────────────────────────────────────── */
.el-browser { padding: 0; overflow: hidden; }
.el-head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 14px; padding: 16px 20px 14px; border-bottom: 1px solid var(--border); }
.el-brand { display: flex; align-items: flex-start; gap: 12px; flex: 1; min-width: 200px; }
.el-brand-logo { display: flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 9px; background: #131314; color: #fff; font-weight: 800; font-size: 13px; letter-spacing: -0.5px; flex-shrink: 0; margin-top: 3px; }
.el-brand h2 { margin: 0 0 3px; font-size: 14px; font-weight: 700; }
.el-brand p { margin: 0; font-size: 12px; }
.el-key-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.el-key-field { display: flex; gap: 6px; }
.el-key-field input { width: 230px; font-size: 12px; padding: 5px 9px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); color: var(--text); font-family: monospace; }
.el-key-btn { font-size: 12px; padding: 5px 12px; }
.el-key-status { font-size: 11px; font-weight: 600; }
.el-key-ok { color: #38a169; }
.el-key-none { color: var(--subtext); }
.el-cats { display: flex; flex-wrap: wrap; gap: 6px; padding: 11px 20px; border-bottom: 1px solid var(--border); }
.el-cat { padding: 4px 13px; border-radius: 20px; border: 1px solid var(--border); background: transparent; color: var(--text); font-size: 12px; cursor: pointer; transition: border-color .15s, color .15s, background .15s; white-space: nowrap; }
.el-cat:hover { border-color: var(--accent); color: var(--accent); }
.el-cat.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.el-filters { display: flex; flex-wrap: wrap; gap: 8px; padding: 10px 20px; border-bottom: 1px solid var(--border); align-items: center; }
.el-search { flex: 1; min-width: 130px; font-size: 13px; padding: 5px 9px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); color: var(--text); font-family: inherit; }
.el-filters select { font-size: 12px; padding: 5px 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text); font-family: inherit; }
.el-status-bar { padding: 6px 20px; background: var(--panel); border-bottom: 1px solid var(--border); font-size: 12px; color: var(--subtext); }
.el-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); }
.el-grid > .el-loading,
.el-grid > .el-error,
.el-grid > .el-empty,
.el-grid > .el-idle { grid-column: 1/-1; padding: 36px 20px; text-align: center; color: var(--subtext); font-size: 13px; }
.el-spinner { display: inline-block; width: 13px; height: 13px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: elSpin .75s linear infinite; vertical-align: middle; margin-right: 6px; }
@keyframes elSpin { to { transform: rotate(360deg); } }
.el-error { color: #e53e3e !important; }
.el-card-voice { display: flex; align-items: stretch; gap: 10px; padding: 11px 13px 0; border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); transition: background .12s; flex-wrap: wrap; }
.el-card-voice:hover { background: var(--panel); }
.el-vc-av { flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; background: hsl(var(--elh, 220), 52%, 52%); color: #fff; font-weight: 700; font-size: 15px; display: flex; align-items: center; justify-content: center; margin-top: 3px; }
.el-vc-body { flex: 1; min-width: 0; padding-bottom: 10px; }
.el-vc-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 4px; }
.el-vc-tags { display: flex; flex-wrap: wrap; gap: 3px; margin-bottom: 4px; }
.el-tag { font-size: 10px; padding: 1px 5px; border-radius: 3px; background: var(--panel); border: 1px solid var(--border); color: var(--subtext); white-space: nowrap; }
.el-lang { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 700; }
.el-uc { color: var(--accent); border-color: var(--accent); background: transparent; }
.el-free { color: #38a169; border-color: #38a169; background: transparent; }
/* ── Get Voices Online — source tabs ──────────────────────────────────────── */
.gvo-tabs { display: flex; gap: 4px; flex-wrap: wrap; align-items: flex-end; margin: 0 0 14px; padding: 0; border-bottom: 1px solid var(--border); }
.gvo-tab { display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 11px 18px; border: 1px solid transparent; border-bottom: none; background: transparent; color: var(--subtext); font-size: 14px; font-weight: 600; border-radius: 10px 10px 0 0; cursor: pointer; transition: background .15s, color .15s, border-color .15s; font-family: inherit; position: relative; bottom: -1px; }
.gvo-tab:hover { background: var(--surface); color: var(--text); }
.gvo-tab.active { background: var(--panel); color: var(--accent); border-color: var(--border); border-bottom-color: var(--panel); }
.gvo-tab.active::after { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px; background: var(--accent); border-radius: 2px 2px 0 0; }
.gvo-tab .mdi { font-size: 18px; }
.gvo-tab-sub { font-size: 11px; font-weight: 500; color: var(--subtext); }
.gvo-eleven-logo { background: #111; color: #fff; font-weight: 800; font-size: 11px; width: 20px; height: 20px; border-radius: 5px; display: inline-flex; align-items: center; justify-content: center; }
.gvo-tab.active .gvo-eleven-logo { background: var(--accent); color: #fff; }
.fa-pop-close { background: none; border: none; color: var(--subtext); cursor: pointer; font-size: 18px; padding: 0 2px; line-height: 1; }
.fa-pop-close:hover { color: var(--text); }
/* ── Fish.audio voice browser (fish.audio-style cards w/ hover actions) ────── */
.fa-toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 12px 20px; border-bottom: 1px solid var(--border); }
.fa-search-wrap { flex: 1; min-width: 200px; position: relative; display: flex; align-items: center; }
.fa-search-icon { position: absolute; left: 13px; color: var(--subtext); font-size: 18px; pointer-events: none; }
.fa-search-big { width: 100%; padding: 9px 14px 9px 38px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--text); font-family: inherit; font-size: 13px; }
.fa-search-big:focus { outline: none; border-color: var(--accent); }
.fa-pill-select { font-size: 13px; padding: 8px 12px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--text); font-family: inherit; cursor: pointer; }
.fa-browse-btn { border-radius: 999px; padding: 8px 18px; }
.fa-filter-anchor { position: relative; }
.fa-filter-btn { position: relative; width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; transition: all .12s; }
.fa-filter-btn:hover, .fa-filter-btn.active { border-color: var(--accent); color: var(--accent); }
.fa-filter-badge { position: absolute; top: -4px; right: -4px; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px; background: var(--accent); color: #fff; font-size: 10px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }
/* Popover */
.fa-filter-pop { position: fixed; z-index: 1000; width: 320px; max-width: 90vw; background: var(--card-bg, var(--panel)); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 12px 36px rgba(0,0,0,.25); padding: 16px; display: flex; flex-direction: column; gap: 13px; overflow-y: auto; }
/* author `display` overrides the UA [hidden] rule — restore it so the popover/badge can hide */
.fa-filter-pop[hidden], .fa-filter-badge[hidden] { display: none; }
.fa-pop-head { display: flex; align-items: center; justify-content: space-between; }
.fa-pop-head strong { font-size: 15px; }
.fa-pop-reset { background: none; border: none; color: var(--subtext); font-size: 12px; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
.fa-pop-reset:hover { color: var(--accent); }
.fa-pop-group { display: flex; flex-direction: column; gap: 7px; }
.fa-pop-group > label { font-size: 12px; font-weight: 700; color: var(--text); }
.fa-pchips { display: flex; flex-wrap: wrap; gap: 6px; }
.fa-pchip { font-size: 12px; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--subtext); cursor: pointer; transition: all .12s; font-family: inherit; }
.fa-pchip:hover { color: var(--text); border-color: var(--accent); }
.fa-pchip.active { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.fa-pop-tag { width: 100%; padding: 7px 11px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text); font-family: inherit; font-size: 12px; }
.fa-pop-tag:focus { outline: none; border-color: var(--accent); }
.fa-pop-apply { width: 100%; border-radius: 999px; padding: 9px; margin-top: 2px; }
@media (max-width: 560px) { .fa-filter-pop { right: auto; left: 0; } }
.fa-card { display: flex; gap: 11px; padding: 12px 14px; border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); position: relative; transition: background .12s; }
.fa-card:hover { background: var(--panel); }
.fa-card-disabled { opacity: .62; }
.fa-card-avatar { position: relative; width: 48px; height: 48px; border-radius: 10px; overflow: hidden; flex-shrink: 0; background: linear-gradient(135deg, #0ea5e9, #6366f1); }
.fa-avatar { width: 100%; height: 100%; object-fit: cover; display: block; }
.fa-avatar-fallback::after { content: "🐟"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 22px; }
.fa-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,.45); color: #fff; border: none; cursor: pointer; font-size: 22px; opacity: 0; transition: opacity .12s; }
.fa-card:hover .fa-play, .fa-card-playing .fa-play { opacity: 1; }
.fa-card-playing .fa-play .mdi::before { content: "\F03E4"; } /* pause glyph */
.fa-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.fa-card-top { display: flex; align-items: baseline; gap: 5px; min-width: 0; }
.fa-card-name { font-size: 13.5px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fa-card-author { font-size: 11px; color: var(--subtext); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex-shrink: 1; }
.fa-card-desc { font-size: 12px; color: var(--subtext); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.fa-card-meta { display: flex; flex-wrap: wrap; gap: 4px; }
.fa-meta-chip { font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--surface); border: 1px solid var(--border); color: var(--subtext); white-space: nowrap; }
.fa-card-foot { display: flex; align-items: center; gap: 12px; margin-top: 2px; }
.fa-stat { font-size: 11px; color: var(--subtext); display: inline-flex; align-items: center; gap: 3px; }
.fa-import { margin-left: auto; padding: 3px 11px; font-size: 12px; opacity: 0; transition: opacity .12s; }
.fa-card:hover .fa-import, .fa-card-imported .fa-import { opacity: 1; }
.fa-card-imported .fa-import { background: #16a34a; border-color: #16a34a; }
@media (hover: none) { .fa-play, .fa-import { opacity: 1 !important; } }
.el-feat { color: #d69e2e; border-color: #d69e2e; background: transparent; }
.el-clones { opacity: .7; }
.el-vc-desc { font-size: 11px; color: var(--subtext); line-height: 1.4; margin-bottom: 6px; }
.el-vc-meta { margin-top: 4px; }
.el-play { border: 1px solid var(--border); border-radius: 5px; background: var(--surface); color: var(--text); font-size: 11px; padding: 4px 10px; cursor: pointer; white-space: nowrap; transition: border-color .15s, color .15s; font-family: inherit; }
.el-play:hover { border-color: var(--accent); color: var(--accent); }
.el-vc-footer { width: 100%; display: flex; justify-content: flex-end; padding: 6px 0 10px; border-top: 1px solid var(--border); margin-top: 4px; }
.el-clone { border: 1px solid var(--accent); border-radius: 5px; background: var(--accent); color: #fff; font-size: 12px; padding: 5px 12px; cursor: pointer; white-space: nowrap; transition: opacity .15s; font-family: inherit; font-weight: 600; }
.el-clone:hover { opacity: .85; }
.el-pager { display: flex; align-items: center; gap: 12px; padding: 12px 20px; border-top: 1px solid var(--border); }
.el-pager-info { flex: 1; text-align: center; font-size: 12px; color: var(--subtext); }
/* Bottom action buttons */
/* ── Card subtitle & opt-group subtitle ─────────────────────────────────── */
.card-subtitle { font-size: 12px; color: var(--subtext); line-height: 1.5; margin: 2px 0 6px; }
.opt-group-subtitle { font-size: 11px; color: var(--subtext); padding: 0 14px 6px; line-height: 1.4; }
/* ── Docker container grid ──────────────────────────────────────────────── */
.dc-section-head {
display: flex; align-items: flex-start; justify-content: space-between;
gap: 12px; margin: 0 0 12px;
}
.dc-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(440px, 1fr));
gap: 14px;
margin-bottom: 8px;
}
.dc-loading {
grid-column: 1 / -1; padding: 18px 0; text-align: center;
font-size: 13px; color: var(--subtext);
}
.stt-test-panel {
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px 14px;
margin-bottom: 18px;
display: flex;
flex-direction: column;
gap: 8px;
}
.stt-test-row {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.stt-test-label {
font-size: 12px;
font-weight: 600;
color: var(--subtext);
text-transform: uppercase;
letter-spacing: .04em;
white-space: nowrap;
}
.stt-test-select {
font-size: 13px;
padding: 4px 8px;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
flex: 1;
min-width: 160px;
max-width: 320px;
}
.stt-test-mic {
width: 34px; height: 34px;
border-radius: 50%;
border: none;
background: var(--accent);
color: #fff;
font-size: 16px;
cursor: pointer;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
transition: background .15s, transform .1s;
}
.stt-test-mic:hover { background: var(--accent-hover, #0060d0); }
.stt-test-mic.recording { background: #e53e3e; animation: stt-pulse 1s infinite; }
.stt-test-mic.busy { background: var(--subtext); cursor: not-allowed; }
@keyframes stt-pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.1); } }
.stt-test-status {
font-size: 12px;
color: var(--subtext);
min-width: 60px;
}
.stt-test-result {
font-size: 13px;
color: var(--text);
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
padding: 8px 10px;
white-space: pre-wrap;
word-break: break-word;
min-height: 32px;
}
.dc-load-err { color: var(--red) !important; }
/* ── Engine card skeleton ────────────────────────────────────────────────── */
.dc-skel-card {
background: var(--surface); border: 1px solid var(--border);
border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px;
min-height: 120px;
}
.dc-skel-line {
border-radius: 5px; height: 13px;
background: linear-gradient(90deg, var(--panel), rgba(37,99,235,.08), var(--panel));
background-size: 220% 100%; animation: skeletonSweep 1.15s ease-in-out infinite;
}
.dc-skel-line.wide { width: 70%; }
.dc-skel-line.medium { width: 45%; }
.dc-skel-line.short { width: 28%; }
.dc-skel-line.tall { height: 20px; width: 55%; }
.dc-card {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius); padding: 14px 16px;
display: flex; flex-direction: column; gap: 6px;
transition: border-color .15s, box-shadow .15s;
}
.dc-card:hover { box-shadow: var(--shadow); border-color: rgba(37,99,235,.3); }
.dc-card-running { border-color: rgba(22,163,74,.45); background: rgba(22,163,74,.025); }
.dc-card-head {
display: flex; align-items: center; gap: 8px; margin-bottom: 2px;
}
.dc-icon { font-size: 20px; flex-shrink: 0; width: 26px; text-align: center; line-height: 1; }
.dc-dot {
width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
}
.dc-running { background: var(--green); box-shadow: 0 0 0 3px rgba(22,163,74,.18); }
.dc-stopped { background: var(--yellow); }
.dc-absent { background: var(--border); }
.dc-name { font-size: 13px; font-weight: 700; color: var(--text); flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dc-badges { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.dc-role {
font-size: 10px; font-weight: 700; padding: 1px 5px; border-radius: 3px;
background: var(--accent); color: #fff; white-space: nowrap;
}
.dc-port {
font-size: 10px; font-weight: 600; padding: 1px 5px; border-radius: 3px;
background: var(--panel); border: 1px solid var(--border); color: var(--subtext);
font-family: monospace;
}
.dc-status-label { font-size: 11px; color: var(--subtext); margin-bottom: 2px; }
.dc-desc { font-size: 12px; color: var(--subtext); line-height: 1.45; margin: 0; flex: 1; }
.dc-metrics { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 4px; }
.dc-metric-chip {
font-size: 10px; padding: 1px 6px; border-radius: 4px;
border: 1px solid rgba(99,102,241,.3); background: rgba(99,102,241,.07);
color: var(--accent); white-space: nowrap;
}
.dc-actions { margin-top: 6px; display: flex; gap: 6px; flex-wrap: wrap; }
.dc-btn { font-size: 11.5px; padding: 4px 12px; }
/* ── Performance benchmark ──────────────────────────────────────────────── */
.perf-table-wrap { overflow-x: auto; margin-top: 12px; }
.perf-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.perf-table th, .perf-table td { padding: 7px 10px; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }
.perf-table th { color: var(--subtext); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; }
.perf-th-sort { cursor: pointer; user-select: none; }
.perf-th-sort:hover { color: var(--text); }
.perf-th-sort::after { content: ' ⇅'; opacity: .35; font-size: 10px; }
.perf-th-sort.perf-sort-asc::after { content: ' ↑'; opacity: 1; color: var(--accent); }
.perf-th-sort.perf-sort-desc::after { content: ' ↓'; opacity: 1; color: var(--accent); }
.perf-row-error td { color: var(--subtext); }
.perf-ok { color: var(--green); font-weight: 600; }
.perf-err { color: var(--red); }
.perf-summary { display: flex; flex-wrap: wrap; gap: 10px 18px; padding: 10px 0 4px; font-size: 13px; }
.perf-stat { display: flex; align-items: center; gap: 5px; }
.perf-good { color: var(--green); }
.perf-slow { color: var(--yellow); }
.perf-trend-row { display: flex; align-items: center; gap: 10px; padding: 6px 0 2px; flex-wrap: wrap; font-size: 13px; }
.perf-trend-label { color: var(--subtext); }
.perf-trend-badge { display: inline-flex; align-items: center; gap: 4px; font-weight: 600; padding: 2px 8px; border-radius: 12px; font-size: 12px; }
.perf-trend-better { background: rgba(var(--green-rgb,72,199,116),.15); color: var(--green); }
.perf-trend-worse { background: rgba(var(--red-rgb,255,91,91),.15); color: var(--red); }
.perf-trend-stable { background: var(--panel); color: var(--subtext); }
.perf-sparkline-wrap { display: flex; align-items: center; }
.perf-sparkline { width: 120px; height: 32px; display: block; }
.bench-history-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.bench-history-filter { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--subtext); cursor: pointer; }
.perf-history-list { display: flex; flex-direction: column; gap: 0; overflow-x: auto; }
.perf-history-empty { font-size: 13px; color: var(--subtext); padding: 16px 0; }
.perf-history-row { display: grid; grid-template-columns: 118px minmax(96px,.8fr) 34px 72px 72px minmax(190px,1.4fr) 92px 82px 68px 70px 24px; min-width: 1010px; gap: 0 10px; padding: 7px 4px; border-bottom: 1px solid var(--border); font-size: 12px; align-items: center; }
.perf-history-row:last-child { border-bottom: none; }
.perf-history-head { font-size: 11px; color: var(--subtext); text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
.perf-history-sort { display: inline-flex; align-items: center; gap: 3px; max-width: 100%; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; text-transform: inherit; letter-spacing: inherit; cursor: pointer; text-align: left; }
.perf-history-sort:hover, .perf-history-sort.active { color: var(--accent); }
.perf-history-sort .mdi { font-size: 13px; line-height: 1; }
.perf-history-avatar { width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; overflow: hidden; color: #fff; font-size: 11px; font-weight: 700; }
.perf-history-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.perf-history-avatar-icon { width: 24px !important; height: 24px !important; }
.perf-history-avatar-init { flex-shrink: 0; }
.perf-history-ts { color: var(--subtext); font-size: 11px; }
.perf-history-del { cursor: pointer; color: var(--subtext); font-size: 11px; text-align: right; }
.perf-history-del:hover { color: var(--red); }
.batch-voice-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.batch-search-wrap { display: flex; align-items: center; gap: 7px; min-width: min(300px, 100%); flex: 1 1 260px; height: 34px; padding: 0 10px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--subtext); }
.batch-search-wrap input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--text); font-size: 13px; }
.batch-voice-list { display: flex; flex-direction: column; gap: 0; max-height: 320px; overflow-y: auto; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); }
.batch-voice-item { display: grid; grid-template-columns: auto auto minmax(0,1fr) auto auto auto; align-items: center; gap: 9px; padding: 7px 10px; cursor: pointer; font-size: 13px; border-bottom: 1px solid var(--border); transition: background .1s; }
.batch-voice-item:last-child { border-bottom: none; }
.batch-voice-item:hover { background: var(--hover); }
.batch-voice-item.is-selected { background: rgba(37,99,235,.08); }
.batch-voice-item.is-active .batch-voice-name { font-weight: 700; }
.batch-voice-avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; font-weight: 700; }
.batch-voice-main { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.batch-voice-name, .batch-voice-id { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.batch-voice-name { color: var(--text); font-weight: 600; }
.batch-voice-id { color: var(--subtext); font-size: 11px; font-family: monospace; }
.batch-voice-meta { font-size: 11px; color: var(--subtext); white-space: nowrap; }
.batch-voice-stats { font-size: 11px; color: var(--subtext); font-variant-numeric: tabular-nums; white-space: nowrap; }
.batch-voice-tag { font-size: 10px; padding: 1px 6px; border-radius: 10px; background: rgba(var(--accent-rgb,99,102,241),.15); color: var(--accent); font-weight: 600; white-space: nowrap; }
@media (max-width: 700px) { .batch-voice-item { grid-template-columns: auto auto minmax(0,1fr); } .batch-voice-stats, .batch-voice-tag { grid-column: 3; justify-self: start; } }
.batch-progress { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.batch-progress-head { display: flex; justify-content: space-between; font-size: 12px; color: var(--subtext); }
.batch-progress-track { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; }
.batch-progress-bar { height: 100%; border-radius: 3px; background: var(--accent); transition: width .3s; width: 0%; }
.bench-tabs {
display: flex; gap: 4px; flex-wrap: wrap; align-items: flex-end;
margin: 0; padding: 0 0 0 0; border-bottom: none;
}
.bench-tab {
display: inline-flex; align-items: center; justify-content: center; gap: 7px;
padding: 11px 18px; border: 1px solid transparent; border-bottom: none;
background: transparent; color: var(--subtext); font-size: 14px; font-weight: 700;
border-radius: 10px 10px 0 0; cursor: pointer; font-family: inherit;
position: relative; bottom: -1px;
}
.bench-tab:hover { background: var(--surface); color: var(--text); filter: none; }
.bench-tab.active { background: var(--surface); color: var(--accent); border-color: var(--border); border-bottom-color: var(--surface); }
.bench-tab.active::after { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px; background: var(--accent); border-radius: 2px 2px 0 0; }
.bench-tab .mdi { font-size: 18px; }
.bench-tab span:last-child { font-size: 11px; font-weight: 600; color: var(--subtext); }
.bench-pane { display: none; }
.bench-pane.active { display: flex; flex-direction: column; gap: 14px; margin-top: 0; }
.bench-pane.active > .card:first-child { border-top-left-radius: 0; }
.bench-card { gap: 14px; }
.bench-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.bench-card-head h3 { margin: 0; font-size: 15px; color: var(--text); }
.bench-card-head p { margin: 4px 0 0; font-size: 13px; color: var(--subtext); line-height: 1.45; max-width: 920px; }
.bench-input-grid { align-items: end; }
.bench-library-source { margin: 2px 0 4px; max-width: 760px; }
.bench-source-row { display: flex; gap: 8px; align-items: center; }
.bench-source-row select { flex: 1; min-width: 220px; }
.bench-source-note { margin-top: 5px; color: var(--subtext); font-size: 12px; }
.bench-source-row .bvp-root { flex: 1 1 360px; min-width: min(360px, 100%); }
.bvp-root { position: relative; display: inline-flex; flex-direction: column; min-width: 260px; flex: 1 1 300px; }
.bvp-trigger {
width: 100%; min-height: 34px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
padding: 0 10px; cursor: pointer; background: var(--input-bg, var(--panel)); color: var(--text);
border: 1px solid var(--border); border-radius: var(--radius, 8px); text-align: left; user-select: none;
}
.bvp-trigger:hover, .bvp-trigger.open { border-color: var(--accent); filter: none; }
.bvp-trigger-content { min-width: 0; flex: 1; display: flex; align-items: center; gap: 8px; overflow: hidden; }
.bvp-trigger-main { min-width: 0; display: flex; flex-direction: column; line-height: 1.15; }
.bvp-trigger-name { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; color: var(--text); }
.bvp-trigger-stats { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--subtext); font-variant-numeric: tabular-nums; }
.bvp-placeholder { font-size: 13px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bvp-chevron { color: var(--subtext); flex-shrink: 0; transition: transform .15s; }
.bvp-trigger.open .bvp-chevron { transform: rotate(180deg); }
.bvp-avatar { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
.bvp-drop[hidden] { display: none !important; }
.bvp-drop {
position: absolute; z-index: 245; top: calc(100% + 4px); left: 0; right: 0; min-width: min(520px, 92vw);
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius, 8px);
box-shadow: 0 10px 28px rgba(0,0,0,.18); overflow: hidden;
}
.bvp-search-wrap { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); color: var(--subtext); background: var(--panel); }
.bvp-search { flex: 1; min-width: 0; border: none; outline: none; background: transparent; color: var(--text); font-size: 13px; }
.bvp-list { max-height: 340px; overflow-y: auto; padding: 4px; }
.bvp-item {
width: 100%; display: flex; align-items: center; gap: 9px; padding: 7px 8px;
border: 0; border-radius: 6px; background: transparent; color: var(--text); text-align: left; cursor: pointer;
}
.bvp-item:hover, .bvp-item:focus { background: var(--hover); outline: none; filter: none; }
.bvp-item.selected { background: rgba(37,99,235,.12); color: var(--accent); }
.bvp-item-main { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.bvp-item-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 600; }
.bvp-item-sub { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--subtext); }
.bvp-item-stats { flex-shrink: 0; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--subtext); font-variant-numeric: tabular-nums; }
.bvp-empty { padding: 14px 12px; text-align: center; color: var(--subtext); font-size: 12px; }
.bench-inline-controls .bvp-root { min-width: min(340px, 100%); flex: 1 1 340px; }
@media (max-width: 700px) { .bench-source-row { flex-direction: column; align-items: stretch; } .bvp-drop { min-width: 100%; } .bvp-item-stats { max-width: 110px; } }
.bench-engine-panel { border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); overflow: hidden; }
.bench-engine-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 13px; }
.bench-engine-head span { color: var(--subtext); }
.bench-engine-list { max-height: 420px; min-height: 180px; overflow: auto; display: flex; flex-direction: column; resize: vertical; }
.bench-engine-empty, .bench-empty { color: var(--subtext); font-size: 13px; padding: 16px; text-align: left; }
.bench-engine-item {
display: grid; grid-template-columns: auto minmax(180px, 1fr) auto minmax(160px, .45fr);
gap: 10px; align-items: center; padding: 9px 12px; border-bottom: 1px solid var(--border);
cursor: pointer; background: var(--surface);
}
.bench-engine-item:last-child { border-bottom: none; }
.bench-engine-item:hover { background: color-mix(in srgb, var(--panel) 70%, var(--surface)); }
.bench-engine-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.bench-engine-main strong { font-size: 13px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bench-engine-main small { font-size: 11px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: monospace; }
.bench-engine-state { font-size: 11px; font-weight: 700; padding: 2px 7px; border-radius: 999px; background: var(--panel); color: var(--subtext); border: 1px solid var(--border); }
.bench-engine-item.is-online .bench-engine-state { color: var(--green); background: rgba(22,163,74,.09); border-color: rgba(22,163,74,.28); }
.bench-engine-item.is-offline .bench-engine-state { color: var(--red); background: rgba(220,38,38,.07); border-color: rgba(220,38,38,.24); }
.bench-engine-model { min-width: 0; }
.bench-model-picker { position: relative; min-width: 0; }
.bench-model-trigger {
width: 100%; min-height: 32px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 5px;
padding: 6px 8px; font-family: monospace; font-size: 12px; cursor: pointer; text-align: left;
}
.bench-model-trigger.open, .bench-model-trigger:hover { border-color: var(--accent); filter: none; }
.bench-model-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bench-model-menu {
position: absolute; z-index: 240; top: calc(100% + 4px); left: 0; right: 0;
background: var(--surface); border: 1px solid var(--border); border-radius: 7px; box-shadow: var(--shadow);
overflow: hidden; min-width: min(520px, 90vw);
}
.bench-model-menu[hidden] { display: none !important; }
.bench-model-search-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); color: var(--subtext); }
.bench-model-search { flex: 1; min-width: 0; border: none; outline: none; background: transparent; color: var(--text); font-size: 13px; }
.bench-model-options { max-height: 260px; overflow: auto; padding: 4px; }
.bench-model-option { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 9px; border: 0; border-radius: 5px; background: transparent; color: var(--text); font-family: monospace; font-size: 12px; cursor: pointer; text-align: left; }
.bench-model-option:hover, .bench-model-option.selected { background: var(--hover); filter: none; }
.bench-model-option.selected { color: var(--accent); font-weight: 700; }
.bench-model-empty { color: var(--subtext); font-size: 12px; padding: 12px; }
.bench-status { font-size: 13px; color: var(--subtext); }
.bench-summary { display: flex; gap: 10px 18px; flex-wrap: wrap; min-height: 20px; }
.bench-table td strong { display: block; }
.bench-table td small { display: block; color: var(--subtext); font-size: 11px; font-family: monospace; max-width: 280px; overflow: hidden; text-overflow: ellipsis; }
.bench-output { max-width: 680px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bench-device { display: inline-flex; align-items: center; padding: 2px 7px; border-radius: 999px; background: var(--panel); border: 1px solid var(--border); color: var(--subtext); font-size: 11px; font-weight: 700; }
.bench-device.gpu { color: var(--green); background: rgba(22,163,74,.09); border-color: rgba(22,163,74,.28); }
.bench-device.cpu { color: var(--yellow); background: rgba(217,119,6,.09); border-color: rgba(217,119,6,.28); }
.bench-device.cloud { color: var(--accent); background: rgba(37,99,235,.08); border-color: rgba(37,99,235,.24); }
.bench-inline-controls { display: flex; gap: 6px; min-width: min(620px, 100%); }
.bench-inline-controls input, .bench-inline-controls select { min-width: 0; }
.bench-turn-main .bench-turn-log { min-height: 440px; overflow-y: auto; padding: 16px; }
.bench-turn-log audio { width: min(520px, 100%); margin: 8px 0 0; }
@media (max-width: 900px) {
.bench-engine-item { grid-template-columns: auto minmax(0, 1fr); }
.bench-engine-state, .bench-engine-model { grid-column: 2; }
.bench-inline-controls { flex-wrap: wrap; min-width: 0; }
.bench-inline-controls input, .bench-inline-controls select, .bench-inline-controls .bvp-root { flex: 1 1 180px; }
}
@media (max-width: 560px) {
.bench-tab span:not(.mdi) { display: none; }
.bench-tab { padding: 9px 12px; }
}
/* ── Chunked TTS toggle ──────────────────────────────────────────────────── */
.chunk-toggle-label {
display: inline-flex; align-items: center; gap: 6px;
font-size: 13px; color: var(--subtext); cursor: pointer; user-select: none;
}
.chunk-toggle-label input { cursor: pointer; }
.chunk-progress {
font-size: 12px; color: var(--accent); padding: 6px 0 0;
display: flex; align-items: center; gap: 6px;
}
.chunk-progress::before { content: '⏳'; font-size: 13px; }
/* ── Effects panel ───────────────────────────────────────────────────────── */
.effects-preset-row {
display: flex; align-items: center; gap: 10px;
flex-wrap: wrap; margin-bottom: 16px;
}
.field-label-sm { font-size: 12px; font-weight: 600; color: var(--subtext); white-space: nowrap; }
.effects-grid { display: flex; flex-direction: column; gap: 14px; }
.fx-row { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.fx-toggle {
display: flex; align-items: center; gap: 6px;
font-size: 13px; font-weight: 600; color: var(--text);
min-width: 120px; flex-shrink: 0; cursor: pointer; user-select: none;
padding: 4px 0;
}
.fx-toggle input { cursor: pointer; }
.fx-sliders {
display: flex; flex-wrap: wrap; gap: 8px 20px; flex: 1; min-width: 0;
}
.fx-sliders label {
display: flex; align-items: center; gap: 8px;
font-size: 12px; color: var(--subtext); white-space: nowrap;
}
.fx-sliders input[type=range] { width: 110px; cursor: pointer; }
.fx-sliders span { font-size: 11px; color: var(--text); font-variant-numeric: tabular-nums; min-width: 44px; }
/* ── History panel ───────────────────────────────────────────────────────── */
.history-list { display: flex; flex-direction: column; gap: 8px; }
.history-empty { font-size: 13px; color: var(--subtext); padding: 12px 0; }
/* ── Voice Picker ───────────────────────────────────────────────────────── */
.vp-root { position: relative; display: inline-flex; flex-direction: column; min-width: 200px; flex: 1 1 200px; }
.vp-trigger {
display: flex; align-items: center; justify-content: space-between; gap: 8px;
padding: 0 10px; height: 34px; cursor: pointer;
background: var(--input-bg, var(--panel)); border: 1px solid var(--border);
border-radius: var(--radius, 8px); user-select: none;
transition: border-color .15s;
}
.vp-trigger:hover, .vp-trigger.open { border-color: var(--accent); }
.vp-trigger-content { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; overflow: hidden; }
.vp-trigger-name { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.vp-trigger-meta {
margin-left: auto; flex-shrink: 0; color: var(--subtext); font-size: 12px;
font-variant-numeric: tabular-nums; letter-spacing: 0;
}
.vp-trigger-placeholder { font-size: 13px; color: var(--subtext); }
.vp-chevron { font-size: 16px; color: var(--subtext); flex-shrink: 0; transition: transform .15s; }
.vp-trigger.open .vp-chevron { transform: rotate(180deg); }
.vp-avatar { flex-shrink: 0; }
.vp-flag { font-size: 13px; flex-shrink: 0; }
.vp-drop[hidden] { display: none !important; }
/* attachTextPicker's floating variant — appended to <body> and positioned in
JS (next to whatever text input it's browsing for), not inside a .vp-root. */
.vp-drop-floating { position: fixed; z-index: 2001; }
.route-output-wrap { position: relative; display: inline-flex; align-items: center; width: 100%; }
.route-output-wrap .route-output { flex: 1; min-width: 0; padding-right: 24px; }
.vp-text-browse {
position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
border: none; background: none; color: var(--subtext); cursor: pointer;
padding: 2px; line-height: 1; border-radius: 4px;
}
.vp-text-browse:hover { color: var(--accent); background: var(--panel); }
.vp-drop {
position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 200;
background: var(--card-bg, var(--panel)); border: 1px solid var(--border);
border-radius: var(--radius, 8px); box-shadow: 0 8px 24px rgba(0,0,0,.18);
display: flex; flex-direction: column; max-height: 320px; overflow: hidden;
}
.vp-search-wrap { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.vp-search-icon { color: var(--subtext); font-size: 15px; }
.vp-search { flex: 1; background: none; border: none; outline: none; font-size: 13px; color: var(--text); }
.vp-list { overflow-y: auto; flex: 1; padding: 4px 0; }
.vp-item {
display: flex; align-items: center; gap: 8px;
padding: 6px 12px; cursor: pointer; font-size: 13px; color: var(--text);
}
.vp-item:hover, .vp-item:focus { background: rgba(37,99,235,.08); outline: none; }
.vp-item.selected { background: rgba(37,99,235,.13); font-weight: 600; }
.vp-item-name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.vp-item-meta {
margin-left: auto; flex: 0 0 auto; min-width: 42px; text-align: right;
color: var(--subtext); font-size: 12px; font-weight: 600; letter-spacing: 0;
font-variant-numeric: tabular-nums;
}
.vp-empty { padding: 12px; text-align: center; font-size: 12px; color: var(--subtext); }
/* ── Generation History ─────────────────────────────────────────────────── */
.hist-avatar {
width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
}
.hist-avatar-init {
display: inline-flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 700; color: #fff;
}
.hist-del-btn {
margin-left: auto; background: none; border: none; cursor: pointer;
color: var(--subtext); font-size: 14px; padding: 2px 4px; border-radius: 4px;
display: flex; align-items: center; opacity: .6; transition: opacity .15s, color .15s;
}
.hist-del-btn:hover { opacity: 1; color: var(--red, #ef4444); }
.history-item {
background: var(--panel); border: 1px solid var(--border);
border-radius: var(--radius); padding: 10px 12px;
display: flex; flex-direction: column; gap: 5px;
transition: border-color .15s;
}
.history-item:hover { border-color: rgba(37,99,235,.3); }
.history-item-row1 { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }
.history-voice {
font-size: 12px; font-weight: 700; color: var(--accent);
background: rgba(37,99,235,.07); border: 1px solid rgba(37,99,235,.2);
border-radius: 4px; padding: 1px 7px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px;
}
.history-backend { font-size: 11px; color: var(--subtext); white-space: nowrap; }
.history-time { font-size: 11px; color: var(--subtext); font-variant-numeric: tabular-nums; white-space: nowrap; }
.history-item-text { font-size: 12px; color: var(--text); line-height: 1.4; }
.history-item-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.btn-xs {
font-size: 11px; padding: 3px 9px; border-radius: 5px;
}
/* ── Playlist panel ──────────────────────────────────────────────────────── */
.playlist-list { display: flex; flex-direction: column; gap: 6px; }
.playlist-item {
display: flex; align-items: center; gap: 10px;
background: var(--panel); border: 1px solid var(--border);
border-radius: var(--radius); padding: 8px 12px;
transition: border-color .15s;
}
.playlist-item:hover { border-color: rgba(37,99,235,.3); }
.playlist-num {
font-size: 12px; font-weight: 700; color: var(--subtext);
min-width: 18px; text-align: center;
}
.playlist-info { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.playlist-text { font-size: 12px; color: var(--subtext); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.playlist-item-actions { display: flex; gap: 4px; flex-shrink: 0; }
/* ── Refine panel ────────────────────────────────────────────────────────── */
.refine-config {
display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-start;
margin-bottom: 14px;
}
.refine-toggles {
display: flex; flex-wrap: wrap; gap: 8px 20px; margin-bottom: 4px;
}
.refine-toggle {
display: inline-flex; align-items: center; gap: 6px;
font-size: 13px; color: var(--text); cursor: pointer; user-select: none;
}
.refine-toggle input { cursor: pointer; }
/* ── Persona inspector panel ─────────────────────────────────────────────── */
.insp-persona-panel {
background: var(--panel); border: 1px solid var(--border);
border-radius: var(--radius); padding: 14px 16px;
margin: 12px 0; display: flex; flex-direction: column; gap: 10px;
}
.insp-persona-head { display: flex; flex-direction: column; gap: 3px; }
.insp-persona-title { font-size: 13px; font-weight: 700; color: var(--text); }
.insp-persona-hint { font-size: 11px; color: var(--subtext); line-height: 1.4; }
.insp-persona-input {
width: 100%; font-size: 13px; padding: 8px 10px;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text);
font-family: var(--font); resize: vertical; min-height: 72px;
transition: border-color .15s;
}
.insp-persona-input:focus { border-color: var(--accent); outline: none; }
.insp-persona-actions { display: flex; align-items: center; gap: 10px; }
.insp-persona-status { font-size: 11px; color: var(--green); }
/* ── Preview persona button ──────────────────────────────────────────────── */
.preview-persona-btn {
font-size: 12px; padding: 4px 11px;
border: 1px solid var(--teal); color: var(--teal);
background: rgba(13,148,136,.06); border-radius: 5px;
cursor: pointer; font-family: var(--font); transition: background .15s;
}
.preview-persona-btn:hover { background: rgba(13,148,136,.12); }
.preview-persona-btn:disabled { opacity: .5; cursor: default; }
/* ── Seed Finder ─────────────────────────────────────────────────────────── */
.seed-finder-group { margin-top: 12px; }
.seed-finder-body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 12px; }
.seed-finder-config { display: flex; flex-direction: column; gap: 10px; }
.seed-finder-row { display: flex; flex-direction: column; gap: 5px; }
.seed-finder-label { font-size: 12px; font-weight: 600; color: var(--subtext); }
.seed-finder-text {
width: 100%; font-size: 13px; padding: 8px 10px;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text);
font-family: var(--font); resize: vertical; min-height: 68px;
transition: border-color .15s;
}
.seed-finder-text:focus { border-color: var(--accent); outline: none; }
.seed-finder-params { flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: 14px; }
.seed-finder-field { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text); }
.seed-finder-field input[type="number"] {
width: 64px; padding: 5px 7px; font-size: 13px;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text); text-align: center;
}
.seed-finder-field select {
padding: 5px 8px; font-size: 13px;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text);
}
.seed-finder-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.seed-finder-status { font-size: 12px; color: var(--subtext); }
.seed-finder-pin { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--border); }
.seed-finder-pin-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.seed-finder-pin-input { width: 90px; padding: 5px 8px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--text); font-family: var(--font); }
.seed-finder-pin-status { font-size: 12px; color: var(--accent); font-weight: 600; }
.seed-finder-progress { display: flex; flex-direction: column; gap: 6px; }
.seed-finder-progress-head { display: flex; justify-content: space-between; font-size: 12px; color: var(--subtext); }
.seed-finder-bar { height: 100%; background: var(--accent); transition: width .2s ease; border-radius: 999px; }
.seed-finder-results { display: flex; flex-direction: column; gap: 6px; }
.seed-finder-result-row {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding: 7px 10px; border-radius: var(--radius);
border: 1px solid var(--border); background: var(--surface);
font-size: 13px;
}
.seed-finder-result-row.sfr-active { border-color: var(--accent); background: rgba(var(--accent-rgb, 124,77,255),.07); }
.seed-finder-result-row.seed-finder-result-error { opacity: .6; }
.sfr-seed { font-weight: 700; min-width: 58px; color: var(--text); }
.sfr-dur { color: var(--subtext); font-size: 12px; min-width: 170px; flex: 1 1 210px; }
.sfr-play-btn { font-size: 12px; padding: 4px 10px; }
.sfr-use-btn { font-size: 12px; padding: 4px 10px; }
.sfr-saved { font-size: 12px; color: var(--green); font-weight: 600; }
.sfr-error { font-size: 12px; color: var(--red); }
.sfr-batch-header {
font-size: 12px; color: var(--subtext); font-style: italic;
padding: 4px 2px 2px;
}
.sfr-batch-tag { color: var(--accent); font-style: italic; }
.seed-finder-result-row.sfr-batch { background: rgba(var(--accent-rgb, 124,77,255),.03); }
/* ── Conversation Playground ─────────────────────────────────────────────── */
.conv-config-bar { padding: 14px 18px 10px; margin-bottom: 0; }
/* Conversation: stack STT · LLM · TTS · System prompt full-width, one per row */
.conv-config-bar .engine-setup-row { flex-direction: column; flex-wrap: nowrap; gap: 12px; }
.conv-config-bar .engine-setup-col {
flex: 1 1 auto; width: 100%; min-width: 0;
border-right: none; padding-right: 0;
border-bottom: 1px solid var(--border); padding-bottom: 12px;
}
.conv-config-bar .engine-setup-col:last-child { border-bottom: none; padding-bottom: 0; }
.conv-config-bar .conv-prompt-row { margin-top: 12px; }
.conv-config-bar .conv-system-textarea { width: 100%; }
/* ── Unified Engine Config Rows (used across tools) ───────────────── */
.engine-setup-row {
display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-start;
margin-bottom: 16px; padding: 12px 14px; background: rgba(0,0,0,0.02);
border: 1px solid var(--border); border-radius: 8px;
}
.engine-setup-col {
flex: 1; min-width: 220px; display: flex; flex-direction: column; gap: 6px;
border-right: 1px solid var(--border); padding-right: 16px;
}
.engine-setup-col:last-child, .engine-setup-col.no-border {
border-right: none; padding-right: 0;
}
.engine-setup-label {
font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--subtext);
display: flex; align-items: center; gap: 6px; margin-bottom: 2px;
}
.engine-setup-label .mdi { font-size: 14px; }
.engine-setup-link {
color: var(--subtext); opacity: 0.6; transition: opacity 0.15s, color 0.15s;
margin-left: auto; /* Push gear to the right */
}
.engine-setup-link:hover { opacity: 1; color: var(--accent); }
.engine-setup-controls {
display: flex; gap: 6px; align-items: center; width: 100%; flex-wrap: wrap;
}
.engine-setup-controls select, .engine-setup-controls input[type="text"] {
flex: 1; min-width: 0;
background: var(--bg); border: 1px solid var(--border); color: var(--text);
border-radius: var(--radius); padding: 8px 12px; font-size: 14px;
}
.conv-config-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end; }
.conv-config-group { display: flex; flex-direction: column; gap: 4px; }
.conv-config-group--actions { margin-left: auto; }
.conv-cfg-label { font-size: 11px; font-weight: 700; color: var(--subtext); text-transform: uppercase; letter-spacing: .06em; }
.conv-url-inp { width: 220px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius); font-size: 13px; background: var(--surface); color: var(--text); }
.conv-prompt-row { display: flex; align-items: flex-start; gap: 10px; margin-top: 10px; border-top: 1px solid var(--border); padding-top: 10px; }
.conv-prompt-row .conv-cfg-label { padding-top: 7px; white-space: nowrap; }
.conv-system-textarea { flex: 1; resize: vertical; min-height: 34px; max-height: 120px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius); font-size: 13px; font-family: var(--font); background: var(--surface); color: var(--text); }
/* Layout */
.conv-main { display: flex; gap: 14px; margin-top: 14px; }
/* Chat panel grows to fill remaining height; input bar stays pinned at bottom */
.conv-chat-panel {
flex: 1; display: flex; flex-direction: column; gap: 0; min-width: 0;
height: calc(100vh - 340px); min-height: 440px;
}
/* Collapsible engine/prompt config */
.conv-config-toggle {
display: flex; align-items: center; gap: 8px; cursor: pointer;
font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
color: var(--subtext); user-select: none; padding-bottom: 2px;
}
.conv-config-toggle:hover { color: var(--text); }
.conv-config-toggle .conv-config-chevron { margin-left: auto; transition: transform .18s ease; font-size: 18px; }
.conv-config-summary { font-weight: 500; text-transform: none; letter-spacing: 0; opacity: .8; font-size: 11.5px; }
.conv-config-body { margin-top: 10px; }
.conv-config-bar.collapsed .conv-config-body { display: none; }
.conv-config-bar.collapsed .conv-config-chevron { transform: rotate(180deg); }
.conv-config-bar.collapsed .conv-config-summary { display: inline; }
.conv-config-bar:not(.collapsed) .conv-config-summary { display: none; }
/* Desktop: make the Conversation fill the viewport height — no page scroll;
only the chat window scrolls internally. Collapsing the config frees space. */
@media (min-width: 768px) {
#s-conversation.is-active { display: flex; flex-direction: column; height: 100%; min-height: 0; }
#s-conversation .conv-main { flex: 1; min-height: 0; margin-top: 12px; }
#s-conversation .conv-chat-panel { height: auto; min-height: 0; }
#s-conversation .conv-stats-panel { overflow-y: auto; }
}
/* Read Aloud — fit the document area into the viewport height so the transport
+ synthesise bar below it stay visible (only the document scrolls). */
@media (min-width: 768px) {
#s-reader.is-active, #s-caststudio.is-active { display: flex; flex-direction: column; height: 100%; min-height: 0; }
#s-caststudio #tab-caststudio { flex: 1; min-height: 0; display: flex !important; flex-direction: column; }
#s-caststudio #stu-phase-2:not([hidden]) { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#s-caststudio #stu-cast-slot:not([hidden]),
#s-caststudio #stu-castchars-slot:not([hidden]) { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#s-reader #tab-reader { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#s-caststudio #tab-reader { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#s-reader #reader-main-view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#s-caststudio #reader-main-view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#s-reader #reader-main-view[hidden] { display: none; }
#s-caststudio #reader-main-view[hidden] { display: none; }
#s-reader #reader-doc { flex: 1; min-height: 0; overflow-y: auto; }
#s-caststudio #reader-doc { flex: 1; min-height: 0; overflow-y: auto; }
}
.conv-stats-panel { width: 280px; flex-shrink: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; display: flex; flex-direction: column; gap: 8px; }
/* Chat window fills the space above the input bar; warning box scrolls inside it */
.conv-chat-window { flex: 1; min-height: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0; padding: 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.conv-chat-welcome { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; flex: 1; color: var(--subtext); text-align: center; }
/* Bubbles */
.conv-bubble-wrap { display: flex; flex-direction: column; max-width: 72%; }
.conv-bubble-wrap--user { align-self: flex-end; align-items: flex-end; }
.conv-bubble-wrap--assistant { align-self: flex-start; align-items: flex-start; }
.conv-bubble { padding: 10px 14px; border-radius: 16px; font-size: 14.5px; line-height: 1.55; word-break: break-word; }
.conv-bubble--user { background: var(--accent); color: #fff; border-bottom-right-radius: 4px; }
.conv-bubble--assistant { background: var(--panel); color: var(--text); border: 1px solid var(--border); border-bottom-left-radius: 4px; }
.conv-bubble--error { background: rgba(220,38,38,.08); color: var(--red); border: 1px solid rgba(220,38,38,.2); border-radius: 10px; padding: 8px 12px; font-size: 13px; }
.conv-bubble-meta { font-size: 11px; color: var(--subtext); margin-top: 3px; padding: 0 4px; }
/* Typing dots */
.conv-typing { display: inline-flex; gap: 4px; align-items: center; padding: 4px 2px; }
.conv-typing span { width: 7px; height: 7px; border-radius: 50%; background: var(--subtext); opacity: .4; animation: convDot 1.2s infinite; }
.conv-typing span:nth-child(2) { animation-delay: .2s; }
.conv-typing span:nth-child(3) { animation-delay: .4s; }
@keyframes convDot { 0%,80%,100% { transform: scale(.7); opacity:.3; } 40% { transform: scale(1); opacity:.9; } }
/* ── Collapsible "thinking" (reasoning) panel inside an assistant bubble ── */
.conv-think-wrap { border: 1px solid var(--border); border-radius: 10px; margin-bottom: 8px; background: var(--surface); overflow: hidden; }
.conv-think-toggle {
width: 100%; display: flex; align-items: center; gap: 6px; padding: 7px 10px;
background: none; border: none; cursor: pointer; font-family: inherit;
font-size: 12.5px; font-weight: 600; color: var(--subtext); text-align: left;
}
.conv-think-toggle:hover { color: var(--text); }
.conv-think-toggle .mdi { transition: transform .15s; font-size: 15px; }
.conv-think-toggle[aria-expanded="true"] .mdi { transform: rotate(90deg); }
.conv-think-body {
padding: 0 12px 10px; font-size: 12.5px; line-height: 1.5; color: var(--subtext);
max-height: 220px; overflow-y: auto; white-space: pre-wrap; word-break: break-word;
}
.conv-answer-text { white-space: pre-wrap; word-break: break-word; }
/* ── Conversation input bar (text field + send + mic) ───────────────────── */
.conv-input-bar {
background: var(--surface); border: 1px solid var(--border); border-top: none;
border-radius: 0 0 var(--radius) var(--radius); padding: 10px 16px 12px;
display: flex; flex-direction: column; gap: 8px;
}
.conv-mic-status { font-size: 13px; color: var(--subtext); min-height: 18px; }
.conv-text-row { display: flex; align-items: center; gap: 8px; }
.conv-text-inp {
flex: 1; min-width: 0; padding: 10px 14px; font-size: 14px; font-family: inherit;
border: 1.5px solid var(--border); border-radius: 22px;
background: var(--panel); color: var(--text); outline: none;
transition: border-color .15s;
}
.conv-text-inp:focus { border-color: var(--accent); }
.conv-text-inp::placeholder { color: var(--subtext); opacity: .7; }
.conv-send-btn {
flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%;
border: none; background: var(--accent); color: #fff;
font-size: 17px; cursor: pointer; display: flex; align-items: center;
justify-content: center; transition: background .15s, transform .1s;
}
.conv-send-btn:hover:not(:disabled) { background: #1d4ed8; transform: scale(1.05); }
.conv-send-btn:disabled { opacity: .4; cursor: default; }
.conv-divider { width: 1px; height: 32px; background: var(--border); flex-shrink: 0; }
.conv-mic-btn {
flex-shrink: 0; width: 52px; height: 52px; border-radius: 50%;
border: 2px solid var(--accent); background: var(--accent); color: #fff;
font-size: 22px; cursor: pointer; display: flex; align-items: center;
justify-content: center; transition: background .15s, transform .1s, box-shadow .15s;
}
.conv-mic-btn:hover { background: #1d4ed8; }
.conv-mic-btn.live { background: var(--accent); border-color: var(--accent); box-shadow: 0 0 0 4px rgba(37,99,235,.16); }
.conv-mic-btn.live:not(.processing) { animation: convPulse 1.4s infinite; }
.conv-mic-btn.recording:not(.live) { background: var(--red); border-color: var(--red); animation: convPulse 1s infinite; }
.conv-mic-btn.processing { background: var(--yellow); border-color: var(--yellow); cursor: pointer; }
.conv-mic-btn.processing.live { background: var(--accent); border-color: var(--accent); }
@keyframes convPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(220,38,38,.4); } 50% { box-shadow: 0 0 0 8px rgba(220,38,38,0); } }
.conv-mic-timer { font-size: 13px; font-variant-numeric: tabular-nums; color: var(--red); min-width: 36px; text-align: right; }
.conv-vad-label { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--subtext); cursor: pointer; white-space: nowrap; user-select: none; }
.conv-vad-label input { cursor: pointer; accent-color: var(--accent); }
/* Noise gate row — grouped with the mic controls, not a full-width row */
.conv-gate-row { display: flex; align-items: center; gap: 6px; flex-shrink: 0; width: 96px; }
.conv-gate-label { font-size: 13px; color: var(--subtext); flex-shrink: 0; line-height: 1; }
.conv-gate-slider { flex: 1; min-width: 0; height: 3px; cursor: pointer; accent-color: var(--accent); }
.conv-level-wrap { position: relative; flex: 1; min-width: 0; height: 6px; background: var(--panel); border-radius: 3px; margin: 0; overflow: visible; display: none; }
.conv-level-wrap.active { display: block; }
.conv-level-fill { height: 100%; background: var(--red); border-radius: 3px; width: 0%; transition: width .07s linear; }
.conv-level-gate { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--accent); border-radius: 1px; pointer-events: none; }
.conv-text-inp.listening { border-color: var(--red); font-style: italic; color: var(--subtext); }
/* Stats panel collapsible */
.conv-stats-toggle-row { display: flex; align-items: center; justify-content: space-between; }
.conv-stats-collapse-btn { background: none; border: none; cursor: pointer; color: var(--subtext); font-size: 16px; line-height: 1; padding: 2px; border-radius: 4px; }
.conv-stats-collapse-btn:hover { color: var(--text); background: var(--panel); }
.conv-stats-panel.collapsed { width: 0 !important; padding: 0; overflow: hidden; border: none; min-width: 0; }
.conv-stats-expand-btn {
align-items: center; justify-content: center;
width: 32px; height: 32px; border-radius: 50%; background: var(--surface);
border: 1px solid var(--border); cursor: pointer; color: var(--subtext); font-size: 16px;
flex-shrink: 0; align-self: flex-start; margin-top: 4px;
}
.conv-stats-expand-btn:hover { color: var(--text); background: var(--panel); }
/* Stats panel */
.conv-stats-head { font-size: 10px; font-weight: 800; color: var(--subtext); text-transform: uppercase; letter-spacing: .08em; }
.conv-pipeline { display: flex; flex-direction: column; gap: 8px; }
.conv-pipe-step { display: grid; grid-template-columns: 1fr auto; grid-template-rows: auto auto; gap: 2px 8px; }
.conv-pipe-label { grid-column: 1; font-size: 12px; color: var(--subtext); }
.conv-pipe-val { grid-column: 2; grid-row: 1 / 3; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); align-self: center; text-align: right; min-width: 52px; }
.conv-pipe-bar { grid-column: 1; height: 4px; background: var(--panel); border-radius: 2px; overflow: hidden; }
.conv-pipe-fill { height: 100%; background: var(--teal); border-radius: 2px; width: 0%; transition: width .4s ease; }
.conv-pipe-total .conv-pipe-label { font-weight: 700; color: var(--text); }
.conv-pipe-total .conv-pipe-val { color: var(--accent); font-size: 15px; }
/* Turn history */
.conv-turn-history { display: flex; flex-direction: column; gap: 5px; overflow-y: auto; max-height: 220px; }
.conv-history-empty { font-size: 12px; color: var(--subtext); font-style: italic; }
.conv-hist-item { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 4px 6px; border-radius: 5px; background: var(--panel); }
.conv-hist-num { font-weight: 700; color: var(--subtext); min-width: 20px; }
.conv-hist-time { font-variant-numeric: tabular-nums; font-weight: 700; margin-left: auto; }
.conv-hist-ok { color: var(--green); }
.conv-hist-err { color: var(--red); }
/* ── Character library section ─────────────────────────────────────────── */
.cl-toolbar { margin-bottom: 14px; }
.cl-tool-field { display: flex; flex-direction: column; gap: 4px; }
.cl-tool-label { font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--subtext); }
.cl-tool-field select, .cl-tool-field input { padding: 7px 10px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text); font-size: 13px; }
.cl-grid { display: flex; flex-direction: column; gap: 20px; }
.cl-book-group { }
.cl-book-head { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 14px; padding: 4px 0 10px; border-bottom: 2px solid var(--border); margin-bottom: 12px; }
.cl-book-head .mdi { color: var(--accent); }
.cl-book-count { margin-left: 6px; font-size: 11px; font-weight: 700; color: var(--subtext); border: 1px solid var(--border); border-radius: 20px; padding: 1px 8px; }
.cl-book-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(430px, 1fr));
gap: 18px;
align-items: start;
}
.cl-card-wrap { position: relative; min-width: 0; }
.cl-card-tools { position: absolute; top: 8px; right: 8px; display: flex; gap: 4px; z-index: 2; opacity: 0; transition: opacity .15s; }
.cl-card-wrap:hover .cl-card-tools { opacity: 1; }
.cl-card-tools .btn-sm { font-size: 11px; padding: 2px 7px; }
.cl-empty { text-align: center; padding: 60px 20px; color: var(--subtext); }
.cl-empty p { margin: 8px 0 0; }
.cl-empty-hint { font-size: 12.5px; }
.cl-edit-box { max-width: 620px; width: 92vw; }
.cl-edit-body { display: flex; flex-direction: column; gap: 10px; max-height: 70vh; overflow-y: auto; padding: 4px 2px; }
.cl-edit-row { display: flex; flex-direction: column; gap: 3px; }
.cl-edit-row > span { font-size: 11px; font-weight: 700; color: var(--subtext); }
.cl-edit-row input, .cl-edit-row textarea, .cl-edit-row select { padding: 7px 9px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text); font-size: 13px; font-family: inherit; resize: vertical; }
/* ── Recast unknown: gap between non-contiguous passages ───────────────── */
.ab-cv-divider { text-align: center; color: var(--subtext); font-size: 20px; letter-spacing: .35em; line-height: 1; padding: 10px 0 6px; opacity: .55; user-select: none; }
.ab-cv-divider-expand { cursor: pointer; font-size: 14px; letter-spacing: normal; transition: opacity .15s; }
.ab-cv-divider-expand:hover { opacity: .9; color: var(--accent); }
.ab-cv-divider-hint { font-size: 11px; font-weight: 500; text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 2px; vertical-align: middle; }
.ab-cv-ctx-row { opacity: .7; background: color-mix(in srgb, var(--panel) 60%, transparent); border-left: 2px solid var(--border); }
.reader-synth-prog { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }
.reader-synth-track { width: 130px; height: 38px; border-radius: 4px; background: var(--panel); overflow: hidden; }
.reader-synth-fill { height: 100%; width: 0; background: rgba(234,179,8,.9); transition: width .15s; }
.reader-synth-label { font-size: 12px; color: var(--subtext); min-width: 52px; }
/* Select mode: clickable sentences (pointer, not crosshair — it's click-to-pick) */
.reader-doc.reader-selecting { box-shadow: inset 0 0 0 2px var(--accent); }
.reader-doc.reader-selecting .reader-stat { pointer-events: auto; cursor: pointer; }
.reader-doc.reader-selecting .reader-stat:hover { background: rgba(37,99,235,.16); outline: 1px dashed rgba(37,99,235,.5); }
.reader-doc.reader-selecting .reader-word { cursor: pointer; }
.reader-doc.reader-selecting .reader-word:hover { background: rgba(37,99,235,.18); }
/* committed range */
.reader-stat.sel { outline: 2px solid var(--accent); outline-offset: 0; background: rgba(37,99,235,.10); }
.reader-word.in-sel { box-shadow: inset 0 -2px 0 var(--accent); }
/* the start "anchor" pulses while waiting for the end click */
.reader-stat.sel-anchor { outline: 2px solid var(--accent); background: rgba(37,99,235,.20); animation: readerAnchorPulse 1s ease-in-out infinite; }
.reader-word.sel-anchor { box-shadow: inset 0 -2px 0 var(--accent); background: rgba(37,99,235,.22); animation: readerAnchorPulse 1s ease-in-out infinite; }
@keyframes readerAnchorPulse { 0%,100% { opacity: 1; } 50% { opacity: .45; } }
/* Zoom toolbar + status legend */
.reader-toolbar {
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;
margin-top: 10px; padding: 8px 12px; background: var(--surface);
border: 1px solid var(--border); border-radius: var(--radius);
}
.reader-zoom { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.reader-zoom-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }
.reader-zoom-pct { font-size: 12px; font-weight: 700; min-width: 44px; text-align: center; color: var(--subtext); }
/* PDF Search */
.reader-search-wrap { display: flex; align-items: center; gap: 5px; }
.reader-search-icon { font-size: 14px; color: var(--subtext); }
.reader-search-inp {
width: 160px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 20px;
background: var(--panel); color: var(--text); font-size: 13px; outline: none;
transition: border-color .15s, width .2s;
}
.reader-search-inp:focus { border-color: var(--accent); width: 220px; }
.reader-search-status { font-size: 11px; color: var(--subtext); white-space: nowrap; min-width: 32px; }
.reader-search-btn {
width: 24px;
height: 24px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: 5px;
background: transparent;
color: var(--subtext);
cursor: pointer;
padding: 0;
}
.reader-search-btn:hover { background: var(--panel); color: var(--accent); }
.reader-search-btn .mdi { font-size: 17px; }
.reader-legend { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 11px; color: var(--subtext); }
.reader-leg { display: inline-flex; align-items: center; gap: 5px; }
.reader-leg::before { content: ''; width: 11px; height: 11px; border-radius: 3px; }
.reader-leg-pending::before { background: rgba(239,68,68,.45); }
.reader-leg-synth::before { background: rgba(234,179,8,.65); }
.reader-leg-ready::before { background: rgba(34,197,94,.55); }
.reader-leg-reading::before { background: rgba(37,99,235,.6); }
.reader-doc {
margin-top: 14px; max-height: 72vh; overflow-y: auto; overflow-x: auto;
background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
padding: 16px; display: flex; flex-direction: column; gap: 16px;
}
.reader-doc:empty { display: none; }
.reader-parsing { display: flex; align-items: center; gap: 10px; padding: 24px; color: var(--subtext); font-size: 13px; margin: 0 auto; }
.reader-doc.two-page { flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: flex-start; }
.reader-page {
position: relative; flex: 0 0 auto; margin: 0 auto;
box-shadow: 0 2px 10px rgba(0,0,0,.12); background: #fff;
contain: layout paint style;
content-visibility: auto;
contain-intrinsic-size: auto 1100px;
}
.reader-canvas { display: block; }
.reader-overlay { position: absolute; inset: 0; pointer-events: none; }
.reader-hl-word {
position: absolute; border-radius: 3px; background: rgba(37,99,235,.30); z-index: 3;
box-shadow: 0 0 0 1.5px rgba(37,99,235,.75); transition: left .12s, top .12s, width .12s, height .12s;
}
.reader-search-hit {
position: absolute;
z-index: 2;
border-radius: 2px;
background: rgba(250, 204, 21, .35);
box-shadow: 0 0 0 1px rgba(202, 138, 4, .25);
pointer-events: none;
}
.reader-search-hit.search-current {
z-index: 4;
background: rgba(250, 204, 21, .72);
box-shadow: 0 0 0 2px rgba(202, 138, 4, .85);
}
.reader-word.search-hit { background: rgba(250, 204, 21, .35); border-radius: 3px; }
.reader-word.search-current {
background: rgba(250, 204, 21, .75);
box-shadow: 0 0 0 2px rgba(202, 138, 4, .8);
}
/* Per-sentence synthesis-state overlay (PDF) — the "not synthesised" tint stays
invisible until synthesis actually starts (button, play, or a restored doc
with saved audio); otherwise a freshly-imported book reads as wall-to-wall red. */
.reader-stat { position: absolute; border-radius: 3px; z-index: 1; transition: background .2s; }
.reader-stat-pending { background: transparent; }
.reader-doc.reader-synth-started .reader-stat-pending { background: rgba(239,68,68,.12); }
.reader-stat-synth { background: rgba(234,179,8,.30); }
.reader-stat-ready { background: rgba(34,197,94,.18); }
.reader-stat-reading { background: rgba(37,99,235,.20); z-index: 2; }
.reader-text {
max-width: 760px; background: var(--surface); color: var(--text);
border: 1px solid var(--border); border-radius: var(--radius);
padding: 28px 34px; line-height: 1.85; font-size: 17px;
}
.reader-text-para { margin: 0 0 1em; }
.reader-word { border-radius: 3px; padding: 0 1px; cursor: pointer; transition: background .12s; }
/* Per-sentence synthesis-state tint (text) */
.reader-word.stat-pending { background: transparent; }
.reader-doc.reader-synth-started .reader-word.stat-pending { background: rgba(239,68,68,.09); }
.reader-word.stat-synth { background: rgba(234,179,8,.22); }
.reader-word.stat-ready { background: rgba(34,197,94,.14); }
.reader-word.stat-reading { background: rgba(37,99,235,.15); }
.reader-word.is-word { background: rgba(37,99,235,.42) !important; box-shadow: 0 0 0 1px rgba(37,99,235,.6); }
/* ── Fish Audio inline emotion-tag reference (Try It Out) ─────────────────── */
/* Uses the app's real theme tokens (--surface/--panel/--border/--text), not
hardcoded colours, so the panel follows both the light and dark themes. */
.fish-tags-panel {
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 10px 12px;
background: var(--panel);
}
.fish-tags-head { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--text); }
.fish-tags-group { margin-top: 10px; }
.fish-tags-group-title { font-size: 12px; font-weight: 600; color: var(--subtext); margin-bottom: 6px; }
.fish-tags-grid { display: flex; flex-wrap: wrap; gap: 6px; }
.fish-tag {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
padding: 3px 8px;
border-radius: 5px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
cursor: pointer;
transition: background .12s, border-color .12s, color .12s;
}
.fish-tag:hover { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.fish-tag:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Quotation-mark visibility toggle in the casting view */
.ab-cv-quote-toggle.is-on { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
/* Quotation marks are wrapped in .ab-q so the toggle is a pure CSS flip */
body.ab-hide-quotes .ab-q { display: none; }
.lcd-book-context {
display: flex;
align-items: center;
gap: 12px;
margin: 0 0 12px;
padding: 10px 14px;
border: 1px solid #d9e2f0;
border-left: 4px solid #2563eb;
border-radius: 8px;
background: #f7faff;
color: #334155;
font-size: 12px;
}
.lcd-book-context-text { flex: 1; line-height: 1.45; }
.ab-book-context-banner {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 14px;
border-bottom: 1px solid var(--border);
background: color-mix(in srgb, var(--primary) 7%, var(--surface));
}
.ab-book-context-copy { display: flex; align-items: baseline; gap: 8px; flex: 1; flex-wrap: wrap; font-size: 12px; }
.ab-book-context-copy > span:last-child { color: var(--subtext); line-height: 1.4; }
@media (max-width: 700px) { .ab-book-context-banner { align-items: flex-start; flex-direction: column; } }
/* ── Consistent-image generation status panel ────────────────────────────────
Live progress for the "Consistent profile + reference" render, which can
legitimately run 10-20+ minutes on a local GPU. A non-blocking corner panel
(not a modal) so the user can keep working while it shows elapsed time and
flags when the backend has gone quiet for too long. */
.cij-progress-panel {
position: fixed; right: 20px; bottom: 20px; z-index: 10000;
background: var(--surface); color: var(--text); border: 1px solid var(--border);
border-radius: 8px; padding: 10px 14px; min-width: 260px; max-width: 340px;
box-shadow: 0 6px 24px rgba(0,0,0,0.35); font-size: 0.85em;
}
.cij-progress-head { display: flex; align-items: center; gap: 6px; font-weight: 700; margin-bottom: 8px; }
.cij-progress-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cij-progress-close { background: none; border: none; cursor: pointer; color: inherit; opacity: 0.7; padding: 2px; }
.cij-progress-close:hover { opacity: 1; }
.cij-progress-steps { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.cij-step { display: flex; align-items: center; gap: 6px; opacity: 0.5; }
.cij-step.is-active, .cij-step.is-done { opacity: 1; }
.cij-step-icon { font-size: 1.1em; }
.cij-step.is-done .cij-step-icon { color: #4caf50; }
.cij-step.is-active .cij-step-icon { color: var(--primary, #4a90d9); }
.cij-progress-detail { opacity: 0.85; margin-bottom: 4px; }
.cij-progress-elapsed { font-variant-numeric: tabular-nums; opacity: 0.7; }
.cij-progress-panel.cij-progress-warn .cij-progress-elapsed { color: #e0a030; opacity: 1; }
.cij-progress-panel.cij-progress-ok { border-color: #4caf50; }
.cij-progress-panel.cij-progress-err { border-color: #e05a4e; }
/* ── Attribution confidence: colour-coded certainty + review navigation ──────
Green >=80 is measured at ~95% correct, orange 50-79 at ~77%, red <50 at
~54%. Reviewing only orange+red covers ~90% of real errors while reading
just over half the book, which is the entire point of showing this. */
.ab-cv-conf {
flex: 0 0 auto;
align-self: flex-start;
min-width: 92px;
margin-right: 6px;
padding: 1px 5px;
border-radius: 999px;
font-size: 10px;
font-weight: 700;
font-variant-numeric: tabular-nums;
text-align: center;
line-height: 1.5;
cursor: help;
border: 1px solid transparent;
}
.ab-conf-green { background: rgba(34,160,90,.14); color: #1f8a4c; border-color: rgba(34,160,90,.35); }
.ab-conf-orange { background: rgba(217,138,10,.16); color: #b3760a; border-color: rgba(217,138,10,.4); }
.ab-conf-red { background: rgba(206,60,55,.14); color: #c0392b; border-color: rgba(206,60,55,.38); }
@media (prefers-color-scheme: dark) {
.ab-conf-green { color: #56d98b; }
.ab-conf-orange { color: #f0b44a; }
.ab-conf-red { color: #ff8178; }
}
.ab-review-ctl {
display: flex;
align-items: center;
gap: 4px;
margin-left: 6px;
}
.ab-review-ctl select {
font-size: 11px; padding: 2px 4px; border-radius: 4px;
border: 1px solid var(--border); background: var(--surface); color: var(--text); outline: none;
}
/* The jump button carries a count, so it is wider than the icon-only nav
buttons it sits beside and needs its own padding rather than the square
.ab-page-nav-btn box. */
.ab-review-ctl .ab-review-jump {
/* A read-out, not a control — the chevrons either side do the navigating. */
cursor: default;
user-select: none;
padding: 0 6px;
gap: 4px;
display: inline-flex;
align-items: center;
white-space: nowrap;
font-size: 11px;
font-weight: 600;
color: #b3760a;
}
@media (prefers-color-scheme: dark) { .ab-review-ctl .ab-review-jump { color: #f0b44a; } }
/* The row the reviewer was just sent to — must stand out from the character
highlight, which uses a left border, so this uses a full-row wash. */
.ab-cv-row.ab-review-focus {
background: rgba(217,138,10,.13);
outline: 2px solid rgba(217,138,10,.5);
outline-offset: -2px;
border-radius: 4px;
}
/* Manually-checked marker: a human verdict outranks the confidence score, so a
checked line reads as settled and drops out of the review queue. */
.ab-conf-checked {
background: rgba(34,160,90,.16);
color: #1f8a4c;
border-color: rgba(34,160,90,.4);
}
@media (prefers-color-scheme: dark) { .ab-conf-checked { color: #56d98b; } }
.ab-cv-check {
flex: 0 0 auto;
align-self: flex-start;
margin-right: 6px;
padding: 0 2px;
border: none;
background: none;
cursor: pointer;
color: var(--subtext);
opacity: .45;
line-height: 1.4;
font-size: 14px;
}
.ab-cv-check:hover { opacity: 1; color: #1f8a4c; }
.ab-cv-check.is-checked { opacity: 1; color: #1f8a4c; }
@media (prefers-color-scheme: dark) {
.ab-cv-check:hover, .ab-cv-check.is-checked { color: #56d98b; }
}
/* Dim a settled row so the eye skips it while scrolling. */
.ab-cv-row[data-mark="ok"] { opacity: .62; }
.ab-cv-row[data-mark="wrong"] { opacity: 1; }
.ab-cv-row[data-mark="wrong"] .ab-cv-txt { text-decoration: underline wavy rgba(206,60,55,.55); text-underline-offset: 3px; }
.ab-conf-wrong { background: rgba(206,60,55,.16); color: #c0392b; border-color: rgba(206,60,55,.45); }
@media (prefers-color-scheme: dark) { .ab-conf-wrong { color: #ff8178; } }
/* Language code combobox: free text with a searchable datalist, so any code
can be entered (the old <select> could not express e.g. Filipino). Kept
narrow like the <select> it replaced so the surrounding row still lines up. */
input[list="lang-codes"] {
width: 88px;
text-transform: uppercase;
font-variant-numeric: tabular-nums;
}
/* ── Searchable language dropdown with flags ─────────────────────────────────
The underlying <select> stays in the DOM (hidden) as the source of truth so
existing .value reads and change listeners keep working; this is only the
presentation layer over it. */
.langsel { position: relative; display: inline-block; min-width: 0; }
.langsel-native { display: none !important; }
.langsel-btn {
display: flex; align-items: center; gap: 6px;
width: 100%; min-height: 30px; padding: 3px 8px;
border: 1px solid var(--border); border-radius: 6px;
background: var(--surface); color: var(--text);
font-size: 13px; cursor: pointer; text-align: left;
}
.langsel-btn:hover { border-color: var(--accent, #4a90d9); }
.langsel-btn .mdi-chevron-down { margin-left: auto; opacity: .6; }
.langsel-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.langsel-flag { font-size: 15px; line-height: 1; flex: 0 0 auto; }
.langsel-pop {
position: absolute; z-index: 60; top: calc(100% + 4px); left: 0;
min-width: 240px; max-width: 320px;
border: 1px solid var(--border); border-radius: 8px;
background: var(--panel); box-shadow: 0 6px 22px rgba(0,0,0,.22);
overflow: hidden;
}
.langsel-search { display: flex; align-items: center; gap: 6px; padding: 7px 9px; border-bottom: 1px solid var(--border); }
.langsel-search .mdi { opacity: .55; }
.langsel-search input {
flex: 1; border: none; outline: none; background: none; color: var(--text); font-size: 13px; min-width: 0;
}
.langsel-list { max-height: 300px; overflow-y: auto; padding: 4px; }
.langsel-opt {
display: flex; align-items: center; gap: 8px;
width: 100%; padding: 6px 8px; border: none; border-radius: 5px;
background: none; color: var(--text); font-size: 13px; text-align: left; cursor: pointer;
}
.langsel-opt:hover { background: rgba(127,127,127,.14); }
.langsel-opt.is-sel { background: rgba(74,144,217,.18); font-weight: 600; }
.langsel-empty { padding: 10px; font-size: 12px; color: var(--subtext); text-align: center; }
/* Routing actions duplicated into the page header: the card holding the
original toolbar is collapsible, and collapsing it hid the only Save button. */
.routing-head-actions {
margin-left: auto;
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.routing-head-actions .note { font-size: 12px; color: var(--subtext); }
/* Narrow column: the flag + code button must not force the row wider. */
.routing-grid .langsel { width: 100%; }
.routing-grid .langsel-btn { padding: 3px 6px; gap: 4px; }
.routing-grid .langsel-label { font-variant-numeric: tabular-nums; }
/* ── Magazines ─────────────────────────────────────────────────────────────
Article-first magazine reader: contents tree, boundary review, reflowed
article with sentence highlighting, and the original PDF page beside it. */
.mag-new { margin-bottom: 20px; }
.mag-new-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 12px; }
.mag-new-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--subtext); }
.mag-new-grid input { padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text); }
.mag-new .reader-dropzone { max-width: none; }
.mag-new-actions { display: flex; justify-content: flex-end; margin-top: 14px; }
.mag-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.mag-card-wrap { min-width: 0; }
.mag-card { display: flex; width: 100%; min-height: 100%; flex-direction: column; gap: 6px; align-items: flex-start; text-align: left;
padding: 14px; border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text); cursor: pointer; }
.mag-card:hover { border-color: var(--accent); }
.mag-card:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.18); }
.mag-card-actions { display: flex; justify-content: flex-end; padding: 6px 4px 0; }
.mag-card-delete { display: inline-flex; align-items: center; gap: 4px; padding: 5px 8px;
border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--subtext); cursor: pointer; }
.mag-card-delete:hover, .mag-card-delete:focus-visible { color: var(--error); border-color: var(--error); background: var(--surface); }
.mag-card-thumb { display: block; width: 100%; height: 190px; object-fit: contain; object-position: center;
background: var(--panel); border: 1px solid var(--border); border-radius: calc(var(--radius) - 2px); }
.mag-card-title { font-weight: 600; }
.mag-card-sub { color: var(--subtext); font-size: 13px; }
.mag-bar { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.mag-bar h3 { margin: 0; }
.mag-bar-actions { margin-left: auto; }
.mag-status { padding: 12px 14px; border-radius: var(--radius); background: var(--panel);
color: var(--subtext); margin-bottom: 12px; border-left: 3px solid var(--border); }
.mag-status.is-running { border-left-color: var(--accent); }
.mag-status.is-done { border-left-color: var(--green); }
.mag-status.is-failed { border-left-color: var(--red); }
.mag-ingest-row { display: flex; align-items: center; gap: 10px; }
.mag-ingest-icon { font-size: 20px; flex-shrink: 0; }
.mag-status.is-running .mag-ingest-icon { color: var(--accent); animation: mag-spin 1.6s linear infinite; }
.mag-status.is-done .mag-ingest-icon { color: var(--green); }
.mag-status.is-failed .mag-ingest-icon { color: var(--red); }
.mag-ingest-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.mag-ingest-text strong { font-weight: 500; color: var(--text); font-size: 13px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mag-ingest-track { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; }
.mag-ingest-fill { height: 100%; background: var(--accent); border-radius: 3px;
transition: width .4s ease; }
.mag-ingest-pct { font-size: 13px; font-weight: 600; color: var(--accent); flex-shrink: 0;
min-width: 3.2em; text-align: right; }
@keyframes mag-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.mag-status.is-running .mag-ingest-icon { animation: none; }
.mag-ingest-fill { transition: none; }
}
/* Live "source page / recognised text" preview during ingestion -- source
page on one side, recognised text filled in on the other as each page
finishes. Dark, console-like treatment on purpose: distinct from the rest
of the page so it clearly reads as a live process, not settled content. */
.mag-ingest-preview { display: grid; grid-template-columns: minmax(280px, 1fr) 8px minmax(300px, 1fr); gap: 0;
background: var(--border); border-radius: var(--radius); overflow: hidden; margin-bottom: 14px; min-height: min(56vh, 540px); }
.mag-ingest-preview-side { background: #14161a; padding: 10px; display: flex; flex-direction: column; gap: 8px; min-height: 0; }
.mag-ingest-preview-label { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: #8a8f98; }
.mag-ingest-preview-side img { width: 100%; min-width: 0; flex: 1 1 auto; min-height: 0; object-fit: contain; margin: 0 auto; border-radius: 4px; }
.mag-ingest-preview-text { color: #d7dae0; font-size: 13px; line-height: 1.6; white-space: pre-wrap;
overflow-y: auto; min-height: 0; flex: 1 1 auto; font-family: ui-monospace, 'SF Mono', Consolas, monospace; }
/* Elements the live preview's HTML formatting inserts (see
_render_ingest_preview_html in routes/magazine.py) -- sans-serif, unlike
the monospace body text, so a detected headline visibly reads as one. */
.mag-ingest-preview-text h3 { margin: 14px 0 6px; font: 600 14px/1.35 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e8eaef; }
.mag-ingest-preview-text h3:first-child { margin-top: 0; }
.mag-ingest-preview-text .mag-ingest-preview-figure { display: flex; flex-direction: column; align-items: center; gap: 4px;
margin: 12px 0; padding: 14px; border: 1px dashed #3a3f47; border-radius: var(--radius);
background: rgba(255,255,255,.04); color: #8a8f98; font: 500 11px/1.3 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
text-transform: uppercase; letter-spacing: .05em; }
.mag-ingest-preview-text .mag-ingest-preview-figure .mdi { font-size: 22px; }
.mag-ingest-preview-text .mag-ingest-preview-figure { margin-block: 12px; } /* <figure> has UA defaults to undo */
.mag-ingest-preview-text .mag-ingest-preview-figure img { display: block; max-width: 100%; max-height: 240px;
border-radius: 4px; object-fit: contain; }
.mag-ingest-preview-text .mag-ingest-preview-excluded { color: #6b7078; font-style: italic; }
.mag-ingest-preview-text .mag-ingest-preview-more { color: #6b7078; text-align: center; padding: 4px 0 0; }
.mag-ingest-preview-resize { background: var(--border); cursor: col-resize; position: relative; touch-action: none; }
.mag-ingest-preview-resize::after { content: ''; position: absolute; inset: 0 2px; background: transparent; }
.mag-ingest-preview.is-resizing { user-select: none; cursor: col-resize; }
.mag-ingest-preview.is-resizing .mag-ingest-preview-resize,
.mag-ingest-preview-resize:hover { background: var(--accent); }
@media (max-width: 860px) {
.mag-ingest-preview { grid-template-columns: 1fr; min-height: 0; }
.mag-ingest-preview-side { min-height: 300px; }
.mag-ingest-preview-resize { display: none; }
}
.mag-pill { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px;
background: var(--panel); color: var(--subtext); border: 1px solid var(--border); }
.mag-pill.ok { background: rgba(22,163,74,.12); color: var(--green); border-color: transparent; }
.mag-pill.warn { background: rgba(217,119,6,.12); color: var(--yellow); border-color: transparent; }
.mag-pill.bad { background: rgba(220,38,38,.12); color: var(--red); border-color: transparent; }
.mag-section h4 { margin: 18px 0 8px; color: var(--subtext); text-transform: uppercase;
font-size: 12px; letter-spacing: .06em; }
.mag-toc { list-style: none; margin: 0; padding: 0; }
.mag-toc-row { display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: center;
padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); margin-bottom: 6px; }
.mag-toc-row.is-approved { border-left: 3px solid var(--green); }
/* Not reviewed yet: blue background and edge (approved keeps the green edge). */
.mag-toc-row.is-unreviewed { border-left: 3px solid #2563eb; background: color-mix(in srgb, #2563eb 10%, var(--surface)); }
.mag-pill.unreviewed { background: rgba(37,99,235,.14); color: #1d4ed8; border-color: transparent; }
:root[data-theme="dark"] .mag-pill.unreviewed { color: #93c5fd; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .mag-pill.unreviewed { color: #93c5fd; } }
.mag-toc-title { font-weight: 600; }
.mag-toc-by { color: var(--subtext); font-size: 13px; margin-left: 8px; }
.mag-toc-meta { display: flex; gap: 10px; align-items: center; color: var(--subtext); font-size: 13px; flex-wrap: wrap; }
.mag-toc-actions { display: flex; gap: 6px; }
.mag-synth { display: inline-flex; align-items: center; gap: 4px; }
.mag-synth.is-done { color: var(--green); font-weight: 600; }
.mag-toc-play { min-width: 32px; }
.mag-select-check { display: flex; align-items: center; padding-right: 4px; }
.mag-select-check input { width: 18px; height: 18px; accent-color: var(--accent); cursor: pointer; }
.mag-toc-row { grid-template-columns: auto 1fr auto auto; }
.mag-card { position: relative; }
.mag-card .mag-select-check { position: absolute; top: 8px; left: 8px; z-index: 1;
background: var(--surface); border-radius: 4px; padding: 2px; }
.mag-bulkbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
padding: 10px 14px; margin-bottom: 12px; border: 1px solid var(--accent); border-radius: var(--radius);
background: var(--surface); position: sticky; top: 0; z-index: 25; }
.mag-bulkbar-count { font-weight: 600; }
.mag-bulkbar-progress { flex: 1; min-width: 0; }
.mag-bulkbar-actions { display: flex; gap: 6px; margin-left: auto; }
.mag-pages-grid { display: grid; grid-template-columns: repeat(var(--cols, 8), 1fr); gap: 12px; }
/* A fixed thumbnail height (the article-thumbnail default) meant the column
slider only ever changed each card's WIDTH -- the page image itself sat
at the same small fixed size regardless, floating in a mostly-empty
card. aspect-ratio lets height follow width instead, so fewer columns
(wider cards) genuinely means bigger thumbnails, matching what "zoom"
should do. ~0.707 is ISO A4's width:height ratio -- close enough for a
real scanned page and much better than a guess when it's slightly off,
since object-fit: contain still letterboxes any mismatch cleanly. */
.mag-pages-grid .mag-card-thumb { height: auto; aspect-ratio: 0.707 / 1; }
.mag-page-articles { display: flex; flex-direction: column; gap: 8px; margin-top: 2px; }
.mag-page-article { display: flex; flex-direction: column; gap: 5px; padding-top: 8px;
border-top: 1px solid var(--border); }
.mag-page-article:first-child { padding-top: 0; border-top: 0; }
.mag-page-article-title { color: var(--subtext); font-size: 13px; line-height: 1.35; overflow-wrap: anywhere; }
.mag-page-article-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.mag-cols-control { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--subtext); }
.mag-cols-control input[type="range"] { width: 90px; accent-color: var(--accent); }
#mag-cols-value { min-width: 16px; text-align: right; }
@media (max-width: 900px) { .mag-pages-grid { grid-template-columns: repeat(min(var(--cols, 8), 4), 1fr); } }
@media (max-width: 560px) { .mag-pages-grid { grid-template-columns: repeat(min(var(--cols, 8), 2), 1fr); } }
/* Page-state colours in the "All pages" grid -- blank (no article yet) is
deliberately the plain default look, not a warning: an untouched page is
normal mid-review, unlike a page that already has content sitting
unreviewed (detected, red) or with nothing worth narrating (empty, grey,
which is a completed decision, not a problem). */
.mag-card.is-page-detected { border-color: var(--red); background: color-mix(in srgb, var(--red) 8%, var(--surface)); }
.mag-card.is-page-approved { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 8%, var(--surface)); }
.mag-card.is-page-audio { border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, var(--surface)); }
.mag-card.is-page-empty { border-color: var(--subtext); background: color-mix(in srgb, var(--subtext) 8%, var(--surface)); }
.mag-card.is-page-checked { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
.mag-card.is-page-flagged { border-color: #9333EA; background: color-mix(in srgb, #9333EA 9%, var(--surface)); }
.mag-pill-flagged { color: #7E22CE; border-color: #9333EA; font-size: 12px; }
:root[data-theme="dark"] .mag-pill-flagged { color: #C084FC; }
.mag-pages-legend-swatch.is-page-checked { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-flagged { border-color: #9333EA; background: color-mix(in srgb, #9333EA 20%, var(--surface)); }
.mag-pages-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--subtext); margin: 0 0 12px; }
.mag-pages-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.mag-pages-legend-swatch { width: 12px; height: 12px; border-radius: 3px; border: 2px solid var(--border); }
.mag-pages-legend-swatch.is-page-detected { border-color: var(--red); background: color-mix(in srgb, var(--red) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-approved { border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-audio { border-color: var(--green); background: color-mix(in srgb, var(--green) 20%, var(--surface)); }
.mag-pages-legend-swatch.is-page-empty { border-color: var(--subtext); background: color-mix(in srgb, var(--subtext) 20%, var(--surface)); }
.mag-audio-export { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding: 10px 14px; margin-bottom: 12px; border: 1px solid var(--border); border-radius: var(--radius);
background: var(--panel); }
.mag-audio-export label { color: var(--subtext); font-size: 13px; }
/* MP3 playlist -- a separate, self-contained player from the live reader:
just an <audio> element pointed at already-rendered files, one track
after another. Sticky player bar + scrollable track list underneath. */
.mag-playlist { border: 1px solid var(--border); border-radius: var(--radius);
background: var(--panel); margin-bottom: 12px; overflow: hidden; }
.mag-playlist-heading { display: flex; justify-content: space-between; align-items: center; gap: 12px;
padding: 10px 14px; border-bottom: 1px solid var(--border); }
.mag-playlist-heading > div { display: flex; flex-direction: column; gap: 2px; }
.mag-playlist-player { display: flex; align-items: center; gap: 12px; padding: 10px 14px;
background: var(--surface); border-bottom: 1px solid var(--border);
position: sticky; top: 0; z-index: 2; }
.mag-playlist-cover { width: 56px; height: 56px; object-fit: cover; border-radius: 6px; flex-shrink: 0; }
.mag-playlist-nowplaying { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.mag-playlist-nowplaying strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mag-playlist-tracks { list-style: none; margin: 0; padding: 4px; max-height: 420px; overflow-y: auto; }
.mag-playlist-track { display: grid; grid-template-columns: 36px minmax(70px, auto) minmax(180px, 1fr) auto 28px;
align-items: center; gap: 10px; padding: 8px 10px; border-radius: 6px; }
.mag-playlist-track:hover { background: var(--surface); }
.mag-playlist-track.is-playing { background: var(--surface); border-left: 3px solid var(--accent); }
.mag-playlist-track-play { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
border: 1px solid var(--border); border-radius: 50%; background: var(--surface); color: var(--accent); cursor: pointer; }
.mag-playlist-track-play:hover { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.mag-playlist-track-page { color: var(--subtext); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mag-playlist-track-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mag-playlist-track-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mag-playlist-track-sub { font-size: 12px; }
.mag-playlist-track-duration { white-space: nowrap; font-variant-numeric: tabular-nums; }
.mag-playlist-track-status { font-size: 20px; text-align: center; color: var(--subtext); }
.mag-playlist-track.is-complete .mag-playlist-track-status { color: var(--green); }
.mag-playlist-track.is-in-progress .mag-playlist-track-status { color: var(--yellow); }
.mag-playlist-companion { display: grid; grid-template-columns: minmax(260px, .8fr) minmax(320px, 1.2fr);
gap: 18px; padding: 16px; border-top: 1px solid var(--border); background: var(--surface); }
.mag-playlist-visual { margin: 0; position: sticky; top: 92px; align-self: start; }
.mag-playlist-visual img { width: 100%; max-height: 65vh; display: block; object-fit: contain;
border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.mag-playlist-visual figcaption { display: flex; flex-direction: column; gap: 4px; padding: 8px 2px;
font-size: 13px; color: var(--subtext); }
.mag-playlist-sync-note { margin-bottom: 8px; font-size: 12px; }
.mag-playlist-transcript { max-height: 65vh; overflow-y: auto; padding: 4px 12px 16px 4px;
font-size: 16px; line-height: 1.65; }
.mag-playlist-line { margin: 0 0 8px; padding: 2px 5px; border-radius: 4px; cursor: pointer; }
.mag-playlist-line:hover { background: var(--panel); }
.mag-playlist-line.is-current { background: rgba(37,99,235,.16); box-shadow: -3px 0 0 var(--accent); }
@media (max-width: 640px) {
.mag-playlist-player { flex-wrap: wrap; }
.mag-playlist-nowplaying { order: 3; flex-basis: 100%; }
.mag-playlist-track { grid-template-columns: 36px 1fr auto 26px; }
.mag-playlist-track-page { display: none; }
.mag-playlist-companion { grid-template-columns: 1fr; }
.mag-playlist-visual { position: static; }
}
.mag-audio-export select { padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
background: var(--surface); color: var(--text); }
.mag-audio-export-progress-wrap { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 120px; }
.mag-audio-export-progress-wrap progress { flex: 1; min-width: 80px; max-width: 220px; height: 8px;
accent-color: var(--accent); }
#mag-audio-export-count { flex-shrink: 0; font-variant-numeric: tabular-nums; }
/* Clicking a title edits it in place -- a dashed underline on hover/focus is
the only cue it's editable, since a permanent border on every card title
would be noisy on a page listing 50+ articles. */
.mag-card-title[contenteditable], .mag-toc-title[contenteditable] { cursor: text; border-radius: 3px; outline: none; }
.mag-card-title[contenteditable]:hover, .mag-toc-title[contenteditable]:hover { text-decoration: underline dashed; }
.mag-card-title[contenteditable]:focus, .mag-toc-title[contenteditable]:focus { box-shadow: 0 0 0 2px var(--accent); }
.mag-review-head { display: grid; grid-template-columns: 2fr 1fr auto; gap: 12px; align-items: end; margin-bottom: 10px; }
.mag-review-head label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--subtext); }
.mag-review-field-control { display: flex; gap: 6px; align-items: center; }
.mag-review-field-control input { flex: 1 1 auto; min-width: 0; }
.mag-review-field-control .btn-sm { white-space: nowrap; }
.mag-review-head input { padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); color: var(--text); }
.mag-page-head { margin: 16px 0 6px; font-size: 13px; color: var(--subtext); }
/* ── Review page navigator + "OCR again" ─────────────────────────────────── */
/* Sticky so the page nav and box tools stay reachable on a long page without
scrolling back up; tightened gaps/heights so the whole bar has a real
chance of fitting one row instead of always wrapping to two. */
.mag-review-pagenav { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
position: sticky; top: 0; z-index: 30; background: var(--bg);
padding: 8px 0; margin-bottom: 12px; box-shadow: 0 2px 6px rgba(0, 0, 0, .06); }
.mag-review-pagenav-group { display: flex; align-items: center; gap: 4px; }
.mag-review-page-controls { display: flex; align-items: center; gap: 8px; padding: 4px;
border: 1px solid var(--accent); border-radius: var(--radius); background: var(--surface); }
.mag-review-page-number { min-width: 90px; text-align: center; font-size: 14px; color: var(--text); }
.mag-review-page-controls .btn-sm { min-width: 44px; min-height: 40px; font-size: 22px; }
.mag-review-pagenav .btn-sm { padding: 6px 10px; min-height: 34px; }
.mag-review-draw-controls { display: flex; gap: 6px; }
.mag-review-draw-controls .btn-sm { min-height: 34px; }
.mag-review-draw-controls .active { background: var(--accent); color: var(--on-accent); }
.mag-draw-toggle-switch { margin-left: 6px; font-size: 17px; vertical-align: -3px; }
.mag-review-draw-controls .active .mag-draw-toggle-switch { color: var(--green, #16a34a); }
#mag-draw-hint:not(:empty) { padding: 8px 12px; margin-bottom: 12px; border-left: 3px solid var(--accent); }
.mag-review-pagenav-spacer { flex: 1; min-width: 0; }
/* ── Split screen: rendered page (left) + extracted blocks (right) ───────── */
.mag-review-split { display: grid; grid-template-columns: 1.1fr 1fr; gap: 18px; align-items: start; }
.mag-review-page { position: sticky; top: 12px; }
.mag-review-page-wrap { position: relative; border: 1px solid var(--border); border-radius: var(--radius);
overflow: hidden; background: var(--panel); }
.mag-review-page-wrap img { width: 100%; height: auto; display: block; }
/* Colour-coded by region type using the same --c custom property and
mpt-<type> classes as the live ingest preview (see .mpt-title etc.
below) -- a headline or byline should be just as easy to spot on an
already-reviewed page as while it's still being detected. State classes
below (.is-excluded, .is-linked) override the type colour, since knowing
a region is unticked or claimed by another article matters more in the
moment than what kind it is. */
.mag-review-box { position: absolute; border: 2px solid var(--c, var(--accent));
background: color-mix(in srgb, var(--c, var(--accent)) 12%, transparent);
cursor: pointer; transition: background .12s, border-color .12s; }
.mag-review-box:hover { background: color-mix(in srgb, var(--c, var(--accent)) 24%, transparent); }
.mag-review-box.is-excluded { border-color: var(--subtext); background: rgba(120,120,120,.10); }
.mag-review-box.is-excluded:hover { background: rgba(120,120,120,.22); }
.mag-review-box.is-linked { border-color: var(--yellow); background: rgba(217,119,6,.22); z-index: 2; }
.mag-review-box-num { position: absolute; top: -1px; left: -1px; min-width: 16px; padding: 0 3px;
background: var(--c, var(--accent)); color: #fff; font-size: 10px; font-weight: 700;
line-height: 16px; text-align: center; border-radius: 0 0 4px 0; }
.mag-review-box.is-excluded .mag-review-box-num { background: var(--subtext); }
/* Centred glyph identifying the region kind (text/figure/furniture) at a
glance -- see magBlockIcon. Sized against the box, not fixed, so it stays
legible on both a full-page figure and a two-line caption. */
.mag-review-box-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
font-size: clamp(12px, 40%, 22px); color: var(--c, var(--accent)); opacity: .7; pointer-events: none; }
.mag-review-box.is-excluded .mag-review-box-icon { color: var(--subtext); }
/* A region already claimed by a DIFFERENT article sharing this page --
easy to mistake for stray unclaimed text without this. */
.mag-review-box-owner { position: absolute; bottom: -1px; right: -1px; padding: 0 4px;
background: var(--mauve); color: #fff; font-size: 9px; font-weight: 700;
line-height: 15px; border-radius: 4px 0 0 0; }
.mag-review-box.has-owner { border-style: dashed; }
/* Manual "draw it" escape hatch, for a region the OCR/layout pipeline
missed entirely. Crosshair cursor cues that a click-drag starts a new
box; the box itself is styled distinctly (solid green, dashed outline)
so it never reads as an already-detected region while being drawn. */
.mag-review-page-wrap.is-drawing { cursor: crosshair; }
.mag-review-page-wrap.is-drawing .mag-review-box:not(.mag-draw-rect) { pointer-events: none; opacity: .18; }
.mag-draw-rect { border: 2px dashed var(--green); background: rgba(22,163,74,.14); cursor: crosshair;
transition: none; z-index: 3; }
#mag-draw-toggle.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.mag-draw-panel { position: fixed; z-index: 60; max-width: calc(100vw - 16px); display: flex; flex-direction: column; gap: 6px;
padding: 8px; min-width: 220px; background: var(--panel); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: 0 4px 16px rgba(0,0,0,.25); }
.mag-draw-panel-row { display: flex; gap: 10px; align-items: center; justify-content: space-between; }
.mag-draw-panel-row label { display: flex; align-items: center; gap: 4px; font-size: 12px; }
.mag-draw-panel textarea { width: 100%; resize: vertical; font: inherit; font-size: 12px;
padding: 4px 6px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface);
color: var(--text); }
/* Searchable region-type combobox in the draw panel — a 16-option native
<select> is slow to scan and slow to reach by scrolling; this filters by
typing and shows an icon per type instead. */
.mag-type-picker { position: relative; display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
.mag-type-picker label { flex-shrink: 0; }
.mag-type-picker-input { flex: 1; min-width: 0; font: inherit; font-size: 12px; padding: 4px 6px;
border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--text); }
.mag-type-picker-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(37,99,235,.18); }
.mag-type-picker-list { position: absolute; top: 100%; left: 0; right: 0; z-index: 5; margin: 2px 0 0;
padding: 4px; list-style: none; max-height: 240px; overflow-y: auto; background: var(--surface);
border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 6px 18px rgba(0,0,0,.25); }
.mag-type-picker-option { display: flex; align-items: center; gap: 8px; padding: 6px 8px; font-size: 13px;
border-radius: 5px; cursor: pointer; color: var(--text); }
.mag-type-picker-option .mdi { color: var(--subtext); font-size: 16px; flex-shrink: 0; }
.mag-type-picker-option:hover { background: var(--panel); }
.mag-type-picker-option.is-selected { background: var(--accent); color: var(--on-accent); }
.mag-type-picker-option.is-selected .mdi { color: inherit; }
.mag-type-picker-empty { padding: 6px 8px; font-size: 13px; }
/* Editing an already-detected region: move by dragging the box body, resize
from its corner handle, delete with its ×. Handles and the delete button
only render usably in edit mode -- kept in the DOM at all times (rather
than added/removed) so toggling edit mode doesn't cost a re-render. */
.mag-review-page-wrap.is-editing { cursor: default; }
.mag-review-page-wrap.is-editing .mag-review-box { cursor: move; }
.mag-review-box-delete { display: none; position: absolute; top: -27px; right: -9px; width: 18px; height: 18px;
border-radius: 50%; border: 1px solid var(--border); background: var(--red); color: #fff;
font-size: 11px; line-height: 1; align-items: center; justify-content: center; padding: 0; cursor: pointer; z-index: 3; }
.mag-review-page-wrap.is-editing .mag-review-box-delete { display: flex; }
/* One handle per edge/corner -- lets a single boundary shared by two
stacked or side-by-side regions be dragged on its own (e.g. moving where
one paragraph block ends and the next begins) instead of only being able
to resize from the bottom-right corner. */
.mag-review-box-resize { display: none; position: absolute; width: 10px; height: 10px;
border-radius: 3px; border: 1px solid var(--accent); background: var(--panel); z-index: 3; }
.mag-review-page-wrap.is-editing .mag-review-box-resize { display: block; }
.mag-review-box-resize.rz-nw { top: -5px; left: -5px; cursor: nwse-resize; }
.mag-review-box-resize.rz-n { top: -5px; left: 50%; margin-left: -5px; cursor: ns-resize; }
.mag-review-box-resize.rz-ne { top: -5px; right: -5px; cursor: nesw-resize; }
.mag-review-box-resize.rz-e { top: 50%; right: -5px; margin-top: -5px; cursor: ew-resize; }
.mag-review-box-resize.rz-se { bottom: -5px; right: -5px; cursor: nwse-resize; }
.mag-review-box-resize.rz-s { bottom: -5px; left: 50%; margin-left: -5px; cursor: ns-resize; }
.mag-review-box-resize.rz-sw { bottom: -5px; left: -5px; cursor: nesw-resize; }
.mag-review-box-resize.rz-w { top: 50%; left: -5px; margin-top: -5px; cursor: ew-resize; }
#mag-edit-toggle.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.mag-block { display: grid; grid-template-columns: auto auto max-content 1fr; gap: 10px; align-items: start;
padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius);
background: var(--surface); margin-bottom: 4px; cursor: pointer; }
.mag-blocks-head { display: grid; grid-template-columns: auto auto max-content 1fr; gap: 10px; align-items: center;
position: sticky; top: 0; z-index: 3; padding: 8px 10px; margin-bottom: 6px;
border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel);
color: var(--subtext); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.mag-blocks-check-all { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
color: var(--text); text-transform: none; letter-spacing: 0; white-space: nowrap; }
.mag-blocks-check-all input { width: 17px; height: 17px; accent-color: var(--accent); }
.mag-block.is-aux { opacity: .68; }
.mag-block:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.14); }
.mag-block-num { font-size: 11px; font-weight: 700; color: var(--accent); min-width: 1.4em; }
.mag-block-type { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--subtext);
display: flex; align-items: center; gap: 3px; }
.mag-block-type .mdi { font-size: 13px; }
.mag-region-type-picker { flex: 0 1 10.5em; width: 10.5em; text-transform: none; letter-spacing: 0; }
.mag-region-type-picker .mag-type-picker-input { width: 100%; min-height: 28px; font-size: 11px; padding: 2px 5px; }
.mag-region-type-picker .mag-type-picker-list { right: auto; min-width: 210px; z-index: 8; text-transform: none; letter-spacing: 0; }
.mag-block-type-select { display: none; }
.mag-block-delete { padding: 2px 6px; min-width: 28px; min-height: 28px; color: var(--subtext); }
.mag-block-delete:hover, .mag-block-delete:focus-visible { color: var(--danger, #dc2626); }
.mag-block-owner { display: inline-block; padding: 1px 6px; margin-right: 6px; border-radius: 999px;
background: var(--mauve); color: #fff; font-size: 10px; font-weight: 700; }
.mag-block-image { cursor: default; grid-template-columns: auto auto max-content 1fr; }
.mag-block-text { font-size: 14px; line-height: 1.45; }
.mag-block-text.is-editable { cursor: text; border-radius: 4px; }
.mag-block-text.is-editable:hover { background: var(--panel); box-shadow: 0 0 0 4px var(--panel); }
/* A 5th grid child in the 4-column .mag-block-image row -- span the whole
row below the thumbnail rather than being squeezed into column 1 alone. */
.mag-describe { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
margin-top: 4px; padding-top: 8px; border-top: 1px dashed var(--border); }
.mag-describe-label { flex-basis: 100%; font-size: 11px; color: var(--subtext); }
.mag-describe-text { flex: 1 1 100%; min-width: 0; min-height: 44px; resize: vertical;
background: var(--panel); border: 1px solid var(--border); color: var(--text);
border-radius: var(--radius); padding: 6px 8px; font-size: 13px; font-family: inherit; }
.mag-review-foot { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px;
position: sticky; bottom: 0; padding: 12px 0; background: var(--bg); }
@media (max-width: 980px) {
.mag-review-split { grid-template-columns: 1fr; }
.mag-review-page { position: static; }
}
/* ── Two-page spread: page images on top, each page's OCR results directly
underneath it -- a 2x2 grid read top-to-bottom-then-across, matching how
an open magazine spread is laid out. Only one of the two pages is
draggable/drawable at a time (see magReviewSetActivePage); the other is
shown for context with working checkboxes. ───────────────────────────── */
.mag-review-spread { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 18px; align-items: start; }
.mag-review-spread-page { min-width: 0; }
.mag-review-spread-pagehead { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.mag-review-spread-page.is-active-page .mag-review-page-wrap { border-color: var(--accent); }
.mag-review-page-wrap.is-context-page { opacity: .94; }
.mag-review-spread-list { min-width: 0; }
@media (max-width: 980px) {
.mag-review-spread { grid-template-columns: 1fr; }
}
.mag-controls { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 14px;
padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.mag-voice-pick { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--subtext); }
.mag-pane-tabs { margin-left: auto; display: flex; gap: 4px; }
.mag-pane-tabs .active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.mag-article { max-width: 68ch; margin: 0 auto; font-size: 17px; line-height: 1.7; color: var(--text); }
.mag-article h2 { font-size: 26px; line-height: 1.25; margin: 0 0 8px; }
.mag-article .mag-deck { font-size: 19px; color: var(--subtext); margin: 0 0 12px; }
.mag-article .mag-byline { font-size: 14px; color: var(--subtext); margin: 0 0 20px; }
.mag-article .mag-caption { font-size: 14px; color: var(--subtext); font-style: italic; }
/* A synthesised aside, not part of the article's own written text -- set
off visually the same way a caption is, so a reader following along
silently (word-highlighting off) can tell it apart from the real prose. */
.mag-article .mag-figure-description { font-size: 15px; color: var(--subtext); font-style: italic;
padding-left: 10px; border-left: 2px solid var(--border); margin: 4px 0 14px; }
.mag-article .mag-figure-description::before { content: '\1F5BC '; font-style: normal; }
.mag-article [data-i] { cursor: pointer; border-radius: 3px; }
.mag-article [data-i]:hover { background: rgba(37,99,235,.07); }
.mag-article [data-i]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The reading highlight has to survive both themes and colour-blindness, so it
carries a left rule as well as a tint rather than relying on hue alone. */
.mag-article [data-i].is-current { background: rgba(37,99,235,.16); box-shadow: -3px 0 0 0 var(--accent); }
/* Word-level highlighting is an ESTIMATE (see estimateWordTimings in
magazine.js) -- a distinct, lighter treatment from the sentence highlight
above keeps that difference legible rather than implying frame-accurate
timing. */
.mag-w.is-current { background: var(--accent); color: var(--on-accent); border-radius: 2px; }
.mag-karaoke-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--subtext); }
.mag-read-image { max-width: 68ch; margin: 0 auto 18px; }
.mag-read-image img { width: 100%; height: auto; max-height: 360px; object-fit: contain;
border-radius: var(--radius); border: 1px solid var(--border); background: var(--panel); display: block; }
.mag-page-wrap { position: relative; max-width: 900px; margin: 0 auto; }
.mag-page-wrap img { width: 100%; height: auto; display: block; border: 1px solid var(--border); border-radius: var(--radius); }
.mag-page-box { position: absolute; border: 2px solid var(--accent); background: rgba(37,99,235,.12);
border-radius: 2px; pointer-events: none; transition: all .25s ease; }
.mag-podcast { margin-top: 24px; }
.mag-podcast summary { cursor: pointer; font-weight: 600; }
.mag-hosts { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin: 12px 0; }
.mag-hosts label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--subtext); }
.mag-podcast-actions { display: flex; gap: 8px; margin-bottom: 12px; }
.mag-turns { padding-left: 20px; line-height: 1.6; }
.mag-turns li { margin-bottom: 8px; border-radius: 3px; padding: 2px 4px; }
.mag-turns li.is-current { background: rgba(37,99,235,.16); box-shadow: -3px 0 0 0 var(--accent); }
/* ── Driving mode ──────────────────────────────────────────────────────────
Full-screen, minimal-interaction overlay: two oversized controls, large
type, nothing else competing for attention. Reuses whatever is already
playing/queued -- it is a view, not a separate playback path. */
.mag-driving { position: fixed; inset: 0; z-index: 500; background: var(--bg);
display: flex; align-items: center; justify-content: center; }
.mag-driving-exit { position: absolute; top: 20px; right: 20px; width: 52px; height: 52px;
border-radius: 50%; border: 1px solid var(--border); background: var(--surface); color: var(--text);
font-size: 22px; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.mag-driving-exit:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.mag-driving-body { text-align: center; max-width: 90vw; }
.mag-driving-body h2 { font-size: clamp(28px, 5vw, 48px); margin: 0 0 8px; }
.mag-driving-queue { margin-bottom: 20px; font-size: 18px; }
.mag-driving-controls { display: flex; align-items: center; justify-content: center; gap: 32px; margin-top: 32px; }
.mag-driving-btn { width: 96px; height: 96px; border-radius: 50%; border: none;
background: var(--panel); color: var(--text); font-size: 36px; cursor: pointer;
display: flex; align-items: center; justify-content: center; }
.mag-driving-btn.mag-driving-play { width: 140px; height: 140px; font-size: 56px;
background: var(--accent); color: var(--on-accent); }
.mag-driving-time { margin-top: 26px; font-size: 22px; font-variant-numeric: tabular-nums; }
.mag-driving-progress { width: min(680px, 80vw); height: 10px; margin: 12px auto 0;
overflow: hidden; border-radius: 999px; background: var(--border); }
.mag-driving-progress span { display: block; width: 0; height: 100%; background: var(--accent); transition: width .2s linear; }
.mag-driving-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.mag-driving-btn:active { transform: scale(0.96); }
@media (prefers-reduced-motion: reduce) {
.mag-page-box { transition: none; }
.mag-driving-btn:active { transform: none; }
}
@media (max-width: 860px) {
.mag-new-grid, .mag-review-head { grid-template-columns: 1fr; }
.mag-toc-row { grid-template-columns: 1fr; }
.mag-toc-actions { justify-content: flex-start; }
.mag-block { grid-template-columns: auto auto 1fr; }
/* The type picker and delete button stay on small screens; the text drops to its own line. */
.mag-block-type { grid-column: 3; }
.mag-block-type > .mdi { display: none; }
.mag-block-text, .mag-block-thumb-wrap { grid-column: 1 / -1; }
.mag-article { font-size: 18px; }
.mag-driving-controls { gap: 20px; }
.mag-driving-btn { width: 76px; height: 76px; font-size: 28px; }
.mag-driving-btn.mag-driving-play { width: 110px; height: 110px; font-size: 44px; }
}
.mag-review-box.is-advertisement { border-color: var(--red); background: rgba(220,38,38,.08); }
.mag-review-box.is-advertisement .mag-review-box-num { background: var(--red); }
/* Appearance forms: manage / rename / delete / per-form image generation */
.lcd-forms-manage { margin: 10px 0 14px; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius, 8px); background: var(--surface); }
.lcd-forms-manage > summary { cursor: pointer; font-weight: 600; }
.lcd-forms-list { list-style: none; margin: 8px 0; padding: 0; display: grid; gap: 6px; }
.lcd-forms-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; }
.lcd-forms-list li.is-active { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(37,99,235,.14); }
.lcd-form-name, .lcd-form-new-name { flex: 1 1 180px; min-width: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--text); }
.lcd-form-flag { font-size: 12px; color: var(--subtext); white-space: nowrap; }
.lcd-form-flag.is-review { color: var(--warning, #d97706); font-weight: 600; }
.lcd-form-flag.is-ok { color: var(--green, #16a34a); }
.lcd-form-add { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px; }
.lcd-forms-manage :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Reading order by hand (magazine review) */
.mag-block-order { width: 3.2em; min-height: 28px; padding: 2px 4px; font: inherit; font-size: 12px;
text-align: center; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.mag-order-bar:empty { display: none; }
.mag-order-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 6px; padding: 6px 10px;
border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); font-size: 13px; }
.mag-review-page-wrap.is-ordering .mag-review-box { cursor: pointer; }
.mag-review-box.is-ordered { outline: 3px solid var(--accent, #2563eb); outline-offset: -1px; }
.mag-review-box.is-ordered .mag-review-box-num { background: var(--accent, #2563eb); color: #fff; }
/* Quick corrections in the magazine review list */
.mag-list-keys { font-size: 12px; margin: 0 0 6px; }
.mag-row-actions { display: inline-flex; gap: 2px; grid-column: -2 / -1; justify-self: end; }
.mag-row-action { padding: 2px 6px; min-width: 28px; min-height: 28px; color: var(--subtext); }
.mag-row-action:hover, .mag-row-action:focus-visible { color: var(--text); }
.mag-row-editor { display: flex; flex-direction: column; gap: 6px; grid-column: 1 / -1; }
.mag-row-editor textarea { width: 100%; font: inherit; font-size: 13px; padding: 6px; border: 1px solid var(--border);
border-radius: var(--radius); background: var(--surface); color: var(--text); resize: vertical; }
.mag-row-editor-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.mag-blocks [data-block-row]:focus-within { outline: 2px solid var(--accent, #2563eb); outline-offset: 1px; }
/* Select several boxes (magazine review) */
.mag-review-page-wrap.is-selecting { cursor: crosshair; }
.mag-review-page-wrap.is-selecting .mag-review-box { cursor: pointer; }
.mag-review-box.is-selected { outline: 3px solid var(--warning, #d97706); outline-offset: -1px;
background: color-mix(in srgb, var(--warning, #d97706) 18%, transparent); }
.mag-blocks [data-block-row].is-selected { border-color: var(--warning, #d97706); box-shadow: inset 3px 0 0 var(--warning, #d97706); }
/* Live region boxes on the page being read (magazine ingestion preview) */
.mag-ingest-preview-canvas { position: relative; flex: 1 1 auto; min-height: 0; display: flex; }
.mag-ingest-preview-canvas { align-items: flex-start; }
.mag-ingest-preview-canvas img { width: 100%; height: 100%; object-fit: contain; object-position: center top; }
.mag-ingest-preview-boxes { position: absolute; pointer-events: none; }
.mag-preview-box { position: absolute; border: 2px solid var(--c, #3b82f6); border-radius: 2px;
background: color-mix(in srgb, var(--c, #3b82f6) 14%, transparent); }
.mag-preview-box.is-new { animation: mag-preview-in .45s ease-out; }
@keyframes mag-preview-in { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .mag-preview-box.is-new { animation: none; } }
.mag-preview-box-num { position: absolute; left: -2px; top: -2px; min-width: 16px; padding: 0 3px; font: 600 10px/16px system-ui, sans-serif;
color: #fff; background: var(--c, #3b82f6); border-radius: 2px 0 2px 0; text-align: center; }
.mag-ingest-preview-legend { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: 11px; color: #b6bac2; }
.mag-preview-legend-item { display: inline-flex; align-items: center; gap: 4px; }
.mag-preview-swatch { width: 10px; height: 10px; border-radius: 2px; background: var(--c); }
.mag-preview-legend-count { margin-left: auto; color: #8a8f98; }
.mag-review-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 12px; color: var(--subtext); margin: 6px 0 10px; }
.mpt-title { --c: #a855f7; } .mpt-heading { --c: #d8b4fe; } .mpt-deck { --c: #06b6d4; } .mpt-byline { --c: #10b981; } .mpt-body { --c: #3b82f6; } .mpt-quote { --c: #8b5cf6; }
.mpt-caption { --c: #14b8a6; } .mpt-pullquote { --c: #ec4899; } .mpt-sidebar { --c: #f59e0b; } .mpt-ad { --c: #ef4444; }
.mpt-furniture, .mpt-page_number { --c: #9ca3af; }
/* Visual regions: their own colours and a stronger fill, so a picture reads as an area, not a text line. */
.mpt-image, .mpt-figure { --c: #f97316; } .mpt-chart { --c: #84cc16; } .mpt-table { --c: #eab308; } .mpt-code { --c: #94a3b8; }
.mag-preview-box.mpt-image, .mag-preview-box.mpt-figure, .mag-preview-box.mpt-chart, .mag-preview-box.mpt-table,
.mag-preview-box.mpt-code { border-width: 3px; border-style: dashed; background: color-mix(in srgb, var(--c) 24%, transparent); }
.mag-preview-legend-hint { color: #8a8f98; font-style: italic; }
.mag-quality-report { margin: 8px 0; padding: 10px 14px; border: 1px solid var(--border, #c9c9c9);
border-radius: 8px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.mag-quality-report[hidden] { display: none; }
.mag-quality-report progress { flex: 1 1 100%; height: 10px; }
/* Live quality-run indicator on the page grid */
.mag-card .mag-live-tag { position: absolute; top: 8px; right: 8px; z-index: 2; padding: 2px 8px;
border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--surface);
border: 1px solid var(--accent); color: var(--accent); }
.mag-card.is-page-working { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent);
animation: mag-working-pulse 1.2s ease-in-out infinite; }
.mag-card.is-page-live-done .mag-live-tag { border-color: var(--green); color: var(--green); }
@keyframes mag-working-pulse { 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 15%, transparent); } }
@media (prefers-reduced-motion: reduce) { .mag-card.is-page-working { animation: none; } }
.mag-card .mag-thumb-flag { position: absolute; top: 8px; left: 8px; z-index: 2; display: inline-flex; gap: 4px;
align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 700; cursor: pointer;
background: #9333EA; color: #fff; border: 2px solid #fff; }
.mag-card .mag-thumb-flag:hover, .mag-card .mag-thumb-flag:focus-visible { background: #7E22CE; outline: 2px solid #9333EA; outline-offset: 2px; }
.mag-card.is-page-flagged { border-width: 2px; }
.mag-card.is-page-ad { border-color: var(--green); border-style: dashed; border-width: 2px;
background: color-mix(in srgb, var(--green) 12%, var(--surface)); }
.mag-pages-legend-swatch.is-page-ad { border-color: var(--green); border-style: dashed; background: color-mix(in srgb, var(--green) 20%, var(--surface)); }
/* Driving mode: Spotify-style transport, text + image toggles, speed */
.mag-driving { overflow-y: auto; }
.mag-driving-body { width: min(760px, 94vw); padding: 24px 0; }
.mag-driving-visual { margin: 0 auto 16px; max-height: 32vh; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.mag-driving-visual img { max-width: 100%; max-height: 28vh; object-fit: contain; border-radius: 12px; }
.mag-driving-visual figcaption { font-size: 14px; color: var(--subtext); }
.mag-driving-lyrics { margin: 8px auto 18px; max-width: 640px; }
.mag-driving-line { margin: 6px 0; font-size: clamp(16px, 2.4vw, 22px); line-height: 1.4; color: var(--subtext); opacity: .6; }
.mag-driving-line.is-current { font-size: clamp(22px, 3.6vw, 34px); font-weight: 700; color: var(--text); opacity: 1; }
.mag-driving-seek { margin-top: 12px; }
.mag-driving-seek input[type="range"] { width: min(680px, 88vw); height: 28px; accent-color: var(--accent); }
.mag-driving-seek .mag-driving-time { margin-top: 2px; }
.mag-driving-controls { gap: 20px; margin-top: 18px; }
.mag-driving-btn.is-small { width: 64px; height: 64px; font-size: 26px; }
.mag-driving-options { display: flex; justify-content: center; gap: 12px; margin-top: 22px; flex-wrap: wrap; }
.mag-driving-opt { min-width: 76px; min-height: 52px; padding: 0 18px; border-radius: 26px; font-size: 18px; font-weight: 700;
border: 2px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; }
.mag-driving-opt[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.mag-driving-opt:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
@media (max-width: 860px) { .mag-driving-btn.is-small { width: 52px; height: 52px; font-size: 22px; } .mag-driving-controls { gap: 12px; } }
/* Driving mode karaoke text: whole article, current sentence + word highlighted */
.mag-driving-lyrics { max-height: 34vh; overflow-y: auto; text-align: left; padding: 8px 14px; border-radius: 12px;
background: color-mix(in srgb, var(--surface) 70%, transparent); scroll-behavior: auto; }
.mag-driving-lyrics .mag-driving-line { margin: 0 0 12px; font-size: clamp(18px, 2.6vw, 26px); opacity: .55; color: var(--text); font-weight: 400; }
.mag-driving-lyrics .mag-driving-line.is-current { opacity: 1; font-weight: 600; font-size: clamp(20px, 3vw, 30px);
border-left: 4px solid var(--accent); padding-left: 10px; }
.mag-dw.is-current { background: var(--accent); color: var(--on-accent, #fff); border-radius: 4px; padding: 0 3px; }
.mag-driving-lyrics { position: relative; }
/* On a phone the review toolbar wraps to many rows; sticky, it would cover most of the page image
(drag-drawing and box selection then start on a toolbar button), so it scrolls away instead. */
@media (max-width: 860px) {
.mag-review-pagenav { position: static; box-shadow: none; }
}
/* Magazine: spelling marks and the pronunciation/spelling panel */
.mag-spell { background: transparent; color: inherit; text-decoration: underline wavy #d93025; text-decoration-thickness: 1.5px; text-underline-offset: 3px; cursor: help; }
.mag-spell-panel, .mag-checks { margin-top: 12px; }
.mag-spell-list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 8px; }
.mag-spell-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.mag-spell-ctx { flex: 1 1 320px; min-width: 0; overflow-wrap: anywhere; }
.mag-acr-table { width: 100%; border-collapse: collapse; margin: 8px 0 12px; }
.mag-acr-table th, .mag-acr-table td { text-align: left; padding: 4px 8px; vertical-align: middle; }
.mag-acr-table input { width: 100%; min-width: 140px; }
.mag-checks h4 { margin: 14px 0 4px; }
@media (max-width: 700px) {
.mag-acr-table thead { display: none; }
.mag-acr-table tr { display: grid; gap: 2px; padding: 6px 0; border-bottom: 1px solid var(--border, #ddd); }
}
/* Magazine review: what is wrong on this page */
.mag-issues-panel { margin: 10px 0; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); }
.mag-issues-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.mag-issues-list { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }
.mag-issues-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.mag-issues-text { flex: 1 1 320px; min-width: 0; }
.mag-issue-swatch { width: 18px; height: 14px; border-radius: 3px; flex: 0 0 auto; border: 3px solid transparent; }
.mag-issue-swatch.is-uncovered { border: 2px dashed #dc2626; }
.mag-issue-swatch.is-issue-clipped { border-right: 5px solid #f97316; border-top-color: #bbb; border-bottom-color: #bbb; border-left-color: #bbb; }
.mag-issue-swatch.is-issue-overlap { border: 2px dashed #9333ea; }
.mag-issue-swatch.is-issue-suspect { border: 2px dotted #ca8a04; }
.mag-issue-swatch.is-spell { border: 0; background: repeating-linear-gradient(135deg, transparent 0 3px, #d93025 3px 5px); height: 4px; margin-top: 8px; }
.mag-issue-box { position: absolute; pointer-events: none; z-index: 3; box-sizing: border-box; }
.mag-issue-box.is-uncovered { border: 3px dashed #dc2626; background: rgba(220,38,38,.10); }
.mag-issue-box::after, .mag-review-box[data-issue]::after { display: none; content: attr(data-issue); position: absolute; left: -2px; bottom: 100%; max-width: 240px;
padding: 1px 5px; font-size: 11px; line-height: 1.3; color: #fff; background: #b91c1c; border-radius: 3px 3px 0 0; white-space: nowrap; pointer-events: none; }
.mag-review-box.is-issue-clipped[data-issue]::after { background: #c2410c; }
.mag-review-box.is-issue-overlap[data-issue]::after { background: #7e22ce; }
.mag-review-box.is-issue-suspect[data-issue]::after { background: #a16207; }
.mag-review-box.is-issue-overlap { outline: 3px dashed #9333ea; outline-offset: 1px; }
.mag-review-box.is-issue-suspect { outline: 3px dotted #ca8a04; outline-offset: 1px; }
.mag-review-box.is-issue-clipped.side-right { box-shadow: 5px 0 0 0 #f97316; }
.mag-review-box.is-issue-clipped.side-left { box-shadow: -5px 0 0 0 #f97316; }
.mag-review-box.is-issue-clipped.side-top { box-shadow: 0 -5px 0 0 #f97316; }
.mag-review-box.is-issue-clipped.side-bottom { box-shadow: 0 5px 0 0 #f97316; }
/* Magazine: text flow arrows, chips and reading-view seam markers */
.mag-flow-toggle { margin-left: auto; font-size: 13px; display: inline-flex; align-items: center; gap: 4px; }
.mag-flow-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 4; overflow: visible; }
.mag-flow-path { fill: none; stroke: #16a34a; stroke-width: 3; stroke-linecap: round; }
.mag-flow-label { font-size: 11px; font-weight: 600; fill: #fff; paint-order: stroke; stroke: #15803d; stroke-width: 4px; stroke-linejoin: round; }
.mag-flow-chip { position: absolute; right: 2px; z-index: 5; padding: 0 5px; font-size: 11px; line-height: 1.5; border-radius: 3px;
color: #fff; background: #15803d; white-space: nowrap; pointer-events: none; }
.mag-flow-chip.is-top { top: 2px; } .mag-flow-chip.is-bottom { bottom: 2px; }
.mag-flow-chip.is-edge { background: #475569; }
.mag-seam { display: inline-block; margin: 0 2px; padding: 0 5px; font-size: .72em; line-height: 1.6; vertical-align: middle;
border-radius: 999px; color: #14532d; background: #dcfce7; border: 1px solid #86efac; user-select: none; }
.mag-seam.is-page { background: #bbf7d0; font-weight: 600; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .mag-seam { color: #dcfce7; background: #14532d; border-color: #166534; } }
:root[data-theme="dark"] .mag-seam { color: #dcfce7; background: #14532d; border-color: #166534; }
.mag-review-page-wrap.has-room .mag-issue-box::after, .mag-review-page-wrap.has-room .mag-review-box[data-issue]::after,
.mag-review-box[data-issue]:hover::after { display: block; }
.mag-flow-path.is-paragraph { stroke-dasharray: 7 5; }
.mag-link-page { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 13px; }
.mag-report-group { margin-top: 8px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
details.mag-report-group { display: block; }
details.mag-report-group summary { cursor: pointer; margin-bottom: 6px; }
.mag-page-pill { min-width: 2.6em; padding: 2px 8px; }
.mag-flow-chip.is-open { pointer-events: auto; cursor: pointer; background: #b45309; border: 0; font: inherit; font-size: 11px; }
.mag-flow-chip.is-open:hover, .mag-flow-chip.is-open:focus-visible { background: #92400e; }
/* Page thumbnail as the Review target */
.mag-card-thumb-btn { display: block; width: 100%; padding: 0; margin: 0; border: 0; background: none; cursor: pointer; border-radius: 6px; }
.mag-card-thumb-btn:hover .mag-card-thumb, .mag-card-thumb-btn:focus-visible .mag-card-thumb { outline: 3px solid var(--accent); outline-offset: 2px; }
.mag-card-thumb-btn:focus-visible { outline: none; }
.mag-pagenav-break { flex-basis: 100%; height: 0; margin: 0; padding: 0; }
.mag-spell-edit { cursor: text; border-radius: 3px; }
.mag-spell-edit:hover, .mag-spell-edit:focus-visible { background: rgba(217,48,37,.14); outline: 2px solid rgba(217,48,37,.5); outline-offset: 1px; }
.mag-spell-editor { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; flex: 1 1 320px; }
.mag-spell-input { flex: 1 1 200px; min-width: 140px; font: inherit; padding: 4px 8px; border: 1px solid var(--accent); border-radius: 4px; background: var(--surface); color: var(--text); }
/* Find an issue online (magazine library) */
.mag-find { margin-bottom: 18px; }
.mag-find-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.mag-find-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.mag-find-query { flex: 1 1 240px; }
.mag-find-results { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.mag-find-item { display: flex; gap: 12px; align-items: center; justify-content: space-between;
padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.mag-find-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mag-find-summary { color: var(--subtext); font-size: 13px; overflow-wrap: anywhere; }
@media (max-width: 600px) { .mag-find-item { flex-direction: column; align-items: stretch; } }
/* Review: text edited by hand, and its difference from the recognised text */
.mag-edited { display: inline-flex; align-items: center; gap: 6px; margin-left: 8px; font-size: 12px; color: var(--subtext); }
.mag-diff { margin: 6px 0 2px 28px; padding: 8px 10px; border: 1px dashed var(--border); border-radius: var(--radius);
background: var(--surface); line-height: 1.6; overflow-wrap: anywhere; }
.mag-diff del { text-decoration: line-through; color: var(--red, #b91c1c); }
.mag-diff ins { text-decoration: underline; color: var(--green); }
.mag-diff del::before { content: "\2212\00a0"; }
.mag-diff ins::before { content: "+\00a0"; }
/* Reading view: sidebars shown in place but not narrated */
.mag-aside { display: block; margin: 12px 0; padding: 10px 14px; border-left: 4px solid var(--border);
background: var(--surface); border-radius: 0 var(--radius) var(--radius) 0; color: var(--subtext); font-size: .92em; }
.mag-aside-label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 4px; }
.mag-aside-text { display: block; white-space: pre-line; overflow-wrap: anywhere; }