diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ce9c8..45928c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi ## [Unreleased] ### Changed +- **Rehearser stylesheet extraction.** The main Rehearser layout, cast, stage, training, library, and script-view + rules now live in `static/css/rehearser.css`, loaded after the core stylesheet with release cache busting. - **Rehearser cast-renderer extraction.** The full cast-card renderer and delegated cast interactions now live in `rehearser-cast.js`; the legacy `renderCastList` global and existing behavior remain available. - **Provider status clarity.** TTS and STT backend discovery now reports configuration separately from liveness, diff --git a/TODO.md b/TODO.md index c1a3219..ec07c33 100644 --- a/TODO.md +++ b/TODO.md @@ -142,7 +142,8 @@ architecture change: the larger Audiobook/Rehearser/style split. - [x] Split the Performance/resource diagnostic styles into `static/css/resource-diagnostics.css`. - [x] Split background-job history and retry-panel styles into `static/css/background-jobs.css`. - [x] Split Voice Design form and sample-grid styles into `static/css/voice-design.css`. -- [ ] Split `style.css` by feature. +- [x] Split `style.css` by feature; Rehearser rules now live in `static/css/rehearser.css` alongside the existing + diagnostics, background-job, and voice-design feature styles. - [ ] Do not migrate to TypeScript or rewrite the frontend until behavior is covered by tests. ## P1 — Frontend performance and memory safety diff --git a/VERSION b/VERSION index 4d65d5e..067233c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.24.44 +1.24.45 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index cdef598..5610ded 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -42,6 +42,7 @@ Done incrementally as global-scope ordered files (no ES-module change needed) - ✅ `static/css/resource-diagnostics.css` — isolated Performance/resource diagnostic panel styles. - ✅ `static/css/background-jobs.css` — isolated background-job history and retry-panel styles. - ✅ `static/css/voice-design.css` — isolated Voice Design form, samples, and preview-match styles. +- ✅ `static/css/rehearser.css` — isolated Rehearser modal, cast, stage, training, bookshelf, and script-view styles. - ✅ `rehearser-train.js` — transcript normalization, LCS comparison, and word-level training feedback; microphone/state wiring remains in `rehearser.js`. - ✅ `rehearser-library.js` — SQLite persistence helpers and IndexedDB migration; import/export and auto-save remain in `rehearser.js` until their UI/event-handler dependencies are isolated. diff --git a/static/css/rehearser.css b/static/css/rehearser.css new file mode 100644 index 0000000..9ac2c94 --- /dev/null +++ b/static/css/rehearser.css @@ -0,0 +1,1135 @@ +/* ── Script Rehearser ───────────────────────────────────────────────────── */ +.reh-phase[hidden] { display: none; } + +/* ── IMSDb browser modal ────────────────────────────────────────────────── */ +.reh-imsdb-modal { + position: fixed; inset: 0; z-index: 1000; + background: rgba(0,0,0,.55); display: flex; align-items: center; justify-content: center; + padding: 24px; +} +.reh-imsdb-modal[hidden] { display: none; } +.reh-imsdb-box { + background: var(--bg); border: 1px solid var(--border); border-radius: 14px; + width: 100%; max-width: 1100px; height: 88vh; display: flex; flex-direction: column; + box-shadow: 0 20px 60px rgba(0,0,0,.4); overflow: hidden; +} +.reh-imsdb-head { + display: flex; align-items: center; gap: 12px; padding: 14px 18px; + border-bottom: 1px solid var(--border); flex-shrink: 0; +} +.reh-imsdb-head h3 { margin: 0; font-size: 15px; display: flex; align-items: center; gap: 7px; white-space: nowrap; } +.reh-imsdb-url-row { display:flex; align-items:center; gap:8px; padding:10px 18px; border-bottom:1px solid var(--border); background:var(--panel); } +.reh-imsdb-url-row .reh-imsdb-url-input { flex:1; min-width:0; height:32px; padding:0 10px; border:1px solid var(--border); border-radius:7px; background:var(--surface); color:var(--text); font-size:13px; } +.reh-imsdb-search { + flex: 1; height: 34px; padding: 0 12px; border: 1px solid var(--border); + border-radius: 8px; background: var(--input-bg, var(--panel)); color: var(--text); font-size: 13px; +} +.reh-imsdb-count { font-size: 12px; color: var(--subtext); white-space: nowrap; } +.reh-imsdb-grid { + flex: 1; overflow-y: auto; padding: 16px; + display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; + align-content: start; +} +.reh-imsdb-loading { grid-column: 1/-1; text-align: center; padding: 40px; color: var(--subtext); font-size: 13px; display: flex; align-items: center; justify-content: center; gap: 10px; } +.reh-imsdb-load-error { grid-column: 1/-1; margin-bottom: 8px; padding: 10px 12px; border: 1px solid var(--red); border-left-width: 5px; border-radius: 8px; color: var(--red); background: rgba(220,38,38,.08); font-size: 13px; font-weight: 700; } +.reh-scripts-link { white-space: nowrap; } +.reh-imsdb-card { + cursor: pointer; border-radius: 8px; overflow: hidden; background: var(--card-bg, var(--panel)); + border: 1px solid var(--border); transition: transform .12s, box-shadow .12s, border-color .12s; + display: flex; flex-direction: column; +} +.reh-imsdb-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,0,0,.25); border-color: var(--accent); } +/* Poster image: use padding-bottom trick for guaranteed 2:3 ratio regardless of parent */ +.reh-imsdb-poster-wrap { + position: relative; width: 100%; padding-bottom: 150%; /* 2:3 ratio */ overflow: hidden; flex-shrink: 0; +} +.reh-imsdb-poster { + position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; +} +.reh-imsdb-fallback { + position: absolute; inset: 0; width: 100%; height: 100%; + display: flex; flex-direction: column; align-items: center; justify-content: center; + gap: 6px; color: rgba(255,255,255,.85); font-size: 28px; padding: 10px; box-sizing: border-box; +} +.reh-imsdb-fallback-title { + font-size: 11px; font-weight: 700; text-align: center; line-height: 1.35; + color: rgba(255,255,255,.95); text-shadow: 0 1px 4px rgba(0,0,0,.5); + overflow: hidden; display: -webkit-box; + -webkit-line-clamp: 4; -webkit-box-orient: vertical; + word-break: break-word; padding: 0 4px; max-width: 100%; +} +.reh-imsdb-meta { padding: 7px 9px; display: flex; flex-direction: column; gap: 2px; } +.reh-imsdb-title { font-size: 12px; font-weight: 600; color: var(--text); line-height: 1.25; + display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } +.reh-imsdb-year { font-size: 11px; color: var(--subtext); } + +/* IMSDb list view */ +.reh-imsdb-grid.list-view { + display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; +} +.reh-imsdb-grid.list-view .reh-imsdb-card { + flex-direction: row; align-items: center; gap: 0; height: 48px; border-radius: 6px; +} +.reh-imsdb-grid.list-view .reh-imsdb-card:hover { transform: none; box-shadow: 0 2px 8px rgba(0,0,0,.15); } +.reh-imsdb-grid.list-view .reh-imsdb-poster-wrap { + width: 32px; min-width: 32px; height: 48px; padding-bottom: 0; flex-shrink: 0; +} +.reh-imsdb-grid.list-view .reh-imsdb-fallback { + font-size: 13px; gap: 0; +} +.reh-imsdb-grid.list-view .reh-imsdb-fallback-title { display: none; } +.reh-imsdb-grid.list-view .reh-imsdb-poster { + position: static; width: 32px; height: 48px; object-fit: cover; +} +.reh-imsdb-grid.list-view .reh-imsdb-meta { + flex-direction: row; align-items: center; gap: 8px; padding: 0 12px; flex: 1; min-width: 0; +} +.reh-imsdb-grid.list-view .reh-imsdb-title { + display:block; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); -webkit-line-clamp: unset; font-size: 13px; flex: 1; +} +.reh-imsdb-grid.list-view .reh-imsdb-card { background:var(--surface); } +.reh-imsdb-grid.list-view .reh-imsdb-year { margin-left: auto; white-space: nowrap; font-size: 11px; } + +/* View toggle buttons in modal header */ +.reh-imsdb-view-btns { + display: flex; gap: 2px; flex-shrink: 0; +} +.reh-imsdb-view-btn { + background: none; border: 1px solid var(--border); border-radius: 6px; + padding: 4px 8px; cursor: pointer; color: var(--subtext); font-size: 15px; + transition: background .12s, color .12s; +} +.reh-imsdb-view-btn:hover { background: var(--panel); color: var(--text); } +.reh-imsdb-view-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; } + +/* Loading spinner */ +@keyframes reh-spin { to { transform: rotate(360deg); } } +.reh-imsdb-spinner { + display: inline-block; width: 16px; height: 16px; border-radius: 50%; + border: 2px solid var(--border); border-top-color: var(--accent); + animation: reh-spin .7s linear infinite; flex-shrink: 0; +} + +/* ── Page break marker ──────────────────────────────────────────────────── */ +.reh-block-pagebreak { + display: flex; align-items: center; justify-content: center; + padding: 6px 0; margin: 4px 0; gap: 10px; +} +.reh-block-pagebreak::before, .reh-block-pagebreak::after { + content: ''; flex: 1; height: 1px; background: var(--border); +} +.reh-pagebreak-label { + font-size: 10px; color: var(--subtext); white-space: nowrap; letter-spacing: .04em; +} + +/* ── Scroll mode (no A4 paper) ──────────────────────────────────────────── */ +.reh-page-wrap:not(.paginated) .reh-a4-page { + box-shadow: none; border: none; border-radius: 0; min-height: unset; + padding: 24px 32px; +} + +/* ── Train Mode ─────────────────────────────────────────────────────────── */ +.reh-train-panel { + display: flex; flex-direction: column; gap: 10px; + padding: 12px 16px 16px; +} +.reh-train-header { + display: flex; align-items: center; gap: 10px; flex-shrink: 0; +} +.reh-train-badge { + display: inline-flex; align-items: center; gap: 5px; + font-size: 11px; font-weight: 800; letter-spacing: .08em; + color: var(--accent); background: rgba(37,99,235,.1); + border: 1px solid rgba(37,99,235,.25); border-radius: 6px; padding: 3px 10px; +} +.reh-train-progress { font-size: 13px; color: var(--subtext); font-variant-numeric: tabular-nums; } +.reh-train-cue, .reh-train-myline, .reh-train-rec, .reh-train-result { flex-shrink: 0; } +.reh-train-cue.no-cue { border-style: dashed; opacity: .7; } +.reh-train-cue.no-cue .reh-train-cue-text { color: var(--subtext); font-style: italic; } +.reh-train-cue-head, .reh-train-myline-head { + display: flex; align-items: center; gap: 8px; margin-bottom: 8px; +} +.reh-train-cue-avatar { display: inline-flex; flex-shrink: 0; } +.reh-train-cue-speaker { font-size: 13px; font-weight: 700; color: var(--text); } +.reh-train-cue-tag { + font-size: 10px; font-weight: 700; letter-spacing: .06em; + background: rgba(37,99,235,.1); color: var(--accent); + border-radius: 4px; padding: 1px 7px; margin-left: 2px; +} +.reh-train-me-tag { background: rgba(16,185,129,.1); color: var(--green); } +.reh-train-cue-state { margin-left: auto; font-size: 12px; } +.reh-train-cue-text { font-size: 14px; line-height: 1.55; } +.reh-train-cue-block { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; } +.reh-train-cue-block:last-child { margin-bottom: 0; } +.reh-train-cue-who { font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; } +.reh-train-cue-line { font-style: italic; color: var(--subtext); } +.reh-train-my-text { font-size: 16px; color: var(--text); line-height: 1.6; font-weight: 600; min-height: 2em; } +.reh-train-rec-head { + display: flex; align-items: center; gap: 10px; font-size: 13px; font-weight: 600; + color: var(--text); margin-bottom: 6px; +} +.reh-train-rec-state { flex: 1; } +.reh-train-rec-timer { font-variant-numeric: tabular-nums; color: var(--red); font-weight: 700; font-size: 13px; } +.reh-train-meters { margin-top: 6px; } +.reh-train-result-head { + display: flex; align-items: center; gap: 8px; + font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 10px; +} +.reh-train-score { margin-left: auto; font-size: 15px; } +.reh-train-compare-row { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; flex-wrap: wrap; } +.reh-train-compare-lbl { font-size: 11px; font-weight: 700; color: var(--subtext); white-space: nowrap; min-width: 58px; } +.reh-train-compare-text { font-size: 14px; line-height: 1.7; flex: 1; } +.tw-ok { color: var(--green); } +.tw-miss { color: var(--red); text-decoration: line-through; } +.tw-extra{ color: #f59e0b; } +.reh-train-controls { + display: flex; align-items: center; justify-content: center; gap: 10px; + margin-top: 4px; flex-shrink: 0; padding: 8px 0; + border-top: 1px solid var(--border); +} +.reh-train-rec-btn { color: var(--red) !important; } +.reh-impex-cat { font-size: 13px; font-weight: 700; color: var(--subtext); text-transform: uppercase; letter-spacing: .05em; margin: 16px 0 10px; } +.reh-impex-note { font-size: 12px; color: var(--subtext); margin: -4px 0 10px; } +.reh-impex-grid { display: flex; flex-wrap: wrap; gap: 10px; } +.reh-impex-btn { + display: inline-flex; flex-direction: column; align-items: center; justify-content: center; + gap: 6px; padding: 14px 18px; min-width: 100px; + background: var(--card-bg); border: 1px solid var(--border); border-radius: 10px; + color: var(--text); font-size: 12px; font-weight: 600; cursor: pointer; + transition: border-color .15s, background .15s; text-align: center; +} +.reh-impex-btn .mdi { font-size: 22px; color: var(--accent); } +.reh-impex-btn:hover { border-color: var(--accent); background: rgba(var(--accent-rgb),.07); } +.reh-impex-btn--accent { border-color: rgba(var(--accent-rgb),.35); } + +/* Library */ +.reh-lib-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; } +.reh-lib-list { display: flex; flex-direction: column; gap: 8px; } +.reh-lib-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 28px 0; color: var(--subtext); } +.reh-lib-empty .mdi { font-size: 36px; opacity: .4; } +.reh-lib-empty p { text-align: center; font-size: 13px; line-height: 1.5; margin: 0; } +.reh-lib-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; flex-wrap: wrap; } + +/* Phase 2 backend row */ +.reh-cast2-backend { display: flex; gap: 10px; align-items: flex-end; margin-bottom: 14px; flex-wrap: wrap; } +.reh-narrator-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; margin-bottom: 8px; border-top: 1px solid var(--border); flex-wrap: wrap; } +.reh-cast-instruct-wrap { padding: 0 12px 8px; margin-top: -4px; } +.reh-cast-instruct { width: 100%; font-size: 11px; padding: 4px 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--subtext); font-family: var(--font); } +.reh-cast-instruct:focus { outline: none; border-color: var(--accent); color: var(--text); } +.reh-lib-current { border-color: var(--accent); background: rgba(137,180,250,.06); } +.reh-lib-row-main { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; } +.reh-lib-avatars { display: flex; gap: 4px; flex-shrink: 0; } +.reh-lib-info { min-width: 0; flex: 1; } +.reh-lib-info strong { display: block; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.reh-lib-progress-wrap { height: 3px; background: var(--border); border-radius: 2px; overflow: hidden; margin-top: 5px; } +.reh-lib-progress { height: 100%; background: var(--accent); } +.reh-lib-row-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; } + +/* Phase 1 */ +.reh-new-script-head { + display: flex; align-items: center; gap: 14px; margin-bottom: 6px; flex-wrap: wrap; +} +.reh-script-title-inline { + flex: 1; min-width: 160px; max-width: 360px; + height: 32px; padding: 0 10px; border: 1px solid var(--border); border-radius: 6px; + background: var(--input-bg, var(--surface)); color: var(--text); font-size: 14px; + font-weight: 600; transition: border-color .15s; +} +.reh-script-title-inline:focus { outline: none; border-color: var(--accent); } +.reh-input-row { display: grid; grid-template-columns: 1fr 200px; gap: 14px; align-items: start; } +.reh-input-row textarea { min-height: 220px; font-family: monospace; font-size: 13px; width: 100%; resize: vertical; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 10px; color: var(--text); } +.reh-input-side { display: flex; flex-direction: column; gap: 8px; } + +/* ── Cast list: toolbar + Card/List view toggle ───────────────────────────── */ +.reh-cast-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; } +.reh-cast-count { font-size: 13px; color: var(--subtext); font-weight: 600; } +.reh-view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; background: var(--panel); } +.reh-view-btn { display: inline-flex; align-items: center; gap: 5px; padding: 7px 14px; border: none; background: transparent; color: var(--subtext); font-size: 13px; font-weight: 600; cursor: pointer; font-family: var(--font); transition: background .12s, color .12s; } +.reh-view-btn + .reh-view-btn { border-left: 1px solid var(--border); } +.reh-view-btn:hover { color: var(--text); } +.reh-view-btn.active { background: var(--accent); color: #fff; } +.reh-view-btn .mdi { font-size: 16px; } +.reh-cast-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; flex: 1; min-width: 0; justify-content: center; } +.reh-cast-ctl { font-size: 13px; padding: 6px 9px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font-family: var(--font); } +.reh-cast-ctl:focus { outline: none; border-color: var(--accent); } +.reh-cast-search { min-width: 150px; flex: 1 1 150px; max-width: 240px; } +.reh-cast-sortdir { display: inline-flex; align-items: center; justify-content: center; width: 34px; padding: 6px; cursor: pointer; color: var(--subtext); } +.reh-cast-sortdir:hover { color: var(--accent); border-color: var(--accent); } +.reh-cast-sortdir .mdi { font-size: 17px; } + +/* ── Cast cards (shared) ──────────────────────────────────────────────────── */ +.reh-cast-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; display: flex; flex-direction: column; transition: border-color .15s, opacity .15s, box-shadow .15s; } +.reh-cast-card.reh-cast-narrator { border-color: var(--accent); } +.reh-cast-card.reh-cast-ignored { opacity: .5; } +.reh-cast-card.reh-cast-hidden-c { outline: 1px dashed var(--border); } +.reh-cc-head { display: flex; gap: 12px; } +.reh-cc-avatar { flex-shrink: 0; } +/* rounded-square portrait (not a circle) — overrides the inline border-radius:50% */ +.reh-cc-avatar .reh-char-img, .reh-cc-avatar span, .reh-cc-avatar img { width: 64px !important; height: 64px !important; font-size: 28px !important; border-radius: 12px !important; } +.reh-cc-titles { flex: 1; min-width: 0; } +.reh-cc-name { font-size: 16px; font-weight: 800; line-height: 1.15; white-space: normal; overflow-wrap: anywhere; word-break: break-word; } +.reh-cc-sub { font-size: 12px; color: var(--subtext); margin-top: 3px; line-height: 1.3; } +.reh-cc-voicechip { display: inline-flex; align-items: center; gap: 5px; margin-top: 7px; font-size: 11px; font-weight: 600; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); padding: 3px 9px; border-radius: 999px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.reh-cc-voicechip.empty { color: var(--subtext); background: var(--surface); } +.reh-cc-sample-btn { margin-top: 7px; display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); color: var(--accent); cursor: pointer; font-family: var(--font); transition: background .12s; } +.reh-cc-sample-btn:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); } +.reh-cc-sample-btn.playing { background: var(--accent); color: #fff; } +.reh-cc-sample-btn.loading { pointer-events: none; opacity: .8; } +.reh-cc-sample-btn.loading .mdi { animation: spin .8s linear infinite; } +.reh-cc-sample-btn .mdi { font-size: 13px; } +.reh-cc-voicechip .mdi { font-size: 13px; } +.reh-cc-occupation { font-size: 11.5px; color: var(--subtext); font-style: italic; margin-top: 2px; line-height: 1.3; } +.reh-cc-emotions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 7px; } +.reh-cc-emo-chip { + font-size: 10.5px; font-weight: 600; padding: 2px 7px; border-radius: 999px; + background: var(--panel); border: 1px solid var(--border); color: var(--text); white-space: nowrap; +} +.reh-cc-actions { display: flex; align-items: center; gap: 5px; } +.reh-cc-actions-spacer { flex: 1; } +.reh-cc-me-row { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--subtext); cursor: pointer; white-space: nowrap; } +.reh-cc-me-row:hover { color: var(--text); } +.reh-cc-me-row .mdi { font-size: 15px; } +.reh-cc-extra { display: flex; flex-direction: column; gap: 8px; } + +/* ── Card view: "character card" look ─────────────────────────────────────── */ +.reh-cast-view-card { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px; } +.reh-cast-view-card .reh-cast-card { overflow: hidden; } +.reh-cast-view-card .reh-cast-card:hover { box-shadow: 0 6px 22px rgba(0,0,0,.10); } +.reh-cast-view-card .reh-cc-head { flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: 22px 18px 16px; background: linear-gradient(180deg, color-mix(in srgb, var(--cc-color, var(--accent)) 24%, var(--panel)), var(--panel)); border-bottom: 1px solid var(--border); } +.reh-cast-view-card .reh-cc-titles { flex: none; display: flex; flex-direction: column; align-items: center; } +.reh-cast-view-card .reh-cc-avatar .reh-char-img, .reh-cast-view-card .reh-cc-avatar span, .reh-cast-view-card .reh-cc-avatar img { width: 104px !important; height: 104px !important; font-size: 44px !important; border-width: 3px !important; box-shadow: 0 4px 14px rgba(0,0,0,.20); } +.reh-cast-view-card .reh-cc-name { font-size: 22px; } +.reh-cast-view-card .reh-cc-actions { padding: 10px 16px; border-bottom: 1px solid var(--border); } +.reh-cast-view-card .reh-cc-body { padding: 14px 16px 16px; gap: 10px; } + +/* ── List view: compact rows ──────────────────────────────────────────────── */ +.reh-cast-view-list { display: flex; flex-direction: column; gap: 8px; } +.reh-cast-view-list .reh-cast-card { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 14px; padding: 10px 14px; border-radius: 10px; } +.reh-cast-view-list .reh-cc-head { flex: 1; min-width: 200px; align-items: center; gap: 12px; padding: 0; background: none; border: none; } +.reh-cast-view-list .reh-cc-avatar .reh-char-img, .reh-cast-view-list .reh-cc-avatar span, .reh-cast-view-list .reh-cc-avatar img { width: 52px !important; height: 52px !important; font-size: 22px !important; } +.reh-cast-view-list .reh-cc-titles { flex: 1; } +.reh-cast-view-list .reh-cc-name { font-size: 16px; } +.reh-cast-view-list .reh-cc-voicechip { margin-top: 4px; } +.reh-cast-view-list .reh-cc-body { order: 2; flex: 0 0 240px; padding: 0; } +.reh-cast-view-list .reh-cc-extra { display: none; } /* full editor lives in Card view */ +.reh-cast-view-list .reh-cc-voice > label { display: none; } +.reh-cast-view-list .reh-cc-actions { order: 3; padding: 0; } +.reh-cast-view-list .reh-cc-actions-spacer { display: none; } +@media (max-width: 620px) { + .reh-cast-view-list .reh-cc-body { flex-basis: 100%; } +} +/* ── Online voice picker (try / alternatives / agree) ─────────────────────── */ +.reh-cc-online { border: 1px solid var(--border); border-radius: 9px; background: var(--surface); padding: 9px; display: flex; flex-direction: column; gap: 7px; } +.reh-cc-online-head { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--subtext); display: flex; align-items: center; gap: 6px; } +.reh-vo-toggle { margin-left: auto; background: none; border: none; color: var(--accent); font-size: 11px; font-weight: 700; cursor: pointer; font-family: inherit; } +.reh-vo-list { display: flex; flex-direction: column; gap: 6px; } +.reh-vo-row { display: flex; align-items: center; gap: 8px; padding: 6px 7px; border-radius: 7px; border: 1px solid transparent; } +.reh-vo-row.current { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); } +.reh-vo-play { flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border); background: var(--panel); color: var(--accent); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; transition: all .12s; } +.reh-vo-play:hover { border-color: var(--accent); } +.reh-vo-play.playing { background: var(--accent); color: #fff; border-color: var(--accent); } +.reh-vo-info { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.2; } +.reh-vo-name { font-size: 13px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.reh-vo-meta { font-size: 10px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.reh-vo-badge { flex-shrink: 0; font-size: 11px; font-weight: 700; color: var(--accent); display: inline-flex; align-items: center; gap: 3px; } +.reh-vo-use { flex-shrink: 0; } +.reh-vo-play.loading { pointer-events: none; } +.reh-vo-play.loading .mdi { animation: spin .8s linear infinite; } +/* change-voice tools (library / online search) */ +.reh-vo-tools { display: flex; gap: 6px; } +.reh-vo-tool { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px; padding: 6px 8px; font-size: 12px; font-weight: 600; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--subtext); cursor: pointer; font-family: inherit; transition: all .12s; } +.reh-vo-tool:hover { color: var(--text); border-color: var(--accent); } +.reh-vo-tool.active { color: var(--accent); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--panel)); } +.reh-vo-tool-panel { display: flex; flex-direction: column; gap: 7px; } +.reh-vo-search-row { display: flex; gap: 6px; } +.reh-vo-search-row .reh-vo-search-input { flex: 1; } +.reh-vo-local-input, .reh-vo-search-input { width: 100%; padding: 7px 9px; font-size: 12px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--text); font-family: inherit; } +.reh-vo-local-input:focus, .reh-vo-search-input:focus { outline: none; border-color: var(--accent); } +.reh-vo-results { display: flex; flex-direction: column; gap: 6px; max-height: 230px; overflow-y: auto; } +.reh-vo-hint { font-size: 11px; color: var(--subtext); padding: 4px 2px; display: flex; align-items: center; gap: 6px; } +.reh-cc-iconbtn { width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--subtext); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; transition: all .12s; } +.reh-cc-iconbtn:hover { color: var(--text); border-color: var(--accent); } +.reh-cc-iconbtn.active { background: var(--accent); color: #fff; border-color: var(--accent); } +.reh-cc-del:hover { color: var(--red); border-color: var(--red); } +.reh-cc-body { display: flex; flex-direction: column; gap: 8px; } +.reh-cc-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; } +.reh-cc-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; } +.reh-cc-field > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--subtext); } +.reh-cc-field select, .reh-cc-field input { width: 100%; min-width: 0; font-size: 12px; padding: 5px 7px; border: 1px solid var(--border); border-radius: 5px; background: var(--surface); color: var(--text); font-family: var(--font); } +.reh-cc-voice .vp-root { width: 100%; min-width: 0; flex: 1 1 auto; } +.reh-cc-voice .vp-trigger { min-height: 30px; font-size: 12px; } +.reh-cc-voice .vp-drop { max-height: 310px; z-index: 80; } +.reh-cc-field select:focus, .reh-cc-field input:focus { outline: none; border-color: var(--accent); } +.reh-cc-soul { border-top: 1px solid var(--border); padding-top: 6px; } +.reh-cc-soul > summary { font-size: 11px; font-weight: 600; color: var(--subtext); cursor: pointer; display: flex; align-items: center; gap: 6px; list-style: none; } +.reh-cc-soul > summary::-webkit-details-marker { display: none; } +.reh-cc-develop { margin-left: auto; padding: 2px 8px; font-size: 11px; } +.reh-cc-soul-text { width: 100%; margin-top: 6px; min-height: 64px; resize: vertical; font-size: 12px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 5px; background: var(--surface); color: var(--text); font-family: var(--font); line-height: 1.45; } +.reh-cc-soul-text:focus { outline: none; border-color: var(--accent); } +.reh-cc-more { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 2px; } +/* Cast card reusing the exact Library card (_charCardHtml) — no extra + border/shadow around it, its own 16px-radius styling already stands + alone; the Rehearser-only controls strip sits directly under it. */ +.reh-cast-card-libcard { background: none; border: none; box-shadow: none; } +.reh-cast-card-libcard .lib-char-card { cursor: pointer; } +.reh-cast-card-libcard .lib-char-select { display: none; } +.reh-cast-card-libcard > .reh-cc-body { padding: 12px 4px 4px; } +.reh-cc-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } +.reh-cc-more > summary { font-size: 11.5px; font-weight: 700; color: var(--subtext); cursor: pointer; display: flex; align-items: center; gap: 6px; list-style: none; } +.reh-cc-more > summary::-webkit-details-marker { display: none; } +.reh-cc-more[open] > summary { color: var(--accent); margin-bottom: 8px; } +.reh-cc-more .reh-cc-extra { margin-top: 8px; } + + +.reh-tb-btn { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--border); background: var(--panel); color: var(--text); cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; transition: background .15s; } +.reh-tb-btn:hover { background: var(--border); } +.reh-tb-play { background: var(--accent); color: #fff; border-color: var(--accent); font-size: 18px; } +.reh-tb-play:hover { opacity: .85; } +.reh-btn-active { background: var(--accent) !important; color: #fff !important; border-color: var(--accent) !important; } +.reh-tb-progress-wrap { flex: 1; height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; } +.reh-tb-progress { height: 100%; background: var(--accent); width: 0%; transition: width .3s ease; } +.reh-tb-label { font-size: 12px; color: var(--subtext); white-space: nowrap; font-variant-numeric: tabular-nums; } + +/* Stage: script page + character sidebar (same .ab-cv-side look Read Aloud's + Casting view uses). The sidebar sticks in place while the script scrolls. */ +.reh-stage-area { display: flex; gap: 12px; align-items: flex-start; transition: none; } +.reh-stage-area .reh-page-wrap { flex: 1; min-width: 0; } +.reh-stage-area .ab-cv-side { + width: 220px; flex-shrink: 0; position: sticky; top: 12px; + max-height: calc(100vh - 160px); +} +.reh-stage-area.side-collapsed .ab-cv-side { width: 44px; } +.reh-stage-area .ab-cv-side .ab-cv-chars { flex: 1; overflow-y: auto; } +@media (max-width: 767px) { + /* The sidebar was a fixed 220px column next to the script page — on a + phone-width viewport that left almost no room for the page itself. + Stack the sidebar above the page instead, collapsible the same way it + already is on desktop, just full-width instead of a narrow rail. */ + .reh-stage-area { flex-direction: column; } + .reh-stage-area .ab-cv-side { width: 100%; position: static; max-height: 220px; order: -1; } + .reh-stage-area.side-collapsed .ab-cv-side { width: 100%; max-height: 44px; overflow: hidden; } + .reh-page-wrap { padding: 16px 10px; } + .reh-a4-page { padding: 20px 14px; } +} + +/* A4 page */ +.reh-page-wrap { padding: 24px 16px; background: var(--panel); min-height: 60vh; } +.reh-a4-page { + width: min(1180px, 96%); min-height: 400px; + background: #fff; color: #1a1a2e; + padding: 56px 72px; + box-shadow: 0 4px 24px rgba(0,0,0,.18); + margin: 0 auto; + font-family: 'Georgia', 'Times New Roman', serif; + border-radius: 2px; +} +[data-theme="dark"] .reh-a4-page { background: #f8f8f2; color: #1a1a2e; } +.reh-page-title { font-size: 22px; font-weight: 700; text-align: center; margin-bottom: 36px; letter-spacing: .04em; text-transform: uppercase; color: #1a1a2e; border-bottom: 2px solid #1a1a2e; padding-bottom: 12px; } +.reh-script-lines { display: flex; flex-direction: column; gap: 0; } + +/* Each dialog block — flex: gutter | content */ +.reh-block { display: flex; align-items: stretch; padding: 8px 12px 8px 2px; border-left: 3px solid transparent; border-radius: 0 4px 4px 0; margin-bottom: 2px; transition: background .2s, border-color .2s; } +.reh-block-inner { flex: 1; min-width: 0; } +.reh-block-head { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; flex-wrap: nowrap; } +.reh-block-name { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; white-space: nowrap; } +.reh-block-head-spacer { flex: 1; min-width: 8px; } +.reh-block-badge { font-size: 10px; padding: 1px 6px; border-radius: 10px; font-family: sans-serif; flex-shrink: 0; } +.reh-badge-tts { background: rgba(137,180,250,.2); color: #2563eb; } +.reh-badge-me { background: rgba(166,227,161,.25); color: #16a34a; } +.reh-block-dialog { font-size: 15px; line-height: 1.65; padding-left: 40px; color: #1a1a2e; } +.reh-direction { font-style: italic; color: #666; font-size: 13px; padding: 4px 12px; } +.reh-char-img { vertical-align: middle; } +.reh-line-play-avatar { border:0; background:transparent; padding:0; margin:0 2px 0 0; cursor:pointer; border-radius:50%; position:relative; display:inline-flex; align-items:center; justify-content:center; } +.reh-line-play-avatar:hover { box-shadow:0 0 0 3px rgba(37,99,235,.18); } +/* This badge overlay is meant to sit in the corner of the bigger avatar + circle (dialogue's own play button) — .reh-action-play-btn (the plain + narrator play button, no avatar underneath) also carries the shared + .reh-line-play-avatar class for click wiring, so it was ALSO getting + this badge layered on top of its own inline icon: two visibly different + play icons stacked on one small button. Excluded here; it's styled to + look like this same badge directly instead (one icon, not two). */ +.reh-line-play-avatar:not(.reh-action-play-btn)::after { content:'\F040A'; font-family:'Material Design Icons'; position:absolute; right:-5px; bottom:-5px; width:16px; height:16px; border-radius:50%; background:var(--accent); color:#fff; font-size:11px; display:flex; align-items:center; justify-content:center; box-shadow:0 1px 4px rgba(0,0,0,.24); } +.reh-line-active .reh-line-play-avatar:not(.reh-action-play-btn)::after { content:'\F03E4'; background:var(--red); } + +/* Narrator paragraph play button — no avatar image underneath, so styled + to look like the same small blue circular badge dialogue's own play + button already shows (see the ::after rule above), just as its own real + icon instead of a badge layered over something else. */ +.reh-action-play-btn { + width: 16px; height: 16px; margin: 0 5px 0 0; vertical-align: middle; + border: none; color: #fff; font-size: 11px; + background: var(--accent); flex-shrink: 0; +} +.reh-action-play-btn:hover { box-shadow: 0 0 0 3px rgba(37,99,235,.18); } +.reh-line-active .reh-action-play-btn { background: var(--red); } + +/* Gutter: narrow play/range column left of each dialog block */ +.reh-gutter-btn { width:22px; min-width:22px; flex-shrink:0; align-self:stretch; background:none; border:none; cursor:pointer; display:flex; align-items:center; justify-content:center; color:transparent; transition:color .12s; font-size:9px; padding:0; margin-right:4px; } +.reh-block:hover .reh-gutter-btn { color:var(--accent); } +.reh-range-start .reh-gutter-btn { color:#10b981 !important; } +.reh-range-end .reh-gutter-btn { color:#ef4444 !important; } +.reh-in-range { background:rgba(245,158,11,.05) !important; } +.reh-range-start { border-left-color:#10b981 !important; } +.reh-range-end { border-left-color:#ef4444 !important; } +.reh-practice-info { display:none; align-items:center; gap:3px; font-size:10px; color:var(--subtext); white-space:nowrap; margin-left:6px; } +.reh-practice-info.visible { display:inline-flex; } + +/* ── Bulk-edit (line selection) ───────────────────────────────────────────── */ +.reh-bulk-bar { + display:flex; align-items:center; gap:6px; flex-wrap:wrap; + padding:6px 10px; margin:6px 0; border:1px solid var(--border); border-radius:8px; + background:var(--panel); position:sticky; top:0; z-index:6; +} +.reh-bulk-count { font-size:12px; font-weight:700; color:var(--accent); min-width:74px; } +.reh-bulk-sep { width:1px; align-self:stretch; background:var(--border); margin:2px 2px; } +.reh-bulk-spacer{ flex:1; } +/* Leading checkbox in front of each line */ +.reh-bulk-check { + display:none; align-items:center; justify-content:center; flex-shrink:0; + width:26px; cursor:pointer; color:var(--subtext); font-size:20px; align-self:center; +} +.reh-bulk-mode .reh-bulk-check { display:inline-flex; } +.reh-bulk-check.checked { color:var(--accent); } +.reh-bulk-check:hover { color:var(--accent); } +/* Non-dialog blocks: keep the checkbox inline at the start */ +.reh-bulk-mode .reh-act, +.reh-bulk-mode .reh-scene, +.reh-bulk-mode .reh-action-block, +.reh-bulk-mode .reh-transition, +.reh-bulk-mode .reh-direction, +.reh-bulk-mode .reh-block-pagebreak { position:relative; } +/* Ignored lines: greyed out but still visible */ +.reh-line-ignored { opacity:.42; filter:grayscale(1); } +.reh-line-ignored .reh-block-dialog { text-decoration:line-through; text-decoration-color:rgba(0,0,0,.3); } +/* Hidden lines revealed in bulk mode: dashed, dimmed */ +.reh-line-hidden { opacity:.5; outline:1px dashed var(--border); outline-offset:-2px; } + +/* Active line */ +.reh-block-active { background: rgba(37,99,235,.07); border-left-color: #2563eb; } +.reh-block-active .reh-block-dialog { font-weight: 500; } + +/* Emotion picker button */ +.reh-emo-btn { font-size:11px; border:1px solid rgba(0,0,0,.15); border-radius:4px; padding:2px 6px; background:rgba(0,0,0,.03); color:#555; cursor:pointer; margin-left:auto; flex-shrink:0; font-family:sans-serif; display:inline-flex; align-items:center; gap:3px; white-space:nowrap; max-width:115px; overflow:hidden; } +.reh-emo-btn:hover { border-color:var(--accent); } +.reh-emo-btn.has-emotion { background:rgba(37,99,235,.07); color:#1a1a2e; border-color:rgba(37,99,235,.3); font-weight:600; } +.reh-emo-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:72px; } + +/* Emotion picker popover */ +.reh-emo-popover { background:var(--bg); border:1px solid var(--border); border-radius:8px; box-shadow:0 8px 32px rgba(0,0,0,.18); overflow:hidden; } +.reh-emo-pop-inner { display:flex; flex-direction:column; max-height:300px; } +.reh-emo-search { padding:8px 10px; border:none; border-bottom:1px solid var(--border); background:var(--surface); font-size:12px; outline:none; color:var(--text); width:100%; box-sizing:border-box; } +.reh-emo-list { overflow-y:auto; flex:1; padding:4px; } +.reh-emo-item { display:flex; align-items:center; gap:8px; padding:5px 8px; border-radius:4px; cursor:pointer; font-size:12px; color:var(--text); } +.reh-emo-item:hover { background:var(--panel); } +.reh-emo-item.selected { background:rgba(37,99,235,.1); color:var(--accent); font-weight:600; } +.reh-emo-item-emoji { font-size:15px; flex-shrink:0; } +.reh-emo-custom-row { padding:6px; border-top:1px solid var(--border); } + +/* Markdown formatting toolbar */ +.reh-fmt-toolbar { display:flex; gap:3px; align-items:center; padding:4px 6px; background:var(--panel); border:1px solid var(--border); border-bottom:none; border-radius:3px 3px 0 0; flex-wrap:wrap; } +.reh-fmt-btn { padding:2px 8px; border:1px solid var(--border); border-radius:3px; background:var(--surface); cursor:pointer; font-size:12px; color:var(--text); line-height:1.4; } +.reh-fmt-btn:hover { background:var(--border); } +.reh-fmt-hint { font-size:10px; color:var(--subtext); margin-left:auto; font-style:italic; } + +/* Markdown inside A4 */ +.reh-a4-page strong, .reh-paper strong { font-weight:700; } +.reh-a4-page em, .reh-paper em { font-style:italic; } +.reh-a4-page u, .reh-paper u { text-decoration:underline; } +.reh-a4-page del, .reh-paper del { text-decoration:line-through; opacity:.65; } +.reh-a4-page .reh-hl, .reh-paper .reh-hl { background:#fef3c7; border-radius:2px; padding:0 1px; } + +/* Word-level highlight during playback */ +.reh-word { display:inline; border-radius:2px; transition:background .06s, color .06s; } +.reh-word-active { background:rgba(37,99,235,.22); color:#1a1a2e; border-radius:2px; padding:0 1px; } + +/* ── Proper screenplay A4 formatting ─────────────────────────────────── */ +/* Use Courier New throughout — 1 page ≈ 1 minute of screen time */ +/* Base play font size. Everything below is expressed in `em` so the whole + play scales together via --reh-stage-scale (the +A / -A control). */ +.reh-a4-page { + font-family: 'Courier New', Courier, monospace !important; + font-size: calc(12pt * var(--reh-stage-scale, 1)); + line-height: 1.6; +} +.reh-page-title { + font-family: 'Courier New', Courier, monospace; + font-size: 1.17em; +} +/* Scene headings: all-caps, bold, with spacing */ +.reh-scene { + font-size: 1em; + letter-spacing: .04em; +} +/* Narrator / action text and spoken dialog share ONE size (1em) so the play + reads evenly — no narrator-vs-dialogue size mismatch. */ +.reh-action-block { font-size: 1em; } +.reh-action-text { font-size: 1em; } + +/* Act headings: larger, extra top space */ +.reh-act { font-size: 1.08em; } + +/* Transitions: right-aligned */ +.reh-transition { font-size: 1em; } + +/* Dialog block — screenplay format */ +.reh-block-name { + font-size: 0.92em; + letter-spacing: .1em; +} +.reh-block-dialog { + font-size: 1em; + padding-left: 32px; /* ~1.5" dialog indent */ + max-width: 440px; /* ~3.5" dialog column width */ +} +/* Parenthetical directions: centered-ish */ +.reh-direction { + font-size: 0.92em; + padding-left: 80px; + color: #444; +} + +/* Script editor modal */ +.reh-modal-overlay { position:fixed; inset:0; z-index:2000; background:rgba(0,0,0,.45); display:flex; align-items:center; justify-content:center; padding:16px; } +.reh-modal-overlay[hidden] { display: none !important; } +.reh-modal-box { background:var(--bg); border-radius:10px; box-shadow:0 20px 60px rgba(0,0,0,.3); overflow:hidden; display:flex; flex-direction:column; } +.reh-modal-head { display:flex; align-items:center; justify-content:space-between; padding:12px 16px; border-bottom:1px solid var(--border); font-weight:700; } + +/* TTS status bar */ +.reh-tts-status-bar { display: flex; align-items: center; gap: 12px; padding: 8px 16px; background: var(--panel); border-top: 1px solid var(--border); font-size: 13px; } +.reh-tts-status-bar[hidden] { display: none; } + +/* Recording overlay */ +.reh-rec-overlay { + position: sticky; bottom: 0; z-index: 60; + background: var(--bg); border-top: 2px solid var(--green); + box-shadow: 0 -4px 20px rgba(0,0,0,.15); +} +.reh-rec-overlay[hidden] { display: none; } +.reh-rec-overlay-inner { padding: 14px 20px; max-width: 860px; margin: 0 auto; } +.reh-rec-cue { font-size: 14px; margin-bottom: 10px; line-height: 1.5; } +.reh-rec-cue-name { font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .1em; } +.reh-rec-cue-text { font-size: 17px; margin-top: 4px; padding: 8px 12px; background: rgba(166,227,161,.1); border-left: 3px solid var(--green); border-radius: 0 4px 4px 0; font-style: italic; } +.reh-rec-inner { padding: 14px 20px; max-width: 860px; margin: 0 auto; } + +/* Summary */ +.reh-summary-list { display: flex; flex-direction: column; gap: 10px; } +.reh-summary-row { display: flex; align-items: flex-start; gap: 10px; padding: 10px; background: var(--panel); border-radius: 6px; } + +/* Console / sticky transport bar */ +.reh-console { + position: sticky; top: 0; z-index: 50; + background: var(--bg); border-bottom: 1px solid var(--border); + display: flex; align-items: center; gap: 10px; padding: 7px 14px; flex-wrap: wrap; +} +.reh-console-transport { display: flex; gap: 4px; align-items: center; flex-shrink: 0; } +.reh-console-progress { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 80px; } +/* flex-shrink:0 with the flexbox-default min-width:auto meant this block could + never shrink below its unwrapped natural width (confirmed live: ~1560px of + buttons in a 524px-wide bar) — flex-wrap never got a chance to kick in since + the item was never considered "too wide to fit" by the wrapping algorithm, + so on any real (non-ultrawide) window the tail of the toolbar — font size, + page mode, Train, Exit — silently fell off-screen with no scrollbar to + reach it. Allowing it to shrink (and explicitly zeroing min-width, since + flex items default to min-width:auto regardless of any width you set) lets + it wrap onto additional rows within the available space instead. */ +.reh-console-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 1; min-width: 0; flex-wrap: wrap; } + +/* Synth progress bar */ +/* Tone / style backend warning bar */ +.reh-tone-warn { + display: flex; align-items: flex-start; gap: 8px; padding: 7px 14px; + background: rgba(234,179,8,.1); border-bottom: 1px solid rgba(234,179,8,.35); + font-size: 12px; color: #92400e; +} +.reh-tone-warn[hidden] { display: none; } +.reh-tone-warn .mdi { color: #d97706; font-size: 14px; flex-shrink: 0; } +/* Aligns the alert icon with the table's own text baseline rather than the + whole (now taller, multi-row) bar. */ +.reh-tone-warn > .mdi { margin-top: 3px; } +.reh-tone-warn-close { + margin-left: auto; background: none; border: none; cursor: pointer; + color: #92400e; font-size: 13px; line-height: 1; padding: 2px 4px; border-radius: 3px; + opacity: .7; flex-shrink: 0; +} +.reh-tone-warn-close:hover { opacity: 1; background: rgba(0,0,0,.06); } + +/* Backend tone/identity comparison table — replaced a run-on sentence with a + button wedged mid-clause (confirmed live: read badly and wrapped worse). + Same two facts, laid out as two columns instead of two clauses. */ +.reh-tone-cmp { border-collapse: collapse; font-size: 12px; } +.reh-tone-cmp th { + text-align: left; font-weight: 600; padding: 2px 14px 4px 0; color: #92400e; + opacity: .75; white-space: nowrap; +} +.reh-tone-cmp td { padding: 3px 14px 3px 0; white-space: nowrap; } +.reh-tone-cmp tr:first-child td { padding-top: 0; } +.reh-tone-cmp-current td:first-child { font-weight: 700; } +.reh-tone-cmp-current-tag { + font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; + color: #92400e; opacity: .7; +} +.reh-tone-cmp-yes { color: #15803d; } +.reh-tone-cmp-no { color: #b91c1c; opacity: .8; } +.reh-tone-cmp-yes .mdi, .reh-tone-cmp-no .mdi { font-size: 13px; } +.reh-tone-switch-btn { padding: 2px 10px !important; font-size: 11px !important; } +.reh-tone-cmp-note { margin: 4px 0 0; font-size: 11.5px; opacity: .85; } + +/* Synth progress bar — more prominent while running */ +.reh-synth-bar { + display: flex; align-items: center; gap: 10px; padding: 7px 16px; + background: linear-gradient(90deg, rgba(37,99,235,.08), rgba(37,99,235,.04)); + border-bottom: 2px solid rgba(37,99,235,.3); font-size: 12px; + box-shadow: 0 2px 8px rgba(37,99,235,.12); +} +.reh-synth-bar[hidden] { display: none; } +.reh-synth-bar-lbl { + font-size: 11px; font-weight: 700; color: var(--accent); white-space: nowrap; + display: flex; align-items: center; gap: 4px; letter-spacing: .04em; +} +.reh-synth-track { flex: 1; height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; } +.reh-synth-fill { height: 100%; background: linear-gradient(90deg, var(--accent), #7c3aed); width: 0%; transition: width .25s ease; border-radius: 3px; } +.reh-synth-label { font-size: 12px; font-weight: 600; color: var(--accent); white-space: nowrap; min-width: 48px; text-align: right; } + +/* Synthesizing dot — pulsing spinner ring */ +@keyframes reh-synth-pulse { 0%,100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.5); opacity: .5; } } +.reh-synth-dot.synthesizing { + background: var(--accent); + animation: reh-synth-pulse .8s ease-in-out infinite; + box-shadow: 0 0 0 3px rgba(37,99,235,.25); +} + +/* Row highlight while a line is being synthesized */ +.reh-line-synthesizing { + background: rgba(37,99,235,.06) !important; + border-left-color: var(--accent) !important; + transition: background .15s; +} + +/* Play font-size stepper (+A / -A) */ +.reh-fontsize-ctl { display: inline-flex; gap: 2px; } +/* No padding override here on purpose — confirmed live these two buttons + rendered ~18px shorter than every sibling toolbar button (2px 7px vs the + base .btn-secondary.btn-sm's 9px 18px) because this rule fought that + padding instead of inheriting it. Font weight is the only real + customization these need. */ +/* Padding now matches every sibling button exactly, but a residual gap + remained — plain "A" + superscript text computes a shorter natural + line-height than an icon+text button, and guessing at a line-height + multiplier to compensate (tried 1: overshot the other way, to 35.7px + against siblings' 43px) is fragile. Match the sibling toolbar buttons' + actual height directly instead of trying to reverse-engineer it via + line-height. */ +.reh-fontsize-btn { font-weight: 700; height: 43px; display: inline-flex; align-items: center; justify-content: center; } +.reh-fontsize-btn .reh-fontsize-plus, .reh-fontsize-btn .reh-fontsize-minus { font-size: 9px; vertical-align: super; margin-left: 1px; } + +/* Act heading on A4 page */ +.reh-act { + font-family: 'Courier New', Courier, monospace; font-size: 13px; font-weight: 700; + text-transform: uppercase; letter-spacing: .14em; color: #1a1a2e; + margin: 28px 0 8px; padding: 7px 0; text-align: center; + border-top: 2.5px solid #1a1a2e; border-bottom: 2.5px solid #1a1a2e; + cursor: pointer; +} + +/* Chapter marker — a horizontal rule with the chapter's own title/number + between the two halves, so a chapter break is visible while scrolling the + script itself and not just audible as a pause in the exported audiobook. */ +.reh-chapter-marker { + display: flex; align-items: center; gap: 14px; + margin: 32px 0 20px; position: relative; +} +.reh-chapter-marker-line { flex: 1; height: 1px; background: var(--border); } +.reh-chapter-marker-label { + font-weight: 700; text-transform: uppercase; letter-spacing: .08em; + font-size: 13px; color: var(--subtext); white-space: nowrap; padding: 0 2px; +} +.reh-chapter-marker:hover .reh-edit-btn { opacity: 1; } + +/* Inline edit button — shown on hover */ +.reh-edit-btn { + opacity: 0; transition: opacity .12s; border: 1px solid transparent; + background: none; cursor: pointer; font-size: 10px; color: var(--subtext); + padding: 1px 5px; border-radius: 3px; line-height: 1; flex-shrink: 0; +} +.reh-block:hover .reh-edit-btn, +.reh-action-block:hover .reh-edit-btn, +.reh-scene:hover .reh-edit-btn, +.reh-act:hover .reh-edit-btn { opacity: 1; } +.reh-edit-btn:hover { background: var(--panel); border-color: var(--border); color: var(--accent); } + +/* Scene heading on the A4 page */ +.reh-scene { + font-family: 'Courier New', Courier, monospace; font-size: 11.5px; font-weight: 700; + text-transform: uppercase; letter-spacing: .07em; color: #1a1a2e; + margin: 22px 0 8px; padding: 5px 0; + border-top: 1.5px solid #333; border-bottom: 1.5px solid #333; + cursor: pointer; display: flex; align-items: center; gap: 6px; +} +.reh-scene .mdi { font-size: 11px; opacity: .5; flex-shrink: 0; } + +/* Action / description block — 1em so narrator matches spoken dialog and + scales with the +A / -A control. */ +.reh-action-block { + font-family: 'Courier New', Courier, monospace; font-size: 1em; line-height: 1.75; + color: #2c2c3e; padding: 2px 0 10px; cursor: pointer; +} + +/* Transition line */ +.reh-transition { + font-family: 'Courier New', Courier, monospace; font-size: 0.75em; font-weight: 700; + text-align: right; text-transform: uppercase; letter-spacing: .1em; + color: #555; padding: 8px 0; +} + +/* Active line highlight (works on any block type) */ +.reh-line-active.reh-block { background: rgba(37,99,235,.08) !important; border-left-color: var(--accent) !important; } +.reh-line-active.reh-scene { background: rgba(37,99,235,.06) !important; outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 3px; } +.reh-line-active.reh-action-block { background: rgba(37,99,235,.05) !important; padding-left: 6px; border-left: 2px solid var(--accent); } +.reh-line-active.reh-direction { background: rgba(37,99,235,.04) !important; } + +/* Emotion selector on TTS dialog blocks */ +.reh-emotion-sel { + font-size: 10px; border: 1px solid rgba(0,0,0,.18); border-radius: 3px; + padding: 1px 4px; background: rgba(0,0,0,.04); color: #555; + cursor: pointer; margin-left: auto; flex-shrink: 0; font-family: sans-serif; + max-width: 90px; +} +.reh-emotion-sel:hover, .reh-emotion-sel:focus { border-color: var(--accent); outline: none; } +.reh-emotion-sel.has-emotion { background: rgba(37,99,235,.08); color: var(--accent); border-color: var(--accent); font-weight: 600; } + +/* Pre-synthesized dot */ +.reh-synth-dot { + width: 7px; height: 7px; border-radius: 50%; background: var(--green); + flex-shrink: 0; display: inline-block; margin-left: 3px; +} +.reh-synth-dot.stale { + background: var(--red, #ef4444); + box-shadow: 0 0 0 2px rgba(239,68,68,.2); +} + +/* Per-line re-synth button */ +.reh-resynth-btn { + background: none; border: none; cursor: pointer; padding: 2px 4px; + color: var(--red, #ef4444); font-size: 12px; border-radius: 4px; + opacity: .85; transition: opacity .15s, background .15s; + display: inline-flex; align-items: center; +} +.reh-resynth-btn:hover { opacity: 1; background: rgba(239,68,68,.1); } + +/* Note area — right gutter of dialog block (holds edit btn + note btn) */ +.reh-block { position: relative; } +.reh-note-area { + display: flex; flex-direction: column; align-items: flex-end; gap: 2px; + min-width: 28px; flex-shrink: 0; padding-top: 2px; +} +/* Edit button inside note-area gutter */ +.reh-note-area .reh-edit-btn { + opacity: 0; transition: opacity .12s; border: 1px solid transparent; + background: none; cursor: pointer; font-size: 13px; color: var(--subtext); + padding: 3px 5px; border-radius: 4px; line-height: 1; flex-shrink: 0; +} +.reh-block:hover .reh-note-area .reh-edit-btn { opacity: 1; } +.reh-note-area .reh-edit-btn:hover { background: var(--panel); border-color: var(--border); color: var(--accent); } +.reh-note-btn { + background: none; border: none; cursor: pointer; padding: 3px; + font-size: 14px; color: var(--subtext); opacity: .45; border-radius: 4px; + transition: opacity .15s, color .15s; line-height: 1; flex-shrink: 0; +} +.reh-note-btn:hover, .reh-note-btn.has-note { opacity: 1; color: #f59e0b; } +.reh-note-ta { + display: none; width: 160px; min-height: 60px; resize: vertical; + font-size: 11px; font-family: inherit; line-height: 1.45; + padding: 6px 8px; border: 1px solid #f59e0b55; border-radius: 6px; + background: rgba(245,158,11,.06); color: var(--text); outline: none; +} +.reh-note-ta.open { display: block; } +.reh-note-ta:focus { border-color: #f59e0b; background: rgba(245,158,11,.1); } + +@media (max-width: 700px) { + .reh-input-row { grid-template-columns: 1fr; } + .reh-a4-page { padding: 28px 20px; } + .reh-console { gap: 8px; } + .reh-cc-grid { grid-template-columns: 1fr; } +} + +/* ── Phase sub-tabs ─────────────────────────────────────────────────────── */ +.reh-subtabs { + display: flex; gap: 4px; padding: 4px; margin: 0 0 14px; + background: var(--panel); border: 1px solid var(--border); border-radius: 10px; + flex-wrap: wrap; +} +.reh-subtab { + display: inline-flex; align-items: center; gap: 6px; + padding: 7px 14px; border: none; border-radius: 7px; cursor: pointer; + background: transparent; color: var(--subtext); font-size: 13px; font-weight: 600; + transition: background .15s, color .15s; +} +.reh-subtab .mdi { font-size: 16px; } +.reh-subtab:hover:not(:disabled):not(.active) { background: var(--border); color: var(--text); } +.reh-subtab.active { background: var(--surface); color: var(--accent); box-shadow: 0 1px 3px rgba(0,0,0,.08); } +.reh-subtab:disabled { opacity: .4; cursor: not-allowed; } +@media (max-width: 600px) { + .reh-subtab span:not(.mdi) { display: none; } + .reh-subtab { padding: 8px 12px; } +} + +/* ── Studio phase tabs (deliberately separate classes from .reh-subtab — + rehearser.js wires its OWN click listeners onto every .reh-subtab in the + document via querySelectorAll, and every section's HTML is present in the + DOM at once regardless of which is visible, so reusing that class name + here would silently attach Rehearser's phase-switching logic to Studio's + own tab buttons too) ───────────────────────────────────────────────── */ +.stu-subtabs { + display: flex; gap: 4px; padding: 4px; margin: 0 0 14px; + background: var(--panel); border: 1px solid var(--border); border-radius: 10px; + flex-wrap: wrap; +} +.stu-subtab { + display: inline-flex; align-items: center; gap: 6px; + padding: 7px 14px; border: none; border-radius: 7px; cursor: pointer; + background: transparent; color: var(--subtext); font-size: 13px; font-weight: 600; + transition: background .15s, color .15s; +} +.stu-subtab .mdi { font-size: 16px; } +.stu-subtab:hover:not(:disabled):not(.active) { background: var(--border); color: var(--text); } +.stu-subtab.active { background: var(--surface); color: var(--accent); box-shadow: 0 1px 3px rgba(0,0,0,.08); } +.stu-subtab:disabled { opacity: .4; cursor: not-allowed; } +.stu-subtab-num { + display: inline-flex; align-items: center; justify-content: center; + width: 16px; height: 16px; border-radius: 50%; font-size: 10px; font-weight: 700; + background: var(--border); color: var(--subtext); flex-shrink: 0; +} +.stu-subtab.active .stu-subtab-num { background: var(--accent); color: #fff; } +@media (max-width: 600px) { + .stu-subtab span:not(.mdi):not(.stu-subtab-num) { display: none; } + .stu-subtab { padding: 8px 12px; } +} + +/* Nested sub-tabs inside Studio's Characters/Perform phases (smaller, inline) */ +.stu-inner-tabs { display: flex; gap: 4px; margin: 0 0 12px; } +.stu-book-context-btn { + display: inline-flex; align-items: center; gap: 6px; margin-right: 4px; + padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px; + cursor: pointer; background: var(--panel); color: var(--subtext); + font-size: 12.5px; font-weight: 600; +} +.stu-book-context-btn:hover { color: var(--accent); border-color: var(--accent); background: var(--surface); } +.stu-inner-tab { + padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; + background: var(--panel); color: var(--subtext); font-size: 12.5px; font-weight: 600; +} +.stu-inner-tab.active { background: var(--surface); color: var(--accent); border-color: var(--accent); } +.stu-mode-toggle { + display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; + border: 1px solid var(--border); border-radius: 8px; background: var(--panel); + font-size: 13px; font-weight: 600; margin: 0 0 14px; cursor: pointer; +} + +/* ── Auto-design voices (Phase 2) ───────────────────────────────────────── */ +.reh-autodesign { + border: 1px solid var(--border); border-radius: 10px; + padding: 12px 14px; margin: 4px 0 14px; + background: linear-gradient(180deg, rgba(37,99,235,.04), transparent); +} +.reh-autodesign-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; font-size: 13px; } +.reh-autodesign-head .note { font-weight: 400; } +.reh-autodesign-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; } +.reh-autodesign-row input, .reh-autodesign-row select { + width: 100%; padding: 6px 8px; border: 1px solid var(--border); + border-radius: 5px; background: var(--surface); color: var(--text); font-size: 12px; +} +.reh-llm-refresh { border: none; background: none; cursor: pointer; color: var(--accent); font-size: 13px; padding: 0 2px; } +.reh-autodesign-progress { display: flex; align-items: center; gap: 10px; margin-top: 10px; } + +/* Three casting options (local match / online match / design) */ +.reh-cast-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin-top: 12px; } +.reh-cast-opt { display: flex; gap: 10px; padding: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; } +.reh-co-num { flex-shrink: 0; width: 22px; height: 22px; border-radius: 50%; background: var(--accent); color: #fff; font-size: 12px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; } +.reh-co-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; } +.reh-co-body > strong { font-size: 13px; display: flex; align-items: center; gap: 6px; } +.reh-co-body > strong .mdi { color: var(--accent); } +.reh-co-body > p { font-size: 11.5px; color: var(--subtext); line-height: 1.45; margin: 0; } +.reh-co-body > p em { font-style: normal; color: var(--text); font-weight: 600; } +.reh-co-body > button { align-self: flex-start; margin-top: 2px; white-space: nowrap; } + +/* Per-character status pill while designing */ +.reh-cast-designing { opacity: .75; } +.reh-cast-design-badge { + font-size: 10px; padding: 1px 7px; border-radius: 10px; margin-left: 6px; + background: rgba(37,99,235,.12); color: var(--accent); font-weight: 600; +} +.reh-cast-design-badge.done { background: rgba(22,163,74,.15); color: var(--green); } +.reh-cast-design-badge.err { background: rgba(220,38,38,.15); color: var(--red); } + +/* ── Per-character auto-design detail panel ─────────────────────────────── */ +.reh-cast-design-panel { + margin: -4px 12px 8px 12px; padding: 10px 12px; + border: 1px solid rgba(37,99,235,.25); border-radius: 8px; + background: rgba(37,99,235,.05); display: flex; flex-direction: column; gap: 7px; + animation: reh-cdp-in .15s ease-out; +} +@keyframes reh-cdp-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } } +.reh-cast-design-panel.done { + border-color: rgba(22,163,74,.25); background: rgba(22,163,74,.04); +} +.reh-cdp-meta { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; } +.reh-cdp-chip { + font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 10px; + background: var(--panel); border: 1px solid var(--border); color: var(--subtext); + display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; +} +.reh-cdp-gender { color: #8b5cf6; border-color: rgba(139,92,246,.3); background: rgba(139,92,246,.07); } +.reh-cdp-lang { color: #0ea5e9; border-color: rgba(14,165,233,.3); background: rgba(14,165,233,.07); } +.reh-cdp-name { color: var(--accent); border-color: rgba(37,99,235,.3); background: rgba(37,99,235,.07); font-family: monospace; font-size: 10px; } +.reh-cdp-desc { + font-size: 11px; line-height: 1.5; color: var(--text); font-style: italic; + border-left: 2px solid var(--accent); padding-left: 8px; opacity: .85; +} +.reh-cdp-step { + display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--subtext); +} +.reh-cdp-step .reh-imsdb-spinner { border-top-color: var(--accent); } + +/* ── Drag & drop importer ───────────────────────────────────────────────── */ +.reh-dropzone { + margin-top: 14px; padding: 26px 16px; border: 2px dashed var(--border); + border-radius: 12px; text-align: center; color: var(--subtext); + display: flex; flex-direction: column; align-items: center; gap: 5px; + transition: border-color .15s, background .15s; cursor: default; +} +.reh-dropzone-icon { font-size: 34px; opacity: .5; } +.reh-dropzone.dragover { + border-color: var(--accent); background: rgba(37,99,235,.06); color: var(--accent); +} +.reh-dropzone.dragover .reh-dropzone-icon { opacity: 1; } + +/* ── Bookshelf library ──────────────────────────────────────────────────── */ +.reh-bookshelf { + display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 18px 16px; padding: 6px 4px 4px; +} +.sk { 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; } +.lib-book-sk { background: linear-gradient(135deg, var(--panel), var(--border)) !important; opacity: .7; animation: none; cursor: default; } +.lib-book-sk .sk { border-radius: 4px; } +.reh-book { + position: relative; cursor: pointer; border-radius: 4px 7px 7px 4px; + aspect-ratio: 2 / 3; padding: 14px 12px 12px 18px; color: #fff; overflow: hidden; + box-shadow: 0 5px 14px rgba(0,0,0,.22), inset 3px 0 0 rgba(0,0,0,.18); + display: flex; flex-direction: column; + transition: transform .16s ease, box-shadow .16s ease; + background: linear-gradient(135deg, var(--bk1, #4f46e5), var(--bk2, #7c3aed)); +} +.reh-book::before { /* spine highlight */ + content: ''; position: absolute; left: 6px; top: 0; bottom: 0; width: 2px; + background: rgba(255,255,255,.25); +} +.reh-book:hover { transform: translateY(-5px) rotate(-.6deg); box-shadow: 0 12px 26px rgba(0,0,0,.3), inset 3px 0 0 rgba(0,0,0,.18); } +.reh-book-title { + font-size: 14px; font-weight: 800; line-height: 1.25; letter-spacing: .01em; + text-shadow: 0 1px 3px rgba(0,0,0,.35); display: -webkit-box; + -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; +} +.reh-book-meta { margin-top: auto; font-size: 10.5px; opacity: .9; line-height: 1.5; } +.reh-book-avatars { display: flex; gap: 3px; margin-bottom: 6px; flex-wrap: wrap; } +.reh-book-avatars span { + width: 19px; height: 19px; border-radius: 50%; font-size: 9px; font-weight: 700; + display: inline-flex; align-items: center; justify-content: center; + border: 1.5px solid rgba(255,255,255,.7); color: #fff; +} +.reh-book-progress { height: 3px; border-radius: 2px; background: rgba(255,255,255,.28); margin-top: 5px; overflow: hidden; } +.reh-book-progress > div { height: 100%; background: rgba(255,255,255,.9); } +.reh-book-actions { + position: absolute; top: 6px; right: 6px; display: flex; gap: 3px; opacity: 0; + transition: opacity .14s; +} +.reh-book:hover .reh-book-actions { opacity: 1; } +.reh-book-act { + width: 22px; height: 22px; border-radius: 5px; border: none; cursor: pointer; + background: rgba(0,0,0,.32); color: #fff; font-size: 12px; + display: inline-flex; align-items: center; justify-content: center; +} +.reh-book-act:hover { background: rgba(0,0,0,.55); } +.reh-book-active-tag { + position: absolute; top: 8px; left: 14px; font-size: 8.5px; font-weight: 700; + text-transform: uppercase; letter-spacing: .08em; background: rgba(255,255,255,.92); + color: #1a1a2e; padding: 1px 6px; border-radius: 8px; +} +/* List-view fallback reuses old rows */ +.reh-bookshelf.list-view { display: flex; flex-direction: column; gap: 8px; } +.reh-bookshelf.list-view .reh-book { + aspect-ratio: auto; flex-direction: row; align-items: center; gap: 12px; + padding: 10px 14px; color: var(--text); background: var(--panel) !important; + box-shadow: none; border: 1px solid var(--border); border-radius: 8px; +} +.reh-bookshelf.list-view .reh-book:hover { transform: none; } +.reh-bookshelf.list-view .reh-book::before { display: none; } +.reh-bookshelf.list-view .reh-book-title { -webkit-line-clamp: 1; text-shadow: none; font-size: 14px; } +.reh-bookshelf.list-view .reh-book-meta { margin: 0 0 0 auto; } +.reh-bookshelf.list-view .reh-book-actions { position: static; opacity: 1; } +.reh-bookshelf.list-view .reh-book-act { background: var(--surface); color: var(--text); border: 1px solid var(--border); } + +/* ── Multi-page (paginated) script view ─────────────────────────────────── */ +.reh-page-wrap.paginated { display: flex; flex-direction: column; align-items: center; gap: 22px; } +.reh-paper { + width: min(1180px, 96%); background: #fff; color: #1a1a2e; + padding: 56px 72px 40px; box-shadow: 0 4px 24px rgba(0,0,0,.18); + font-family: 'Courier New', Courier, monospace; font-size: calc(12pt * var(--reh-stage-scale, 1)); line-height: 1.6; + border-radius: 2px; position: relative; box-sizing: border-box; + min-height: min(1123px, calc((100vw - 32px) * 1.414)); +} +.reh-paper-num { + position: absolute; top: 20px; right: 32px; font-size: 10pt; color: #888; + font-family: 'Courier New', monospace; +} +[data-theme="dark"] .reh-paper { background: #f8f8f2; } + +/* Keep script-browser list rows readable even when old cached list styles collapse. */ +.reh-imsdb-grid.list-view > .reh-imsdb-card { + height: 48px !important; + min-height: 48px !important; + max-height: 48px; + overflow: hidden; +} +.reh-imsdb-grid.list-view > .reh-imsdb-card .reh-imsdb-meta { + height: 48px; + min-height: 48px; +} + + +.reh-bulk-hint { font-size:11px; color:var(--subtext); margin-right:4px; } +.reh-bulk-mode .reh-selected { + background: rgba(37,99,235,.11) !important; + outline: 2px solid rgba(37,99,235,.35); + outline-offset: -2px; +} +.reh-bulk-mode .reh-selected .reh-block-dialog { font-weight:600; } + +/* Keep script-browser thumbnail cards tall enough to click/download in cover view. */ +.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card { + display: flex !important; + flex-direction: column !important; + min-height: 230px !important; + height: auto !important; + overflow: hidden; +} +.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-poster-wrap { + display: block !important; + position: relative !important; + width: 100% !important; + aspect-ratio: 2 / 3 !important; + min-height: 178px !important; + height: auto !important; + padding-bottom: 0 !important; + flex: 0 0 auto !important; +} +.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-poster, +.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-fallback { + position: absolute !important; + inset: 0 !important; + width: 100% !important; + height: 100% !important; +} +.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-meta { + min-height: 46px; + flex: 0 0 auto; +} diff --git a/static/index.html b/static/index.html index aafa52a..32d05d8 100644 --- a/static/index.html +++ b/static/index.html @@ -10,7 +10,7 @@ - + @@ -27,10 +27,11 @@ - - - - + + + + + @@ -395,7 +396,7 @@ window.toggleNavTree = function(treeId, chevronId) { - + diff --git a/static/style.css b/static/style.css index 3aa3bfe..91f9732 100644 --- a/static/style.css +++ b/static/style.css @@ -4333,1141 +4333,6 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami .conv-hist-ok { color: var(--green); } .conv-hist-err { color: var(--red); } -/* ── Script Rehearser ───────────────────────────────────────────────────── */ -.reh-phase[hidden] { display: none; } - -/* ── IMSDb browser modal ────────────────────────────────────────────────── */ -.reh-imsdb-modal { - position: fixed; inset: 0; z-index: 1000; - background: rgba(0,0,0,.55); display: flex; align-items: center; justify-content: center; - padding: 24px; -} -.reh-imsdb-modal[hidden] { display: none; } -.reh-imsdb-box { - background: var(--bg); border: 1px solid var(--border); border-radius: 14px; - width: 100%; max-width: 1100px; height: 88vh; display: flex; flex-direction: column; - box-shadow: 0 20px 60px rgba(0,0,0,.4); overflow: hidden; -} -.reh-imsdb-head { - display: flex; align-items: center; gap: 12px; padding: 14px 18px; - border-bottom: 1px solid var(--border); flex-shrink: 0; -} -.reh-imsdb-head h3 { margin: 0; font-size: 15px; display: flex; align-items: center; gap: 7px; white-space: nowrap; } -.reh-imsdb-url-row { display:flex; align-items:center; gap:8px; padding:10px 18px; border-bottom:1px solid var(--border); background:var(--panel); } -.reh-imsdb-url-row .reh-imsdb-url-input { flex:1; min-width:0; height:32px; padding:0 10px; border:1px solid var(--border); border-radius:7px; background:var(--surface); color:var(--text); font-size:13px; } -.reh-imsdb-search { - flex: 1; height: 34px; padding: 0 12px; border: 1px solid var(--border); - border-radius: 8px; background: var(--input-bg, var(--panel)); color: var(--text); font-size: 13px; -} -.reh-imsdb-count { font-size: 12px; color: var(--subtext); white-space: nowrap; } -.reh-imsdb-grid { - flex: 1; overflow-y: auto; padding: 16px; - display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; - align-content: start; -} -.reh-imsdb-loading { grid-column: 1/-1; text-align: center; padding: 40px; color: var(--subtext); font-size: 13px; display: flex; align-items: center; justify-content: center; gap: 10px; } -.reh-imsdb-load-error { grid-column: 1/-1; margin-bottom: 8px; padding: 10px 12px; border: 1px solid var(--red); border-left-width: 5px; border-radius: 8px; color: var(--red); background: rgba(220,38,38,.08); font-size: 13px; font-weight: 700; } -.reh-scripts-link { white-space: nowrap; } -.reh-imsdb-card { - cursor: pointer; border-radius: 8px; overflow: hidden; background: var(--card-bg, var(--panel)); - border: 1px solid var(--border); transition: transform .12s, box-shadow .12s, border-color .12s; - display: flex; flex-direction: column; -} -.reh-imsdb-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,0,0,.25); border-color: var(--accent); } -/* Poster image: use padding-bottom trick for guaranteed 2:3 ratio regardless of parent */ -.reh-imsdb-poster-wrap { - position: relative; width: 100%; padding-bottom: 150%; /* 2:3 ratio */ overflow: hidden; flex-shrink: 0; -} -.reh-imsdb-poster { - position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; -} -.reh-imsdb-fallback { - position: absolute; inset: 0; width: 100%; height: 100%; - display: flex; flex-direction: column; align-items: center; justify-content: center; - gap: 6px; color: rgba(255,255,255,.85); font-size: 28px; padding: 10px; box-sizing: border-box; -} -.reh-imsdb-fallback-title { - font-size: 11px; font-weight: 700; text-align: center; line-height: 1.35; - color: rgba(255,255,255,.95); text-shadow: 0 1px 4px rgba(0,0,0,.5); - overflow: hidden; display: -webkit-box; - -webkit-line-clamp: 4; -webkit-box-orient: vertical; - word-break: break-word; padding: 0 4px; max-width: 100%; -} -.reh-imsdb-meta { padding: 7px 9px; display: flex; flex-direction: column; gap: 2px; } -.reh-imsdb-title { font-size: 12px; font-weight: 600; color: var(--text); line-height: 1.25; - display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } -.reh-imsdb-year { font-size: 11px; color: var(--subtext); } - -/* IMSDb list view */ -.reh-imsdb-grid.list-view { - display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; -} -.reh-imsdb-grid.list-view .reh-imsdb-card { - flex-direction: row; align-items: center; gap: 0; height: 48px; border-radius: 6px; -} -.reh-imsdb-grid.list-view .reh-imsdb-card:hover { transform: none; box-shadow: 0 2px 8px rgba(0,0,0,.15); } -.reh-imsdb-grid.list-view .reh-imsdb-poster-wrap { - width: 32px; min-width: 32px; height: 48px; padding-bottom: 0; flex-shrink: 0; -} -.reh-imsdb-grid.list-view .reh-imsdb-fallback { - font-size: 13px; gap: 0; -} -.reh-imsdb-grid.list-view .reh-imsdb-fallback-title { display: none; } -.reh-imsdb-grid.list-view .reh-imsdb-poster { - position: static; width: 32px; height: 48px; object-fit: cover; -} -.reh-imsdb-grid.list-view .reh-imsdb-meta { - flex-direction: row; align-items: center; gap: 8px; padding: 0 12px; flex: 1; min-width: 0; -} -.reh-imsdb-grid.list-view .reh-imsdb-title { - display:block; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text); -webkit-line-clamp: unset; font-size: 13px; flex: 1; -} -.reh-imsdb-grid.list-view .reh-imsdb-card { background:var(--surface); } -.reh-imsdb-grid.list-view .reh-imsdb-year { margin-left: auto; white-space: nowrap; font-size: 11px; } - -/* View toggle buttons in modal header */ -.reh-imsdb-view-btns { - display: flex; gap: 2px; flex-shrink: 0; -} -.reh-imsdb-view-btn { - background: none; border: 1px solid var(--border); border-radius: 6px; - padding: 4px 8px; cursor: pointer; color: var(--subtext); font-size: 15px; - transition: background .12s, color .12s; -} -.reh-imsdb-view-btn:hover { background: var(--panel); color: var(--text); } -.reh-imsdb-view-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; } - -/* Loading spinner */ -@keyframes reh-spin { to { transform: rotate(360deg); } } -.reh-imsdb-spinner { - display: inline-block; width: 16px; height: 16px; border-radius: 50%; - border: 2px solid var(--border); border-top-color: var(--accent); - animation: reh-spin .7s linear infinite; flex-shrink: 0; -} - -/* ── Page break marker ──────────────────────────────────────────────────── */ -.reh-block-pagebreak { - display: flex; align-items: center; justify-content: center; - padding: 6px 0; margin: 4px 0; gap: 10px; -} -.reh-block-pagebreak::before, .reh-block-pagebreak::after { - content: ''; flex: 1; height: 1px; background: var(--border); -} -.reh-pagebreak-label { - font-size: 10px; color: var(--subtext); white-space: nowrap; letter-spacing: .04em; -} - -/* ── Scroll mode (no A4 paper) ──────────────────────────────────────────── */ -.reh-page-wrap:not(.paginated) .reh-a4-page { - box-shadow: none; border: none; border-radius: 0; min-height: unset; - padding: 24px 32px; -} - -/* ── Train Mode ─────────────────────────────────────────────────────────── */ -.reh-train-panel { - display: flex; flex-direction: column; gap: 10px; - padding: 12px 16px 16px; -} -.reh-train-header { - display: flex; align-items: center; gap: 10px; flex-shrink: 0; -} -.reh-train-badge { - display: inline-flex; align-items: center; gap: 5px; - font-size: 11px; font-weight: 800; letter-spacing: .08em; - color: var(--accent); background: rgba(37,99,235,.1); - border: 1px solid rgba(37,99,235,.25); border-radius: 6px; padding: 3px 10px; -} -.reh-train-progress { font-size: 13px; color: var(--subtext); font-variant-numeric: tabular-nums; } -.reh-train-cue, .reh-train-myline, .reh-train-rec, .reh-train-result { flex-shrink: 0; } -.reh-train-cue.no-cue { border-style: dashed; opacity: .7; } -.reh-train-cue.no-cue .reh-train-cue-text { color: var(--subtext); font-style: italic; } -.reh-train-cue-head, .reh-train-myline-head { - display: flex; align-items: center; gap: 8px; margin-bottom: 8px; -} -.reh-train-cue-avatar { display: inline-flex; flex-shrink: 0; } -.reh-train-cue-speaker { font-size: 13px; font-weight: 700; color: var(--text); } -.reh-train-cue-tag { - font-size: 10px; font-weight: 700; letter-spacing: .06em; - background: rgba(37,99,235,.1); color: var(--accent); - border-radius: 4px; padding: 1px 7px; margin-left: 2px; -} -.reh-train-me-tag { background: rgba(16,185,129,.1); color: var(--green); } -.reh-train-cue-state { margin-left: auto; font-size: 12px; } -.reh-train-cue-text { font-size: 14px; line-height: 1.55; } -.reh-train-cue-block { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; } -.reh-train-cue-block:last-child { margin-bottom: 0; } -.reh-train-cue-who { font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; } -.reh-train-cue-line { font-style: italic; color: var(--subtext); } -.reh-train-my-text { font-size: 16px; color: var(--text); line-height: 1.6; font-weight: 600; min-height: 2em; } -.reh-train-rec-head { - display: flex; align-items: center; gap: 10px; font-size: 13px; font-weight: 600; - color: var(--text); margin-bottom: 6px; -} -.reh-train-rec-state { flex: 1; } -.reh-train-rec-timer { font-variant-numeric: tabular-nums; color: var(--red); font-weight: 700; font-size: 13px; } -.reh-train-meters { margin-top: 6px; } -.reh-train-result-head { - display: flex; align-items: center; gap: 8px; - font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 10px; -} -.reh-train-score { margin-left: auto; font-size: 15px; } -.reh-train-compare-row { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; flex-wrap: wrap; } -.reh-train-compare-lbl { font-size: 11px; font-weight: 700; color: var(--subtext); white-space: nowrap; min-width: 58px; } -.reh-train-compare-text { font-size: 14px; line-height: 1.7; flex: 1; } -.tw-ok { color: var(--green); } -.tw-miss { color: var(--red); text-decoration: line-through; } -.tw-extra{ color: #f59e0b; } -.reh-train-controls { - display: flex; align-items: center; justify-content: center; gap: 10px; - margin-top: 4px; flex-shrink: 0; padding: 8px 0; - border-top: 1px solid var(--border); -} -.reh-train-rec-btn { color: var(--red) !important; } -.reh-impex-cat { font-size: 13px; font-weight: 700; color: var(--subtext); text-transform: uppercase; letter-spacing: .05em; margin: 16px 0 10px; } -.reh-impex-note { font-size: 12px; color: var(--subtext); margin: -4px 0 10px; } -.reh-impex-grid { display: flex; flex-wrap: wrap; gap: 10px; } -.reh-impex-btn { - display: inline-flex; flex-direction: column; align-items: center; justify-content: center; - gap: 6px; padding: 14px 18px; min-width: 100px; - background: var(--card-bg); border: 1px solid var(--border); border-radius: 10px; - color: var(--text); font-size: 12px; font-weight: 600; cursor: pointer; - transition: border-color .15s, background .15s; text-align: center; -} -.reh-impex-btn .mdi { font-size: 22px; color: var(--accent); } -.reh-impex-btn:hover { border-color: var(--accent); background: rgba(var(--accent-rgb),.07); } -.reh-impex-btn--accent { border-color: rgba(var(--accent-rgb),.35); } - -/* Library */ -.reh-lib-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; } -.reh-lib-list { display: flex; flex-direction: column; gap: 8px; } -.reh-lib-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 28px 0; color: var(--subtext); } -.reh-lib-empty .mdi { font-size: 36px; opacity: .4; } -.reh-lib-empty p { text-align: center; font-size: 13px; line-height: 1.5; margin: 0; } -.reh-lib-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; flex-wrap: wrap; } - -/* Phase 2 backend row */ -.reh-cast2-backend { display: flex; gap: 10px; align-items: flex-end; margin-bottom: 14px; flex-wrap: wrap; } -.reh-narrator-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; margin-bottom: 8px; border-top: 1px solid var(--border); flex-wrap: wrap; } -.reh-cast-instruct-wrap { padding: 0 12px 8px; margin-top: -4px; } -.reh-cast-instruct { width: 100%; font-size: 11px; padding: 4px 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface); color: var(--subtext); font-family: var(--font); } -.reh-cast-instruct:focus { outline: none; border-color: var(--accent); color: var(--text); } -.reh-lib-current { border-color: var(--accent); background: rgba(137,180,250,.06); } -.reh-lib-row-main { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; } -.reh-lib-avatars { display: flex; gap: 4px; flex-shrink: 0; } -.reh-lib-info { min-width: 0; flex: 1; } -.reh-lib-info strong { display: block; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.reh-lib-progress-wrap { height: 3px; background: var(--border); border-radius: 2px; overflow: hidden; margin-top: 5px; } -.reh-lib-progress { height: 100%; background: var(--accent); } -.reh-lib-row-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; } - -/* Phase 1 */ -.reh-new-script-head { - display: flex; align-items: center; gap: 14px; margin-bottom: 6px; flex-wrap: wrap; -} -.reh-script-title-inline { - flex: 1; min-width: 160px; max-width: 360px; - height: 32px; padding: 0 10px; border: 1px solid var(--border); border-radius: 6px; - background: var(--input-bg, var(--surface)); color: var(--text); font-size: 14px; - font-weight: 600; transition: border-color .15s; -} -.reh-script-title-inline:focus { outline: none; border-color: var(--accent); } -.reh-input-row { display: grid; grid-template-columns: 1fr 200px; gap: 14px; align-items: start; } -.reh-input-row textarea { min-height: 220px; font-family: monospace; font-size: 13px; width: 100%; resize: vertical; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 10px; color: var(--text); } -.reh-input-side { display: flex; flex-direction: column; gap: 8px; } - -/* ── Cast list: toolbar + Card/List view toggle ───────────────────────────── */ -.reh-cast-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; } -.reh-cast-count { font-size: 13px; color: var(--subtext); font-weight: 600; } -.reh-view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; background: var(--panel); } -.reh-view-btn { display: inline-flex; align-items: center; gap: 5px; padding: 7px 14px; border: none; background: transparent; color: var(--subtext); font-size: 13px; font-weight: 600; cursor: pointer; font-family: var(--font); transition: background .12s, color .12s; } -.reh-view-btn + .reh-view-btn { border-left: 1px solid var(--border); } -.reh-view-btn:hover { color: var(--text); } -.reh-view-btn.active { background: var(--accent); color: #fff; } -.reh-view-btn .mdi { font-size: 16px; } -.reh-cast-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; flex: 1; min-width: 0; justify-content: center; } -.reh-cast-ctl { font-size: 13px; padding: 6px 9px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font-family: var(--font); } -.reh-cast-ctl:focus { outline: none; border-color: var(--accent); } -.reh-cast-search { min-width: 150px; flex: 1 1 150px; max-width: 240px; } -.reh-cast-sortdir { display: inline-flex; align-items: center; justify-content: center; width: 34px; padding: 6px; cursor: pointer; color: var(--subtext); } -.reh-cast-sortdir:hover { color: var(--accent); border-color: var(--accent); } -.reh-cast-sortdir .mdi { font-size: 17px; } - -/* ── Cast cards (shared) ──────────────────────────────────────────────────── */ -.reh-cast-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; display: flex; flex-direction: column; transition: border-color .15s, opacity .15s, box-shadow .15s; } -.reh-cast-card.reh-cast-narrator { border-color: var(--accent); } -.reh-cast-card.reh-cast-ignored { opacity: .5; } -.reh-cast-card.reh-cast-hidden-c { outline: 1px dashed var(--border); } -.reh-cc-head { display: flex; gap: 12px; } -.reh-cc-avatar { flex-shrink: 0; } -/* rounded-square portrait (not a circle) — overrides the inline border-radius:50% */ -.reh-cc-avatar .reh-char-img, .reh-cc-avatar span, .reh-cc-avatar img { width: 64px !important; height: 64px !important; font-size: 28px !important; border-radius: 12px !important; } -.reh-cc-titles { flex: 1; min-width: 0; } -.reh-cc-name { font-size: 16px; font-weight: 800; line-height: 1.15; white-space: normal; overflow-wrap: anywhere; word-break: break-word; } -.reh-cc-sub { font-size: 12px; color: var(--subtext); margin-top: 3px; line-height: 1.3; } -.reh-cc-voicechip { display: inline-flex; align-items: center; gap: 5px; margin-top: 7px; font-size: 11px; font-weight: 600; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); padding: 3px 9px; border-radius: 999px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.reh-cc-voicechip.empty { color: var(--subtext); background: var(--surface); } -.reh-cc-sample-btn { margin-top: 7px; display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); color: var(--accent); cursor: pointer; font-family: var(--font); transition: background .12s; } -.reh-cc-sample-btn:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); } -.reh-cc-sample-btn.playing { background: var(--accent); color: #fff; } -.reh-cc-sample-btn.loading { pointer-events: none; opacity: .8; } -.reh-cc-sample-btn.loading .mdi { animation: spin .8s linear infinite; } -.reh-cc-sample-btn .mdi { font-size: 13px; } -.reh-cc-voicechip .mdi { font-size: 13px; } -.reh-cc-occupation { font-size: 11.5px; color: var(--subtext); font-style: italic; margin-top: 2px; line-height: 1.3; } -.reh-cc-emotions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 7px; } -.reh-cc-emo-chip { - font-size: 10.5px; font-weight: 600; padding: 2px 7px; border-radius: 999px; - background: var(--panel); border: 1px solid var(--border); color: var(--text); white-space: nowrap; -} -.reh-cc-actions { display: flex; align-items: center; gap: 5px; } -.reh-cc-actions-spacer { flex: 1; } -.reh-cc-me-row { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--subtext); cursor: pointer; white-space: nowrap; } -.reh-cc-me-row:hover { color: var(--text); } -.reh-cc-me-row .mdi { font-size: 15px; } -.reh-cc-extra { display: flex; flex-direction: column; gap: 8px; } - -/* ── Card view: "character card" look ─────────────────────────────────────── */ -.reh-cast-view-card { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px; } -.reh-cast-view-card .reh-cast-card { overflow: hidden; } -.reh-cast-view-card .reh-cast-card:hover { box-shadow: 0 6px 22px rgba(0,0,0,.10); } -.reh-cast-view-card .reh-cc-head { flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: 22px 18px 16px; background: linear-gradient(180deg, color-mix(in srgb, var(--cc-color, var(--accent)) 24%, var(--panel)), var(--panel)); border-bottom: 1px solid var(--border); } -.reh-cast-view-card .reh-cc-titles { flex: none; display: flex; flex-direction: column; align-items: center; } -.reh-cast-view-card .reh-cc-avatar .reh-char-img, .reh-cast-view-card .reh-cc-avatar span, .reh-cast-view-card .reh-cc-avatar img { width: 104px !important; height: 104px !important; font-size: 44px !important; border-width: 3px !important; box-shadow: 0 4px 14px rgba(0,0,0,.20); } -.reh-cast-view-card .reh-cc-name { font-size: 22px; } -.reh-cast-view-card .reh-cc-actions { padding: 10px 16px; border-bottom: 1px solid var(--border); } -.reh-cast-view-card .reh-cc-body { padding: 14px 16px 16px; gap: 10px; } - -/* ── List view: compact rows ──────────────────────────────────────────────── */ -.reh-cast-view-list { display: flex; flex-direction: column; gap: 8px; } -.reh-cast-view-list .reh-cast-card { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 14px; padding: 10px 14px; border-radius: 10px; } -.reh-cast-view-list .reh-cc-head { flex: 1; min-width: 200px; align-items: center; gap: 12px; padding: 0; background: none; border: none; } -.reh-cast-view-list .reh-cc-avatar .reh-char-img, .reh-cast-view-list .reh-cc-avatar span, .reh-cast-view-list .reh-cc-avatar img { width: 52px !important; height: 52px !important; font-size: 22px !important; } -.reh-cast-view-list .reh-cc-titles { flex: 1; } -.reh-cast-view-list .reh-cc-name { font-size: 16px; } -.reh-cast-view-list .reh-cc-voicechip { margin-top: 4px; } -.reh-cast-view-list .reh-cc-body { order: 2; flex: 0 0 240px; padding: 0; } -.reh-cast-view-list .reh-cc-extra { display: none; } /* full editor lives in Card view */ -.reh-cast-view-list .reh-cc-voice > label { display: none; } -.reh-cast-view-list .reh-cc-actions { order: 3; padding: 0; } -.reh-cast-view-list .reh-cc-actions-spacer { display: none; } -@media (max-width: 620px) { - .reh-cast-view-list .reh-cc-body { flex-basis: 100%; } -} -/* ── Online voice picker (try / alternatives / agree) ─────────────────────── */ -.reh-cc-online { border: 1px solid var(--border); border-radius: 9px; background: var(--surface); padding: 9px; display: flex; flex-direction: column; gap: 7px; } -.reh-cc-online-head { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--subtext); display: flex; align-items: center; gap: 6px; } -.reh-vo-toggle { margin-left: auto; background: none; border: none; color: var(--accent); font-size: 11px; font-weight: 700; cursor: pointer; font-family: inherit; } -.reh-vo-list { display: flex; flex-direction: column; gap: 6px; } -.reh-vo-row { display: flex; align-items: center; gap: 8px; padding: 6px 7px; border-radius: 7px; border: 1px solid transparent; } -.reh-vo-row.current { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); } -.reh-vo-play { flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border); background: var(--panel); color: var(--accent); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; transition: all .12s; } -.reh-vo-play:hover { border-color: var(--accent); } -.reh-vo-play.playing { background: var(--accent); color: #fff; border-color: var(--accent); } -.reh-vo-info { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.2; } -.reh-vo-name { font-size: 13px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.reh-vo-meta { font-size: 10px; color: var(--subtext); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.reh-vo-badge { flex-shrink: 0; font-size: 11px; font-weight: 700; color: var(--accent); display: inline-flex; align-items: center; gap: 3px; } -.reh-vo-use { flex-shrink: 0; } -.reh-vo-play.loading { pointer-events: none; } -.reh-vo-play.loading .mdi { animation: spin .8s linear infinite; } -/* change-voice tools (library / online search) */ -.reh-vo-tools { display: flex; gap: 6px; } -.reh-vo-tool { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px; padding: 6px 8px; font-size: 12px; font-weight: 600; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--subtext); cursor: pointer; font-family: inherit; transition: all .12s; } -.reh-vo-tool:hover { color: var(--text); border-color: var(--accent); } -.reh-vo-tool.active { color: var(--accent); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--panel)); } -.reh-vo-tool-panel { display: flex; flex-direction: column; gap: 7px; } -.reh-vo-search-row { display: flex; gap: 6px; } -.reh-vo-search-row .reh-vo-search-input { flex: 1; } -.reh-vo-local-input, .reh-vo-search-input { width: 100%; padding: 7px 9px; font-size: 12px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); color: var(--text); font-family: inherit; } -.reh-vo-local-input:focus, .reh-vo-search-input:focus { outline: none; border-color: var(--accent); } -.reh-vo-results { display: flex; flex-direction: column; gap: 6px; max-height: 230px; overflow-y: auto; } -.reh-vo-hint { font-size: 11px; color: var(--subtext); padding: 4px 2px; display: flex; align-items: center; gap: 6px; } -.reh-cc-iconbtn { width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--subtext); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; transition: all .12s; } -.reh-cc-iconbtn:hover { color: var(--text); border-color: var(--accent); } -.reh-cc-iconbtn.active { background: var(--accent); color: #fff; border-color: var(--accent); } -.reh-cc-del:hover { color: var(--red); border-color: var(--red); } -.reh-cc-body { display: flex; flex-direction: column; gap: 8px; } -.reh-cc-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; } -.reh-cc-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; } -.reh-cc-field > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--subtext); } -.reh-cc-field select, .reh-cc-field input { width: 100%; min-width: 0; font-size: 12px; padding: 5px 7px; border: 1px solid var(--border); border-radius: 5px; background: var(--surface); color: var(--text); font-family: var(--font); } -.reh-cc-voice .vp-root { width: 100%; min-width: 0; flex: 1 1 auto; } -.reh-cc-voice .vp-trigger { min-height: 30px; font-size: 12px; } -.reh-cc-voice .vp-drop { max-height: 310px; z-index: 80; } -.reh-cc-field select:focus, .reh-cc-field input:focus { outline: none; border-color: var(--accent); } -.reh-cc-soul { border-top: 1px solid var(--border); padding-top: 6px; } -.reh-cc-soul > summary { font-size: 11px; font-weight: 600; color: var(--subtext); cursor: pointer; display: flex; align-items: center; gap: 6px; list-style: none; } -.reh-cc-soul > summary::-webkit-details-marker { display: none; } -.reh-cc-develop { margin-left: auto; padding: 2px 8px; font-size: 11px; } -.reh-cc-soul-text { width: 100%; margin-top: 6px; min-height: 64px; resize: vertical; font-size: 12px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 5px; background: var(--surface); color: var(--text); font-family: var(--font); line-height: 1.45; } -.reh-cc-soul-text:focus { outline: none; border-color: var(--accent); } -.reh-cc-more { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 2px; } -/* Cast card reusing the exact Library card (_charCardHtml) — no extra - border/shadow around it, its own 16px-radius styling already stands - alone; the Rehearser-only controls strip sits directly under it. */ -.reh-cast-card-libcard { background: none; border: none; box-shadow: none; } -.reh-cast-card-libcard .lib-char-card { cursor: pointer; } -.reh-cast-card-libcard .lib-char-select { display: none; } -.reh-cast-card-libcard > .reh-cc-body { padding: 12px 4px 4px; } -.reh-cc-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } -.reh-cc-more > summary { font-size: 11.5px; font-weight: 700; color: var(--subtext); cursor: pointer; display: flex; align-items: center; gap: 6px; list-style: none; } -.reh-cc-more > summary::-webkit-details-marker { display: none; } -.reh-cc-more[open] > summary { color: var(--accent); margin-bottom: 8px; } -.reh-cc-more .reh-cc-extra { margin-top: 8px; } - - -.reh-tb-btn { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--border); background: var(--panel); color: var(--text); cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; transition: background .15s; } -.reh-tb-btn:hover { background: var(--border); } -.reh-tb-play { background: var(--accent); color: #fff; border-color: var(--accent); font-size: 18px; } -.reh-tb-play:hover { opacity: .85; } -.reh-btn-active { background: var(--accent) !important; color: #fff !important; border-color: var(--accent) !important; } -.reh-tb-progress-wrap { flex: 1; height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; } -.reh-tb-progress { height: 100%; background: var(--accent); width: 0%; transition: width .3s ease; } -.reh-tb-label { font-size: 12px; color: var(--subtext); white-space: nowrap; font-variant-numeric: tabular-nums; } - -/* Stage: script page + character sidebar (same .ab-cv-side look Read Aloud's - Casting view uses). The sidebar sticks in place while the script scrolls. */ -.reh-stage-area { display: flex; gap: 12px; align-items: flex-start; transition: none; } -.reh-stage-area .reh-page-wrap { flex: 1; min-width: 0; } -.reh-stage-area .ab-cv-side { - width: 220px; flex-shrink: 0; position: sticky; top: 12px; - max-height: calc(100vh - 160px); -} -.reh-stage-area.side-collapsed .ab-cv-side { width: 44px; } -.reh-stage-area .ab-cv-side .ab-cv-chars { flex: 1; overflow-y: auto; } -@media (max-width: 767px) { - /* The sidebar was a fixed 220px column next to the script page — on a - phone-width viewport that left almost no room for the page itself. - Stack the sidebar above the page instead, collapsible the same way it - already is on desktop, just full-width instead of a narrow rail. */ - .reh-stage-area { flex-direction: column; } - .reh-stage-area .ab-cv-side { width: 100%; position: static; max-height: 220px; order: -1; } - .reh-stage-area.side-collapsed .ab-cv-side { width: 100%; max-height: 44px; overflow: hidden; } - .reh-page-wrap { padding: 16px 10px; } - .reh-a4-page { padding: 20px 14px; } -} - -/* A4 page */ -.reh-page-wrap { padding: 24px 16px; background: var(--panel); min-height: 60vh; } -.reh-a4-page { - width: min(1180px, 96%); min-height: 400px; - background: #fff; color: #1a1a2e; - padding: 56px 72px; - box-shadow: 0 4px 24px rgba(0,0,0,.18); - margin: 0 auto; - font-family: 'Georgia', 'Times New Roman', serif; - border-radius: 2px; -} -[data-theme="dark"] .reh-a4-page { background: #f8f8f2; color: #1a1a2e; } -.reh-page-title { font-size: 22px; font-weight: 700; text-align: center; margin-bottom: 36px; letter-spacing: .04em; text-transform: uppercase; color: #1a1a2e; border-bottom: 2px solid #1a1a2e; padding-bottom: 12px; } -.reh-script-lines { display: flex; flex-direction: column; gap: 0; } - -/* Each dialog block — flex: gutter | content */ -.reh-block { display: flex; align-items: stretch; padding: 8px 12px 8px 2px; border-left: 3px solid transparent; border-radius: 0 4px 4px 0; margin-bottom: 2px; transition: background .2s, border-color .2s; } -.reh-block-inner { flex: 1; min-width: 0; } -.reh-block-head { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; flex-wrap: nowrap; } -.reh-block-name { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; white-space: nowrap; } -.reh-block-head-spacer { flex: 1; min-width: 8px; } -.reh-block-badge { font-size: 10px; padding: 1px 6px; border-radius: 10px; font-family: sans-serif; flex-shrink: 0; } -.reh-badge-tts { background: rgba(137,180,250,.2); color: #2563eb; } -.reh-badge-me { background: rgba(166,227,161,.25); color: #16a34a; } -.reh-block-dialog { font-size: 15px; line-height: 1.65; padding-left: 40px; color: #1a1a2e; } -.reh-direction { font-style: italic; color: #666; font-size: 13px; padding: 4px 12px; } -.reh-char-img { vertical-align: middle; } -.reh-line-play-avatar { border:0; background:transparent; padding:0; margin:0 2px 0 0; cursor:pointer; border-radius:50%; position:relative; display:inline-flex; align-items:center; justify-content:center; } -.reh-line-play-avatar:hover { box-shadow:0 0 0 3px rgba(37,99,235,.18); } -/* This badge overlay is meant to sit in the corner of the bigger avatar - circle (dialogue's own play button) — .reh-action-play-btn (the plain - narrator play button, no avatar underneath) also carries the shared - .reh-line-play-avatar class for click wiring, so it was ALSO getting - this badge layered on top of its own inline icon: two visibly different - play icons stacked on one small button. Excluded here; it's styled to - look like this same badge directly instead (one icon, not two). */ -.reh-line-play-avatar:not(.reh-action-play-btn)::after { content:'\F040A'; font-family:'Material Design Icons'; position:absolute; right:-5px; bottom:-5px; width:16px; height:16px; border-radius:50%; background:var(--accent); color:#fff; font-size:11px; display:flex; align-items:center; justify-content:center; box-shadow:0 1px 4px rgba(0,0,0,.24); } -.reh-line-active .reh-line-play-avatar:not(.reh-action-play-btn)::after { content:'\F03E4'; background:var(--red); } - -/* Narrator paragraph play button — no avatar image underneath, so styled - to look like the same small blue circular badge dialogue's own play - button already shows (see the ::after rule above), just as its own real - icon instead of a badge layered over something else. */ -.reh-action-play-btn { - width: 16px; height: 16px; margin: 0 5px 0 0; vertical-align: middle; - border: none; color: #fff; font-size: 11px; - background: var(--accent); flex-shrink: 0; -} -.reh-action-play-btn:hover { box-shadow: 0 0 0 3px rgba(37,99,235,.18); } -.reh-line-active .reh-action-play-btn { background: var(--red); } - -/* Gutter: narrow play/range column left of each dialog block */ -.reh-gutter-btn { width:22px; min-width:22px; flex-shrink:0; align-self:stretch; background:none; border:none; cursor:pointer; display:flex; align-items:center; justify-content:center; color:transparent; transition:color .12s; font-size:9px; padding:0; margin-right:4px; } -.reh-block:hover .reh-gutter-btn { color:var(--accent); } -.reh-range-start .reh-gutter-btn { color:#10b981 !important; } -.reh-range-end .reh-gutter-btn { color:#ef4444 !important; } -.reh-in-range { background:rgba(245,158,11,.05) !important; } -.reh-range-start { border-left-color:#10b981 !important; } -.reh-range-end { border-left-color:#ef4444 !important; } -.reh-practice-info { display:none; align-items:center; gap:3px; font-size:10px; color:var(--subtext); white-space:nowrap; margin-left:6px; } -.reh-practice-info.visible { display:inline-flex; } - -/* ── Bulk-edit (line selection) ───────────────────────────────────────────── */ -.reh-bulk-bar { - display:flex; align-items:center; gap:6px; flex-wrap:wrap; - padding:6px 10px; margin:6px 0; border:1px solid var(--border); border-radius:8px; - background:var(--panel); position:sticky; top:0; z-index:6; -} -.reh-bulk-count { font-size:12px; font-weight:700; color:var(--accent); min-width:74px; } -.reh-bulk-sep { width:1px; align-self:stretch; background:var(--border); margin:2px 2px; } -.reh-bulk-spacer{ flex:1; } -/* Leading checkbox in front of each line */ -.reh-bulk-check { - display:none; align-items:center; justify-content:center; flex-shrink:0; - width:26px; cursor:pointer; color:var(--subtext); font-size:20px; align-self:center; -} -.reh-bulk-mode .reh-bulk-check { display:inline-flex; } -.reh-bulk-check.checked { color:var(--accent); } -.reh-bulk-check:hover { color:var(--accent); } -/* Non-dialog blocks: keep the checkbox inline at the start */ -.reh-bulk-mode .reh-act, -.reh-bulk-mode .reh-scene, -.reh-bulk-mode .reh-action-block, -.reh-bulk-mode .reh-transition, -.reh-bulk-mode .reh-direction, -.reh-bulk-mode .reh-block-pagebreak { position:relative; } -/* Ignored lines: greyed out but still visible */ -.reh-line-ignored { opacity:.42; filter:grayscale(1); } -.reh-line-ignored .reh-block-dialog { text-decoration:line-through; text-decoration-color:rgba(0,0,0,.3); } -/* Hidden lines revealed in bulk mode: dashed, dimmed */ -.reh-line-hidden { opacity:.5; outline:1px dashed var(--border); outline-offset:-2px; } - -/* Active line */ -.reh-block-active { background: rgba(37,99,235,.07); border-left-color: #2563eb; } -.reh-block-active .reh-block-dialog { font-weight: 500; } - -/* Emotion picker button */ -.reh-emo-btn { font-size:11px; border:1px solid rgba(0,0,0,.15); border-radius:4px; padding:2px 6px; background:rgba(0,0,0,.03); color:#555; cursor:pointer; margin-left:auto; flex-shrink:0; font-family:sans-serif; display:inline-flex; align-items:center; gap:3px; white-space:nowrap; max-width:115px; overflow:hidden; } -.reh-emo-btn:hover { border-color:var(--accent); } -.reh-emo-btn.has-emotion { background:rgba(37,99,235,.07); color:#1a1a2e; border-color:rgba(37,99,235,.3); font-weight:600; } -.reh-emo-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:72px; } - -/* Emotion picker popover */ -.reh-emo-popover { background:var(--bg); border:1px solid var(--border); border-radius:8px; box-shadow:0 8px 32px rgba(0,0,0,.18); overflow:hidden; } -.reh-emo-pop-inner { display:flex; flex-direction:column; max-height:300px; } -.reh-emo-search { padding:8px 10px; border:none; border-bottom:1px solid var(--border); background:var(--surface); font-size:12px; outline:none; color:var(--text); width:100%; box-sizing:border-box; } -.reh-emo-list { overflow-y:auto; flex:1; padding:4px; } -.reh-emo-item { display:flex; align-items:center; gap:8px; padding:5px 8px; border-radius:4px; cursor:pointer; font-size:12px; color:var(--text); } -.reh-emo-item:hover { background:var(--panel); } -.reh-emo-item.selected { background:rgba(37,99,235,.1); color:var(--accent); font-weight:600; } -.reh-emo-item-emoji { font-size:15px; flex-shrink:0; } -.reh-emo-custom-row { padding:6px; border-top:1px solid var(--border); } - -/* Markdown formatting toolbar */ -.reh-fmt-toolbar { display:flex; gap:3px; align-items:center; padding:4px 6px; background:var(--panel); border:1px solid var(--border); border-bottom:none; border-radius:3px 3px 0 0; flex-wrap:wrap; } -.reh-fmt-btn { padding:2px 8px; border:1px solid var(--border); border-radius:3px; background:var(--surface); cursor:pointer; font-size:12px; color:var(--text); line-height:1.4; } -.reh-fmt-btn:hover { background:var(--border); } -.reh-fmt-hint { font-size:10px; color:var(--subtext); margin-left:auto; font-style:italic; } - -/* Markdown inside A4 */ -.reh-a4-page strong, .reh-paper strong { font-weight:700; } -.reh-a4-page em, .reh-paper em { font-style:italic; } -.reh-a4-page u, .reh-paper u { text-decoration:underline; } -.reh-a4-page del, .reh-paper del { text-decoration:line-through; opacity:.65; } -.reh-a4-page .reh-hl, .reh-paper .reh-hl { background:#fef3c7; border-radius:2px; padding:0 1px; } - -/* Word-level highlight during playback */ -.reh-word { display:inline; border-radius:2px; transition:background .06s, color .06s; } -.reh-word-active { background:rgba(37,99,235,.22); color:#1a1a2e; border-radius:2px; padding:0 1px; } - -/* ── Proper screenplay A4 formatting ─────────────────────────────────── */ -/* Use Courier New throughout — 1 page ≈ 1 minute of screen time */ -/* Base play font size. Everything below is expressed in `em` so the whole - play scales together via --reh-stage-scale (the +A / -A control). */ -.reh-a4-page { - font-family: 'Courier New', Courier, monospace !important; - font-size: calc(12pt * var(--reh-stage-scale, 1)); - line-height: 1.6; -} -.reh-page-title { - font-family: 'Courier New', Courier, monospace; - font-size: 1.17em; -} -/* Scene headings: all-caps, bold, with spacing */ -.reh-scene { - font-size: 1em; - letter-spacing: .04em; -} -/* Narrator / action text and spoken dialog share ONE size (1em) so the play - reads evenly — no narrator-vs-dialogue size mismatch. */ -.reh-action-block { font-size: 1em; } -.reh-action-text { font-size: 1em; } - -/* Act headings: larger, extra top space */ -.reh-act { font-size: 1.08em; } - -/* Transitions: right-aligned */ -.reh-transition { font-size: 1em; } - -/* Dialog block — screenplay format */ -.reh-block-name { - font-size: 0.92em; - letter-spacing: .1em; -} -.reh-block-dialog { - font-size: 1em; - padding-left: 32px; /* ~1.5" dialog indent */ - max-width: 440px; /* ~3.5" dialog column width */ -} -/* Parenthetical directions: centered-ish */ -.reh-direction { - font-size: 0.92em; - padding-left: 80px; - color: #444; -} - -/* Script editor modal */ -.reh-modal-overlay { position:fixed; inset:0; z-index:2000; background:rgba(0,0,0,.45); display:flex; align-items:center; justify-content:center; padding:16px; } -.reh-modal-overlay[hidden] { display: none !important; } -.reh-modal-box { background:var(--bg); border-radius:10px; box-shadow:0 20px 60px rgba(0,0,0,.3); overflow:hidden; display:flex; flex-direction:column; } -.reh-modal-head { display:flex; align-items:center; justify-content:space-between; padding:12px 16px; border-bottom:1px solid var(--border); font-weight:700; } - -/* TTS status bar */ -.reh-tts-status-bar { display: flex; align-items: center; gap: 12px; padding: 8px 16px; background: var(--panel); border-top: 1px solid var(--border); font-size: 13px; } -.reh-tts-status-bar[hidden] { display: none; } - -/* Recording overlay */ -.reh-rec-overlay { - position: sticky; bottom: 0; z-index: 60; - background: var(--bg); border-top: 2px solid var(--green); - box-shadow: 0 -4px 20px rgba(0,0,0,.15); -} -.reh-rec-overlay[hidden] { display: none; } -.reh-rec-overlay-inner { padding: 14px 20px; max-width: 860px; margin: 0 auto; } -.reh-rec-cue { font-size: 14px; margin-bottom: 10px; line-height: 1.5; } -.reh-rec-cue-name { font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .1em; } -.reh-rec-cue-text { font-size: 17px; margin-top: 4px; padding: 8px 12px; background: rgba(166,227,161,.1); border-left: 3px solid var(--green); border-radius: 0 4px 4px 0; font-style: italic; } -.reh-rec-inner { padding: 14px 20px; max-width: 860px; margin: 0 auto; } - -/* Summary */ -.reh-summary-list { display: flex; flex-direction: column; gap: 10px; } -.reh-summary-row { display: flex; align-items: flex-start; gap: 10px; padding: 10px; background: var(--panel); border-radius: 6px; } - -/* Console / sticky transport bar */ -.reh-console { - position: sticky; top: 0; z-index: 50; - background: var(--bg); border-bottom: 1px solid var(--border); - display: flex; align-items: center; gap: 10px; padding: 7px 14px; flex-wrap: wrap; -} -.reh-console-transport { display: flex; gap: 4px; align-items: center; flex-shrink: 0; } -.reh-console-progress { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 80px; } -/* flex-shrink:0 with the flexbox-default min-width:auto meant this block could - never shrink below its unwrapped natural width (confirmed live: ~1560px of - buttons in a 524px-wide bar) — flex-wrap never got a chance to kick in since - the item was never considered "too wide to fit" by the wrapping algorithm, - so on any real (non-ultrawide) window the tail of the toolbar — font size, - page mode, Train, Exit — silently fell off-screen with no scrollbar to - reach it. Allowing it to shrink (and explicitly zeroing min-width, since - flex items default to min-width:auto regardless of any width you set) lets - it wrap onto additional rows within the available space instead. */ -.reh-console-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 1; min-width: 0; flex-wrap: wrap; } - -/* Synth progress bar */ -/* Tone / style backend warning bar */ -.reh-tone-warn { - display: flex; align-items: flex-start; gap: 8px; padding: 7px 14px; - background: rgba(234,179,8,.1); border-bottom: 1px solid rgba(234,179,8,.35); - font-size: 12px; color: #92400e; -} -.reh-tone-warn[hidden] { display: none; } -.reh-tone-warn .mdi { color: #d97706; font-size: 14px; flex-shrink: 0; } -/* Aligns the alert icon with the table's own text baseline rather than the - whole (now taller, multi-row) bar. */ -.reh-tone-warn > .mdi { margin-top: 3px; } -.reh-tone-warn-close { - margin-left: auto; background: none; border: none; cursor: pointer; - color: #92400e; font-size: 13px; line-height: 1; padding: 2px 4px; border-radius: 3px; - opacity: .7; flex-shrink: 0; -} -.reh-tone-warn-close:hover { opacity: 1; background: rgba(0,0,0,.06); } - -/* Backend tone/identity comparison table — replaced a run-on sentence with a - button wedged mid-clause (confirmed live: read badly and wrapped worse). - Same two facts, laid out as two columns instead of two clauses. */ -.reh-tone-cmp { border-collapse: collapse; font-size: 12px; } -.reh-tone-cmp th { - text-align: left; font-weight: 600; padding: 2px 14px 4px 0; color: #92400e; - opacity: .75; white-space: nowrap; -} -.reh-tone-cmp td { padding: 3px 14px 3px 0; white-space: nowrap; } -.reh-tone-cmp tr:first-child td { padding-top: 0; } -.reh-tone-cmp-current td:first-child { font-weight: 700; } -.reh-tone-cmp-current-tag { - font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; - color: #92400e; opacity: .7; -} -.reh-tone-cmp-yes { color: #15803d; } -.reh-tone-cmp-no { color: #b91c1c; opacity: .8; } -.reh-tone-cmp-yes .mdi, .reh-tone-cmp-no .mdi { font-size: 13px; } -.reh-tone-switch-btn { padding: 2px 10px !important; font-size: 11px !important; } -.reh-tone-cmp-note { margin: 4px 0 0; font-size: 11.5px; opacity: .85; } - -/* Synth progress bar — more prominent while running */ -.reh-synth-bar { - display: flex; align-items: center; gap: 10px; padding: 7px 16px; - background: linear-gradient(90deg, rgba(37,99,235,.08), rgba(37,99,235,.04)); - border-bottom: 2px solid rgba(37,99,235,.3); font-size: 12px; - box-shadow: 0 2px 8px rgba(37,99,235,.12); -} -.reh-synth-bar[hidden] { display: none; } -.reh-synth-bar-lbl { - font-size: 11px; font-weight: 700; color: var(--accent); white-space: nowrap; - display: flex; align-items: center; gap: 4px; letter-spacing: .04em; -} -.reh-synth-track { flex: 1; height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; } -.reh-synth-fill { height: 100%; background: linear-gradient(90deg, var(--accent), #7c3aed); width: 0%; transition: width .25s ease; border-radius: 3px; } -.reh-synth-label { font-size: 12px; font-weight: 600; color: var(--accent); white-space: nowrap; min-width: 48px; text-align: right; } - -/* Synthesizing dot — pulsing spinner ring */ -@keyframes reh-synth-pulse { 0%,100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.5); opacity: .5; } } -.reh-synth-dot.synthesizing { - background: var(--accent); - animation: reh-synth-pulse .8s ease-in-out infinite; - box-shadow: 0 0 0 3px rgba(37,99,235,.25); -} - -/* Row highlight while a line is being synthesized */ -.reh-line-synthesizing { - background: rgba(37,99,235,.06) !important; - border-left-color: var(--accent) !important; - transition: background .15s; -} - -/* Play font-size stepper (+A / -A) */ -.reh-fontsize-ctl { display: inline-flex; gap: 2px; } -/* No padding override here on purpose — confirmed live these two buttons - rendered ~18px shorter than every sibling toolbar button (2px 7px vs the - base .btn-secondary.btn-sm's 9px 18px) because this rule fought that - padding instead of inheriting it. Font weight is the only real - customization these need. */ -/* Padding now matches every sibling button exactly, but a residual gap - remained — plain "A" + superscript text computes a shorter natural - line-height than an icon+text button, and guessing at a line-height - multiplier to compensate (tried 1: overshot the other way, to 35.7px - against siblings' 43px) is fragile. Match the sibling toolbar buttons' - actual height directly instead of trying to reverse-engineer it via - line-height. */ -.reh-fontsize-btn { font-weight: 700; height: 43px; display: inline-flex; align-items: center; justify-content: center; } -.reh-fontsize-btn .reh-fontsize-plus, .reh-fontsize-btn .reh-fontsize-minus { font-size: 9px; vertical-align: super; margin-left: 1px; } - -/* Act heading on A4 page */ -.reh-act { - font-family: 'Courier New', Courier, monospace; font-size: 13px; font-weight: 700; - text-transform: uppercase; letter-spacing: .14em; color: #1a1a2e; - margin: 28px 0 8px; padding: 7px 0; text-align: center; - border-top: 2.5px solid #1a1a2e; border-bottom: 2.5px solid #1a1a2e; - cursor: pointer; -} - -/* Chapter marker — a horizontal rule with the chapter's own title/number - between the two halves, so a chapter break is visible while scrolling the - script itself and not just audible as a pause in the exported audiobook. */ -.reh-chapter-marker { - display: flex; align-items: center; gap: 14px; - margin: 32px 0 20px; position: relative; -} -.reh-chapter-marker-line { flex: 1; height: 1px; background: var(--border); } -.reh-chapter-marker-label { - font-weight: 700; text-transform: uppercase; letter-spacing: .08em; - font-size: 13px; color: var(--subtext); white-space: nowrap; padding: 0 2px; -} -.reh-chapter-marker:hover .reh-edit-btn { opacity: 1; } - -/* Inline edit button — shown on hover */ -.reh-edit-btn { - opacity: 0; transition: opacity .12s; border: 1px solid transparent; - background: none; cursor: pointer; font-size: 10px; color: var(--subtext); - padding: 1px 5px; border-radius: 3px; line-height: 1; flex-shrink: 0; -} -.reh-block:hover .reh-edit-btn, -.reh-action-block:hover .reh-edit-btn, -.reh-scene:hover .reh-edit-btn, -.reh-act:hover .reh-edit-btn { opacity: 1; } -.reh-edit-btn:hover { background: var(--panel); border-color: var(--border); color: var(--accent); } - -/* Scene heading on the A4 page */ -.reh-scene { - font-family: 'Courier New', Courier, monospace; font-size: 11.5px; font-weight: 700; - text-transform: uppercase; letter-spacing: .07em; color: #1a1a2e; - margin: 22px 0 8px; padding: 5px 0; - border-top: 1.5px solid #333; border-bottom: 1.5px solid #333; - cursor: pointer; display: flex; align-items: center; gap: 6px; -} -.reh-scene .mdi { font-size: 11px; opacity: .5; flex-shrink: 0; } - -/* Action / description block — 1em so narrator matches spoken dialog and - scales with the +A / -A control. */ -.reh-action-block { - font-family: 'Courier New', Courier, monospace; font-size: 1em; line-height: 1.75; - color: #2c2c3e; padding: 2px 0 10px; cursor: pointer; -} - -/* Transition line */ -.reh-transition { - font-family: 'Courier New', Courier, monospace; font-size: 0.75em; font-weight: 700; - text-align: right; text-transform: uppercase; letter-spacing: .1em; - color: #555; padding: 8px 0; -} - -/* Active line highlight (works on any block type) */ -.reh-line-active.reh-block { background: rgba(37,99,235,.08) !important; border-left-color: var(--accent) !important; } -.reh-line-active.reh-scene { background: rgba(37,99,235,.06) !important; outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 3px; } -.reh-line-active.reh-action-block { background: rgba(37,99,235,.05) !important; padding-left: 6px; border-left: 2px solid var(--accent); } -.reh-line-active.reh-direction { background: rgba(37,99,235,.04) !important; } - -/* Emotion selector on TTS dialog blocks */ -.reh-emotion-sel { - font-size: 10px; border: 1px solid rgba(0,0,0,.18); border-radius: 3px; - padding: 1px 4px; background: rgba(0,0,0,.04); color: #555; - cursor: pointer; margin-left: auto; flex-shrink: 0; font-family: sans-serif; - max-width: 90px; -} -.reh-emotion-sel:hover, .reh-emotion-sel:focus { border-color: var(--accent); outline: none; } -.reh-emotion-sel.has-emotion { background: rgba(37,99,235,.08); color: var(--accent); border-color: var(--accent); font-weight: 600; } - -/* Pre-synthesized dot */ -.reh-synth-dot { - width: 7px; height: 7px; border-radius: 50%; background: var(--green); - flex-shrink: 0; display: inline-block; margin-left: 3px; -} -.reh-synth-dot.stale { - background: var(--red, #ef4444); - box-shadow: 0 0 0 2px rgba(239,68,68,.2); -} - -/* Per-line re-synth button */ -.reh-resynth-btn { - background: none; border: none; cursor: pointer; padding: 2px 4px; - color: var(--red, #ef4444); font-size: 12px; border-radius: 4px; - opacity: .85; transition: opacity .15s, background .15s; - display: inline-flex; align-items: center; -} -.reh-resynth-btn:hover { opacity: 1; background: rgba(239,68,68,.1); } - -/* Note area — right gutter of dialog block (holds edit btn + note btn) */ -.reh-block { position: relative; } -.reh-note-area { - display: flex; flex-direction: column; align-items: flex-end; gap: 2px; - min-width: 28px; flex-shrink: 0; padding-top: 2px; -} -/* Edit button inside note-area gutter */ -.reh-note-area .reh-edit-btn { - opacity: 0; transition: opacity .12s; border: 1px solid transparent; - background: none; cursor: pointer; font-size: 13px; color: var(--subtext); - padding: 3px 5px; border-radius: 4px; line-height: 1; flex-shrink: 0; -} -.reh-block:hover .reh-note-area .reh-edit-btn { opacity: 1; } -.reh-note-area .reh-edit-btn:hover { background: var(--panel); border-color: var(--border); color: var(--accent); } -.reh-note-btn { - background: none; border: none; cursor: pointer; padding: 3px; - font-size: 14px; color: var(--subtext); opacity: .45; border-radius: 4px; - transition: opacity .15s, color .15s; line-height: 1; flex-shrink: 0; -} -.reh-note-btn:hover, .reh-note-btn.has-note { opacity: 1; color: #f59e0b; } -.reh-note-ta { - display: none; width: 160px; min-height: 60px; resize: vertical; - font-size: 11px; font-family: inherit; line-height: 1.45; - padding: 6px 8px; border: 1px solid #f59e0b55; border-radius: 6px; - background: rgba(245,158,11,.06); color: var(--text); outline: none; -} -.reh-note-ta.open { display: block; } -.reh-note-ta:focus { border-color: #f59e0b; background: rgba(245,158,11,.1); } - -@media (max-width: 700px) { - .reh-input-row { grid-template-columns: 1fr; } - .reh-a4-page { padding: 28px 20px; } - .reh-console { gap: 8px; } - .reh-cc-grid { grid-template-columns: 1fr; } -} - -/* ── Phase sub-tabs ─────────────────────────────────────────────────────── */ -.reh-subtabs { - display: flex; gap: 4px; padding: 4px; margin: 0 0 14px; - background: var(--panel); border: 1px solid var(--border); border-radius: 10px; - flex-wrap: wrap; -} -.reh-subtab { - display: inline-flex; align-items: center; gap: 6px; - padding: 7px 14px; border: none; border-radius: 7px; cursor: pointer; - background: transparent; color: var(--subtext); font-size: 13px; font-weight: 600; - transition: background .15s, color .15s; -} -.reh-subtab .mdi { font-size: 16px; } -.reh-subtab:hover:not(:disabled):not(.active) { background: var(--border); color: var(--text); } -.reh-subtab.active { background: var(--surface); color: var(--accent); box-shadow: 0 1px 3px rgba(0,0,0,.08); } -.reh-subtab:disabled { opacity: .4; cursor: not-allowed; } -@media (max-width: 600px) { - .reh-subtab span:not(.mdi) { display: none; } - .reh-subtab { padding: 8px 12px; } -} - -/* ── Studio phase tabs (deliberately separate classes from .reh-subtab — - rehearser.js wires its OWN click listeners onto every .reh-subtab in the - document via querySelectorAll, and every section's HTML is present in the - DOM at once regardless of which is visible, so reusing that class name - here would silently attach Rehearser's phase-switching logic to Studio's - own tab buttons too) ───────────────────────────────────────────────── */ -.stu-subtabs { - display: flex; gap: 4px; padding: 4px; margin: 0 0 14px; - background: var(--panel); border: 1px solid var(--border); border-radius: 10px; - flex-wrap: wrap; -} -.stu-subtab { - display: inline-flex; align-items: center; gap: 6px; - padding: 7px 14px; border: none; border-radius: 7px; cursor: pointer; - background: transparent; color: var(--subtext); font-size: 13px; font-weight: 600; - transition: background .15s, color .15s; -} -.stu-subtab .mdi { font-size: 16px; } -.stu-subtab:hover:not(:disabled):not(.active) { background: var(--border); color: var(--text); } -.stu-subtab.active { background: var(--surface); color: var(--accent); box-shadow: 0 1px 3px rgba(0,0,0,.08); } -.stu-subtab:disabled { opacity: .4; cursor: not-allowed; } -.stu-subtab-num { - display: inline-flex; align-items: center; justify-content: center; - width: 16px; height: 16px; border-radius: 50%; font-size: 10px; font-weight: 700; - background: var(--border); color: var(--subtext); flex-shrink: 0; -} -.stu-subtab.active .stu-subtab-num { background: var(--accent); color: #fff; } -@media (max-width: 600px) { - .stu-subtab span:not(.mdi):not(.stu-subtab-num) { display: none; } - .stu-subtab { padding: 8px 12px; } -} - -/* Nested sub-tabs inside Studio's Characters/Perform phases (smaller, inline) */ -.stu-inner-tabs { display: flex; gap: 4px; margin: 0 0 12px; } -.stu-book-context-btn { - display: inline-flex; align-items: center; gap: 6px; margin-right: 4px; - padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px; - cursor: pointer; background: var(--panel); color: var(--subtext); - font-size: 12.5px; font-weight: 600; -} -.stu-book-context-btn:hover { color: var(--accent); border-color: var(--accent); background: var(--surface); } -.stu-inner-tab { - padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; - background: var(--panel); color: var(--subtext); font-size: 12.5px; font-weight: 600; -} -.stu-inner-tab.active { background: var(--surface); color: var(--accent); border-color: var(--accent); } -.stu-mode-toggle { - display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; - border: 1px solid var(--border); border-radius: 8px; background: var(--panel); - font-size: 13px; font-weight: 600; margin: 0 0 14px; cursor: pointer; -} - -/* ── Auto-design voices (Phase 2) ───────────────────────────────────────── */ -.reh-autodesign { - border: 1px solid var(--border); border-radius: 10px; - padding: 12px 14px; margin: 4px 0 14px; - background: linear-gradient(180deg, rgba(37,99,235,.04), transparent); -} -.reh-autodesign-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; font-size: 13px; } -.reh-autodesign-head .note { font-weight: 400; } -.reh-autodesign-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; } -.reh-autodesign-row input, .reh-autodesign-row select { - width: 100%; padding: 6px 8px; border: 1px solid var(--border); - border-radius: 5px; background: var(--surface); color: var(--text); font-size: 12px; -} -.reh-llm-refresh { border: none; background: none; cursor: pointer; color: var(--accent); font-size: 13px; padding: 0 2px; } -.reh-autodesign-progress { display: flex; align-items: center; gap: 10px; margin-top: 10px; } - -/* Three casting options (local match / online match / design) */ -.reh-cast-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin-top: 12px; } -.reh-cast-opt { display: flex; gap: 10px; padding: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; } -.reh-co-num { flex-shrink: 0; width: 22px; height: 22px; border-radius: 50%; background: var(--accent); color: #fff; font-size: 12px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; } -.reh-co-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; } -.reh-co-body > strong { font-size: 13px; display: flex; align-items: center; gap: 6px; } -.reh-co-body > strong .mdi { color: var(--accent); } -.reh-co-body > p { font-size: 11.5px; color: var(--subtext); line-height: 1.45; margin: 0; } -.reh-co-body > p em { font-style: normal; color: var(--text); font-weight: 600; } -.reh-co-body > button { align-self: flex-start; margin-top: 2px; white-space: nowrap; } - -/* Per-character status pill while designing */ -.reh-cast-designing { opacity: .75; } -.reh-cast-design-badge { - font-size: 10px; padding: 1px 7px; border-radius: 10px; margin-left: 6px; - background: rgba(37,99,235,.12); color: var(--accent); font-weight: 600; -} -.reh-cast-design-badge.done { background: rgba(22,163,74,.15); color: var(--green); } -.reh-cast-design-badge.err { background: rgba(220,38,38,.15); color: var(--red); } - -/* ── Per-character auto-design detail panel ─────────────────────────────── */ -.reh-cast-design-panel { - margin: -4px 12px 8px 12px; padding: 10px 12px; - border: 1px solid rgba(37,99,235,.25); border-radius: 8px; - background: rgba(37,99,235,.05); display: flex; flex-direction: column; gap: 7px; - animation: reh-cdp-in .15s ease-out; -} -@keyframes reh-cdp-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } } -.reh-cast-design-panel.done { - border-color: rgba(22,163,74,.25); background: rgba(22,163,74,.04); -} -.reh-cdp-meta { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; } -.reh-cdp-chip { - font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 10px; - background: var(--panel); border: 1px solid var(--border); color: var(--subtext); - display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; -} -.reh-cdp-gender { color: #8b5cf6; border-color: rgba(139,92,246,.3); background: rgba(139,92,246,.07); } -.reh-cdp-lang { color: #0ea5e9; border-color: rgba(14,165,233,.3); background: rgba(14,165,233,.07); } -.reh-cdp-name { color: var(--accent); border-color: rgba(37,99,235,.3); background: rgba(37,99,235,.07); font-family: monospace; font-size: 10px; } -.reh-cdp-desc { - font-size: 11px; line-height: 1.5; color: var(--text); font-style: italic; - border-left: 2px solid var(--accent); padding-left: 8px; opacity: .85; -} -.reh-cdp-step { - display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--subtext); -} -.reh-cdp-step .reh-imsdb-spinner { border-top-color: var(--accent); } - -/* ── Drag & drop importer ───────────────────────────────────────────────── */ -.reh-dropzone { - margin-top: 14px; padding: 26px 16px; border: 2px dashed var(--border); - border-radius: 12px; text-align: center; color: var(--subtext); - display: flex; flex-direction: column; align-items: center; gap: 5px; - transition: border-color .15s, background .15s; cursor: default; -} -.reh-dropzone-icon { font-size: 34px; opacity: .5; } -.reh-dropzone.dragover { - border-color: var(--accent); background: rgba(37,99,235,.06); color: var(--accent); -} -.reh-dropzone.dragover .reh-dropzone-icon { opacity: 1; } - -/* ── Bookshelf library ──────────────────────────────────────────────────── */ -.reh-bookshelf { - display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); - gap: 18px 16px; padding: 6px 4px 4px; -} -.sk { 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; } -.lib-book-sk { background: linear-gradient(135deg, var(--panel), var(--border)) !important; opacity: .7; animation: none; cursor: default; } -.lib-book-sk .sk { border-radius: 4px; } -.reh-book { - position: relative; cursor: pointer; border-radius: 4px 7px 7px 4px; - aspect-ratio: 2 / 3; padding: 14px 12px 12px 18px; color: #fff; overflow: hidden; - box-shadow: 0 5px 14px rgba(0,0,0,.22), inset 3px 0 0 rgba(0,0,0,.18); - display: flex; flex-direction: column; - transition: transform .16s ease, box-shadow .16s ease; - background: linear-gradient(135deg, var(--bk1, #4f46e5), var(--bk2, #7c3aed)); -} -.reh-book::before { /* spine highlight */ - content: ''; position: absolute; left: 6px; top: 0; bottom: 0; width: 2px; - background: rgba(255,255,255,.25); -} -.reh-book:hover { transform: translateY(-5px) rotate(-.6deg); box-shadow: 0 12px 26px rgba(0,0,0,.3), inset 3px 0 0 rgba(0,0,0,.18); } -.reh-book-title { - font-size: 14px; font-weight: 800; line-height: 1.25; letter-spacing: .01em; - text-shadow: 0 1px 3px rgba(0,0,0,.35); display: -webkit-box; - -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; -} -.reh-book-meta { margin-top: auto; font-size: 10.5px; opacity: .9; line-height: 1.5; } -.reh-book-avatars { display: flex; gap: 3px; margin-bottom: 6px; flex-wrap: wrap; } -.reh-book-avatars span { - width: 19px; height: 19px; border-radius: 50%; font-size: 9px; font-weight: 700; - display: inline-flex; align-items: center; justify-content: center; - border: 1.5px solid rgba(255,255,255,.7); color: #fff; -} -.reh-book-progress { height: 3px; border-radius: 2px; background: rgba(255,255,255,.28); margin-top: 5px; overflow: hidden; } -.reh-book-progress > div { height: 100%; background: rgba(255,255,255,.9); } -.reh-book-actions { - position: absolute; top: 6px; right: 6px; display: flex; gap: 3px; opacity: 0; - transition: opacity .14s; -} -.reh-book:hover .reh-book-actions { opacity: 1; } -.reh-book-act { - width: 22px; height: 22px; border-radius: 5px; border: none; cursor: pointer; - background: rgba(0,0,0,.32); color: #fff; font-size: 12px; - display: inline-flex; align-items: center; justify-content: center; -} -.reh-book-act:hover { background: rgba(0,0,0,.55); } -.reh-book-active-tag { - position: absolute; top: 8px; left: 14px; font-size: 8.5px; font-weight: 700; - text-transform: uppercase; letter-spacing: .08em; background: rgba(255,255,255,.92); - color: #1a1a2e; padding: 1px 6px; border-radius: 8px; -} -/* List-view fallback reuses old rows */ -.reh-bookshelf.list-view { display: flex; flex-direction: column; gap: 8px; } -.reh-bookshelf.list-view .reh-book { - aspect-ratio: auto; flex-direction: row; align-items: center; gap: 12px; - padding: 10px 14px; color: var(--text); background: var(--panel) !important; - box-shadow: none; border: 1px solid var(--border); border-radius: 8px; -} -.reh-bookshelf.list-view .reh-book:hover { transform: none; } -.reh-bookshelf.list-view .reh-book::before { display: none; } -.reh-bookshelf.list-view .reh-book-title { -webkit-line-clamp: 1; text-shadow: none; font-size: 14px; } -.reh-bookshelf.list-view .reh-book-meta { margin: 0 0 0 auto; } -.reh-bookshelf.list-view .reh-book-actions { position: static; opacity: 1; } -.reh-bookshelf.list-view .reh-book-act { background: var(--surface); color: var(--text); border: 1px solid var(--border); } - -/* ── Multi-page (paginated) script view ─────────────────────────────────── */ -.reh-page-wrap.paginated { display: flex; flex-direction: column; align-items: center; gap: 22px; } -.reh-paper { - width: min(1180px, 96%); background: #fff; color: #1a1a2e; - padding: 56px 72px 40px; box-shadow: 0 4px 24px rgba(0,0,0,.18); - font-family: 'Courier New', Courier, monospace; font-size: calc(12pt * var(--reh-stage-scale, 1)); line-height: 1.6; - border-radius: 2px; position: relative; box-sizing: border-box; - min-height: min(1123px, calc((100vw - 32px) * 1.414)); -} -.reh-paper-num { - position: absolute; top: 20px; right: 32px; font-size: 10pt; color: #888; - font-family: 'Courier New', monospace; -} -[data-theme="dark"] .reh-paper { background: #f8f8f2; } - -/* Keep script-browser list rows readable even when old cached list styles collapse. */ -.reh-imsdb-grid.list-view > .reh-imsdb-card { - height: 48px !important; - min-height: 48px !important; - max-height: 48px; - overflow: hidden; -} -.reh-imsdb-grid.list-view > .reh-imsdb-card .reh-imsdb-meta { - height: 48px; - min-height: 48px; -} - - -.reh-bulk-hint { font-size:11px; color:var(--subtext); margin-right:4px; } -.reh-bulk-mode .reh-selected { - background: rgba(37,99,235,.11) !important; - outline: 2px solid rgba(37,99,235,.35); - outline-offset: -2px; -} -.reh-bulk-mode .reh-selected .reh-block-dialog { font-weight:600; } - -/* Keep script-browser thumbnail cards tall enough to click/download in cover view. */ -.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card { - display: flex !important; - flex-direction: column !important; - min-height: 230px !important; - height: auto !important; - overflow: hidden; -} -.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-poster-wrap { - display: block !important; - position: relative !important; - width: 100% !important; - aspect-ratio: 2 / 3 !important; - min-height: 178px !important; - height: auto !important; - padding-bottom: 0 !important; - flex: 0 0 auto !important; -} -.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-poster, -.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-fallback { - position: absolute !important; - inset: 0 !important; - width: 100% !important; - height: 100% !important; -} -.reh-imsdb-grid:not(.list-view) > .reh-imsdb-card .reh-imsdb-meta { - min-height: 46px; - flex: 0 0 auto; -} /* ── Read Aloud reader ─────────────────────────────────────────────────── */ .reader-controls {