tts-voice-creator-clone-and.../static/sections/s-rehearser.html
mARTin-B78 36437478a6 feat: Read Aloud reader, multi-voice audiobook casting, character sheets (v1.7.0)
Read Aloud (new "Vorlesen" tab):
- PDF (real page render + overlay highlight) / TXT reader with live word
  highlighting, voice + speed, per-sentence synthesis-state colours, zoom
  (fit-width/height, two-page, ±), resume, and a server-side book library
  (syncs across devices; per-unit MP3 audio fetched on demand).

Book -> multi-speaker audiobook:
- "Cast as audiobook" attributes dialogue to characters via the LLM
  (guillemet/quote-style aware, turn-taking, recent-context), with a
  deterministic speech-tag fallback. Editable preview, non-blocking live
  casting panel, then auto-saved as a reopenable Script Rehearser play.
- Audiobook export: synthesise every cast line -> one MP3 per chapter.

Character sheets:
- LLM-extracted, self-filling RPG-style sheets (with page+quote sources)
  in both Read Aloud and the Rehearser.

Also: MP3 storage + per-page/sentence export, voice-library "Precompute
embeddings" pre-warm, German "Vorlesen" i18n + flag language toggle,
large-PDF performance (lazy raster, buffer/canvas eviction, yielded parse),
and the Seed Finder changelog entry.

New: routes/reader.py, POST /api/attribute-dialogue, POST /api/character-sheets,
static/js/{reader,audiobook,character-sheets}.js, static/sections/s-reader.html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:08:46 +02:00

539 lines
36 KiB
HTML

<div class="section-head">
<span class="section-icon"><span class="mdi mdi-theater"></span></span>
<div class="section-title">
<h2>Script Rehearser</h2>
<p>Upload a script, cast characters to TTS voices or your own mic, then rehearse scene by scene.</p>
</div>
</div>
<!-- Phase sub-tabs -->
<div class="reh-subtabs" id="reh-subtabs">
<button class="reh-subtab active" data-phase="1"><span class="mdi mdi-bookshelf"></span> <span>Library</span></button>
<button class="reh-subtab" data-phase="2" disabled><span class="mdi mdi-account-group-outline"></span> <span>Cast</span></button>
<button class="reh-subtab" data-phase="3" disabled><span class="mdi mdi-theater"></span> <span>Stage</span></button>
<button class="reh-subtab" data-phase="4" disabled><span class="mdi mdi-check-circle-outline"></span> <span>Summary</span></button>
</div>
<div class="tab-content" id="tab-rehearser">
<!-- ── Import / Export panel (hidden unless nav item clicked) ── -->
<div class="reh-phase" id="reh-impex-panel" hidden>
<div class="card">
<h2><span class="mdi mdi-swap-vertical"></span> Import / Export</h2>
<p class="card-subtitle">Import a script or saved rehearsal, or export the current session in any format.</p>
<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">
<h4 class="reh-impex-cat" style="margin:0"><span class="mdi mdi-web"></span> Import from URL</h4>
<button class="btn-secondary btn-sm" id="reh-browse-imsdb-btn-impex" title="Browse 1300+ movie scripts from IMSDb"><span class="mdi mdi-movie-open-outline"></span> Browse scripts</button>
</div>
<div class="reh-impex-url-row">
<span class="mdi mdi-web reh-impex-url-icon"></span>
<input id="reh-impex-url" type="text" class="reh-impex-url-inp"
placeholder="https://www.imsdb.com/scripts/… or https://www.scripts.com/script/the_pianist_72/2"
spellcheck="false" autocomplete="off">
<button class="btn-primary" id="reh-impex-url-btn" type="button">
<span class="mdi mdi-download"></span> Fetch
</button>
</div>
<p class="reh-impex-note" id="reh-impex-url-status"></p>
<h4 class="reh-impex-cat" style="margin-top:14px"><span class="mdi mdi-import"></span> Import from file</h4>
<div class="reh-impex-grid">
<label class="reh-impex-btn">
<span class="mdi mdi-text-box-outline"></span>
<span>.txt / .md</span>
<input type="file" accept=".txt,.md" class="reh-impex-file" data-impex-type="text" style="display:none">
</label>
<label class="reh-impex-btn">
<span class="mdi mdi-file-pdf-box"></span>
<span>.pdf</span>
<input type="file" accept=".pdf" class="reh-impex-file" data-impex-type="pdf" style="display:none">
</label>
<label class="reh-impex-btn">
<span class="mdi mdi-fountain-pen-tip"></span>
<span>.fountain</span>
<input type="file" accept=".fountain" class="reh-impex-file" data-impex-type="fountain" style="display:none">
</label>
<label class="reh-impex-btn">
<span class="mdi mdi-file-code-outline"></span>
<span>.fdx / .osf</span>
<input type="file" accept=".fdx,.osf" class="reh-impex-file" data-impex-type="fdx" style="display:none">
</label>
<label class="reh-impex-btn reh-impex-btn--accent">
<span class="mdi mdi-book-open-variant"></span>
<span>.reh (session)</span>
<input type="file" accept=".reh,.json" class="reh-impex-file" data-impex-type="reh" style="display:none">
</label>
</div>
<h4 class="reh-impex-cat" style="margin-top:20px"><span class="mdi mdi-export"></span> Export</h4>
<p class="reh-impex-note" id="reh-impex-export-note"></p>
<div class="reh-impex-grid">
<button class="reh-impex-btn" id="reh-impex-reh-btn">
<span class="mdi mdi-book-open-variant"></span>
<span>.reh (session)</span>
</button>
<button class="reh-impex-btn" id="reh-impex-fountain-btn">
<span class="mdi mdi-fountain-pen-tip"></span>
<span>.fountain</span>
</button>
<button class="reh-impex-btn" id="reh-impex-fdx-btn">
<span class="mdi mdi-file-code-outline"></span>
<span>.fdx</span>
</button>
<button class="reh-impex-btn" id="reh-impex-txt-btn">
<span class="mdi mdi-text-box-outline"></span>
<span>.txt</span>
</button>
<button class="reh-impex-btn" id="reh-impex-md-btn">
<span class="mdi mdi-language-markdown-outline"></span>
<span>.md</span>
</button>
<button class="reh-impex-btn" id="reh-impex-osf-btn">
<span class="mdi mdi-xml"></span>
<span>.osf</span>
</button>
</div>
<div class="btn-row" style="margin-top:18px">
<button class="btn-secondary" onclick="navRehearserPhase(1)"><span class="mdi mdi-arrow-left"></span> Back to Library</button>
</div>
</div>
</div>
<!-- ── Phase 1: Library + new script ─────────────────────────── -->
<div class="reh-phase" id="reh-phase-1">
<div class="card">
<div class="reh-lib-header">
<h2 style="margin:0"><span class="mdi mdi-bookshelf"></span> Rehearsal library</h2>
<div style="display:flex;gap:8px;align-items:center">
<button class="btn-secondary btn-sm" id="reh-browse-imsdb-btn" title="Browse 1300+ movie scripts from IMSDb"><span class="mdi mdi-movie-open-outline"></span> Browse scripts</button>
<button class="btn-secondary btn-sm" id="reh-lib-view-toggle" title="Toggle shelf / list view"><span class="mdi mdi-view-list"></span></button>
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
<span class="mdi mdi-import"></span> Import .reh
<input type="file" id="reh-lib-import-file" accept=".reh,.json" style="display:none">
</label>
</div>
</div>
<div id="reh-library-list" class="reh-bookshelf">
<div class="reh-lib-empty"><span class="mdi mdi-book-open-outline"></span><p>No saved rehearsals yet.<br>Parse a script below to start.</p></div>
</div>
</div>
<!-- Drag & drop importer -->
<div class="reh-dropzone" id="reh-dropzone">
<span class="mdi mdi-cloud-upload-outline reh-dropzone-icon"></span>
<strong>Drag &amp; drop a script here</strong>
<span class="note">.txt · .md · .fountain · .pdf · .fdx · .osf · .reh</span>
</div>
<div class="card">
<div class="reh-new-script-head">
<h2 style="margin:0"><span class="mdi mdi-script-text-outline"></span> New script</h2>
<input type="text" id="reh-script-title" class="reh-script-title-inline" placeholder="Script title…">
</div>
<p class="card-subtitle">Paste a script below. Supports standard screenplay format (INT./EXT. headings, CHARACTER name on own line, dialog follows) as well as the simple <code>CHARACTER: text</code> format. Lines starting with <code>#</code> are explicit stage directions.</p>
<div class="reh-input-row">
<textarea id="reh-script-text" placeholder="EXT. LOCATION - DAY&#10;&#10;Scene description goes here.&#10;&#10;ALICE&#10;Hello, how are you?&#10;&#10;BOB&#10;I'm doing great, thank you!" spellcheck="false"></textarea>
<div class="reh-input-side">
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
<span class="mdi mdi-upload"></span> .txt / .md
<input type="file" id="reh-file-input" accept=".txt,.md,.fountain" style="display:none">
</label>
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
<span class="mdi mdi-file-pdf-box"></span> .pdf
<input type="file" id="reh-pdf-input" accept=".pdf" style="display:none">
</label>
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
<span class="mdi mdi-file-code-outline"></span> .fdx / .osf
<input type="file" id="reh-fdx-input" accept=".fdx,.osf,.xml" style="display:none">
</label>
<p class="note" style="font-size:11px;margin-top:8px">Supports:<br>• Screenplay: INT./EXT., CAPS names<br>• Theatre: ACT I / SCENE 1<br><code>CHAR: text</code> · <code># direction</code><br>• Import: .txt .fountain .pdf .fdx .osf</p>
</div>
</div>
<div class="btn-row" style="margin-top:12px">
<button class="btn-primary" id="reh-parse-btn"><span class="mdi mdi-auto-fix"></span> Parse &amp; cast</button>
</div>
</div>
</div>
<!-- ── Phase 2: Cast ──────────────────────────────────────────── -->
<div class="reh-phase" id="reh-phase-2" hidden>
<div class="card">
<h2><span class="mdi mdi-account-group-outline"></span> Cast your characters</h2>
<p class="card-subtitle">Assign a TTS voice or your mic to each character. Add a speaking-style note per character so the voice matches their personality.</p>
<div class="reh-cast2-backend">
<div class="field" style="flex:1;min-width:160px">
<label>TTS backend</label>
<select id="reh-backend-select"><option value="">Checking…</option></select>
</div>
<button class="btn-secondary" id="reh-fetch-voices-btn" style="align-self:flex-end"><span class="mdi mdi-refresh"></span> Fetch voices</button>
</div>
<!-- Narrator is now a regular cast entry — see NARRATOR row in cast list -->
<!-- Auto-cast: match characters to voices (local / online) or design new ones -->
<div class="reh-autodesign" role="group" aria-labelledby="reh-autocast-title">
<div class="reh-autodesign-head">
<span class="mdi mdi-auto-fix" style="color:var(--accent)" aria-hidden="true"></span>
<strong id="reh-autocast-title">Match characters with voices</strong>
<span class="note">— let an LLM cast every character automatically</span>
</div>
<div class="reh-autodesign-row">
<div class="field" style="flex:1;min-width:150px;margin:0">
<label for="reh-llm-url" style="font-size:11px">LLM endpoint</label>
<select id="reh-llm-url-sel" style="display:none" aria-hidden="true"></select>
<input type="text" id="reh-llm-url" placeholder="http://localhost:11434/v1" list="reh-llm-url-list" aria-label="LLM endpoint URL">
<datalist id="reh-llm-url-list"></datalist>
</div>
<div class="field" style="flex:1;min-width:150px;margin:0">
<label for="reh-llm-model" style="font-size:11px">Model <button class="reh-llm-refresh" id="reh-llm-refresh" title="List available models" aria-label="Refresh model list"></button></label>
<select id="reh-llm-model" aria-label="LLM model"><option value="">— default —</option></select>
</div>
<div class="field" style="min-width:90px;margin:0">
<label for="reh-design-lang" style="font-size:11px">Language</label>
<select id="reh-design-lang" aria-label="Voice language">
<option value="English">English</option>
<option value="German">German</option>
<option value="Auto">Auto</option>
<option value="French">French</option>
<option value="Spanish">Spanish</option>
<option value="Italian">Italian</option>
</select>
</div>
</div>
<!-- Three casting options -->
<div class="reh-cast-options">
<div class="reh-cast-opt">
<div class="reh-co-num">1</div>
<div class="reh-co-body">
<strong><span class="mdi mdi-bookshelf" aria-hidden="true"></span> Match from local library</strong>
<p>The LLM picks the best voice you already have (cloned · designed · imported) for each character. <em>No TTS engine required.</em></p>
<button class="btn-secondary" id="reh-matchlib-btn" title="LLM picks the best existing library voice for each character">
<span class="mdi mdi-account-search-outline" aria-hidden="true"></span> Match local
</button>
</div>
</div>
<div class="reh-cast-opt">
<div class="reh-co-num">2</div>
<div class="reh-co-body">
<strong><span class="mdi mdi-earth" aria-hidden="true"></span> Match from online (fish.audio)</strong>
<p>Search fish.audio's 2M public voices for the best fit per character and import them to your library. <em>Needs internet.</em></p>
<button class="btn-secondary" id="reh-matchonline-btn" title="Search fish.audio for a matching voice per character and import it">
<span class="mdi mdi-cloud-search-outline" aria-hidden="true"></span> Match online
</button>
</div>
</div>
<div class="reh-cast-opt">
<div class="reh-co-num">3</div>
<div class="reh-co-body">
<strong><span class="mdi mdi-magic-staff" aria-hidden="true"></span> Design new voices</strong>
<p>Generate a unique voice per character from the LLM's description. <em>Requires the <b>Voice Design</b> engine (Qwen3-TTS&nbsp;:8021).</em></p>
<button class="btn-primary" id="reh-autodesign-btn" title="Design a brand-new voice for each character via the Voice Design engine">
<span class="mdi mdi-magic-staff" aria-hidden="true"></span> Design all
</button>
</div>
</div>
</div>
<div class="reh-autodesign-progress" id="reh-autodesign-progress" hidden role="progressbar" aria-label="Casting progress">
<div class="reh-synth-track"><div class="reh-synth-fill" id="reh-autodesign-fill"></div></div>
<span id="reh-autodesign-label" class="reh-synth-label">0 / 0</span>
<button class="btn-secondary btn-sm" id="reh-autodesign-cancel" style="margin-left:8px">Cancel</button>
</div>
</div>
<div class="reh-cast-toolbar">
<span class="reh-cast-count" id="reh-cast-count"></span>
<div class="reh-cast-controls">
<input type="search" id="reh-cast-search" class="reh-cast-ctl reh-cast-search" placeholder="Filter name or tag…" autocomplete="off">
<select id="reh-cast-filter-gender" class="reh-cast-ctl" title="Filter by gender">
<option value="">All genders</option>
<option value="F">♀ Female</option>
<option value="M">♂ Male</option>
<option value="N">⚥ Diverse</option>
</select>
<select id="reh-cast-filter-lang" class="reh-cast-ctl" title="Filter by language">
<option value="">All languages</option>
<option>English</option><option>German</option><option>French</option>
<option>Spanish</option><option>Italian</option><option>Portuguese</option>
<option>Dutch</option><option>Polish</option><option>Auto</option>
</select>
<select id="reh-cast-sort" class="reh-cast-ctl" title="Sort characters by">
<option value="name">Sort: Name</option>
<option value="gender">Sort: Gender</option>
<option value="lang">Sort: Language</option>
<option value="lines">Sort: Lines</option>
<option value="tag">Sort: Tag</option>
</select>
<button type="button" id="reh-cast-sort-dir" class="reh-cast-ctl reh-cast-sortdir" title="Toggle ascending / descending" data-dir="asc"><span class="mdi mdi-sort-ascending"></span></button>
</div>
<div class="reh-view-toggle" id="reh-cast-view-toggle" role="tablist" aria-label="Cast view">
<button type="button" class="reh-view-btn active" data-view="card" title="Card view"><span class="mdi mdi-card-account-details-outline"></span> Cards</button>
<button type="button" class="reh-view-btn" data-view="list" title="List view"><span class="mdi mdi-format-list-bulleted"></span> List</button>
</div>
</div>
<div id="reh-cast-list" class="reh-cast-list reh-cast-view-card"></div>
<div class="btn-row" style="margin-top:14px">
<button class="btn-secondary" id="reh-back-1-btn"><span class="mdi mdi-arrow-left"></span> Back</button>
<button class="btn-secondary" id="reh-cast-save-btn"><span class="mdi mdi-content-save-outline"></span> Save to library</button>
<button class="btn-primary" id="reh-start-btn"><span class="mdi mdi-theater"></span> Open rehearsal</button>
</div>
</div>
</div>
<!-- ── Phase 3: Rehearsal ─────────────────────────────────────── -->
<div class="reh-phase reh-stage-wrap" id="reh-phase-3" hidden style="position:relative">
<!-- Director's console -->
<div class="reh-console" id="reh-transport-bar">
<div class="reh-cast-strip" id="reh-cast-strip"></div>
<div class="reh-console-transport">
<button class="reh-tb-btn" id="reh-tb-prev" title="Previous line"><span class="mdi mdi-skip-previous"></span></button>
<button class="reh-tb-btn reh-tb-play" id="reh-tb-play" title="Play all"><span class="mdi mdi-play"></span></button>
<button class="reh-tb-btn" id="reh-tb-stop" title="Stop"><span class="mdi mdi-stop"></span></button>
<button class="reh-tb-btn" id="reh-tb-next" title="Next line"><span class="mdi mdi-skip-next"></span></button>
<button class="reh-tb-btn" id="reh-tb-repeat" title="Loop"><span class="mdi mdi-repeat"></span></button>
</div>
<div class="reh-console-progress">
<div class="reh-tb-progress-wrap"><div class="reh-tb-progress" id="reh-tb-progress"></div></div>
<span class="reh-tb-label" id="reh-tb-label">0 / 0</span>
<span id="reh-practice-info" class="reh-practice-info" hidden>
<span style="color:#10b981"></span><span id="reh-practice-from">1</span>
<span style="color:#ef4444;margin-left:3px"></span><span id="reh-practice-to">1</span>
<button class="reh-tb-btn" id="reh-practice-clear" style="width:18px;height:18px;font-size:9px" title="Clear practice range"></button>
</span>
</div>
<div class="reh-console-actions">
<button class="btn-secondary btn-sm" id="reh-tb-synth-all" title="Pre-synthesize all TTS lines for instant playback">
<span class="mdi mdi-lightning-bolt"></span> Synth all
</button>
<button class="btn-secondary btn-sm" id="reh-tb-audiobook" title="Synthesise every line and download the audiobook as MP3 (one file per chapter)">
<span class="mdi mdi-book-music-outline"></span> Audiobook
</button>
<button class="btn-secondary btn-sm" id="reh-charsheets-btn" title="Extract actor-facing RPG-style character sheets (with sources) for this script">
<span class="mdi mdi-account-details-outline"></span> Character sheets
</button>
<button class="btn-secondary btn-sm" id="reh-tb-resynth-stale" title="Re-synthesize only lines whose tone changed" hidden>
<span class="mdi mdi-refresh" style="color:var(--red)"></span> Re-synth stale
</button>
<label class="chunk-toggle-label" style="font-size:11px;gap:4px;white-space:nowrap" title="Skip scene headings &amp; action descriptions during playback">
<input type="checkbox" id="reh-skip-desc-toggle" checked>
<span>Skip desc.</span>
</label>
<button class="btn-secondary btn-sm" id="reh-bulk-toggle" title="Bulk edit lines — select to ignore, hide or delete"><span class="mdi mdi-checkbox-multiple-marked-outline"></span> Select</button>
<button class="btn-secondary btn-sm" id="reh-edit-script-btn" title="Edit script &amp; title"><span class="mdi mdi-pencil"></span></button>
<button class="btn-secondary btn-sm" id="reh-tb-save" title="Save to library"><span class="mdi mdi-content-save-outline"></span> Save</button>
<button class="btn-secondary btn-sm" id="reh-tb-export" title="Export .reh"><span class="mdi mdi-export"></span></button>
<button class="btn-secondary btn-sm" id="reh-fountain-btn" title="Export as .fountain (plain text)"><span class="mdi mdi-file-document-outline"></span></button>
<button class="btn-secondary btn-sm" id="reh-page-mode-btn" title="Switch between A4 pages / scroll / PDF pages"><span class="mdi mdi-file-document-outline"></span> A4 pages</button>
<button class="btn-secondary btn-sm" id="reh-train-open-btn" title="Train mode — practice your lines with cue playback &amp; speech recognition"><span class="mdi mdi-school-outline"></span> Train</button>
<button class="btn-secondary btn-sm" id="reh-exit-btn">Exit</button>
</div>
</div>
<!-- Bulk-edit action bar (shown when "Select" mode is on) -->
<div class="reh-bulk-bar" id="reh-bulk-bar" hidden>
<span class="reh-bulk-count" id="reh-bulk-count">0 selected</span>
<span class="reh-bulk-hint">Click lines to select · Shift-click range</span>
<button class="btn-secondary btn-sm" id="reh-bulk-all" title="Select all visible lines"><span class="mdi mdi-select-all"></span> All</button>
<button class="btn-secondary btn-sm" id="reh-bulk-none" title="Clear selection">Clear</button>
<button class="btn-secondary btn-sm" id="reh-bulk-range" title="Set playback range to the selected lines"><span class="mdi mdi-playlist-play"></span> Set range</button>
<span class="reh-bulk-sep"></span>
<button class="btn-secondary btn-sm" id="reh-bulk-ignore" title="Grey out &amp; skip these lines during playback/synth"><span class="mdi mdi-eye-off-outline"></span> Ignore</button>
<button class="btn-secondary btn-sm" id="reh-bulk-unignore" title="Restore ignored lines"><span class="mdi mdi-eye-outline"></span> Un-ignore</button>
<button class="btn-secondary btn-sm" id="reh-bulk-hide" title="Hide these lines from the script view"><span class="mdi mdi-minus-circle-outline"></span> Hide</button>
<button class="btn-secondary btn-sm" id="reh-bulk-delete" title="Delete these lines permanently"><span class="mdi mdi-trash-can-outline" style="color:var(--red)"></span> Delete</button>
<span class="reh-bulk-sep"></span>
<label class="chunk-toggle-label" style="font-size:11px;gap:4px;white-space:nowrap" title="Reveal hidden lines so you can restore them">
<input type="checkbox" id="reh-bulk-show-hidden">
<span>Show hidden</span>
</label>
<span class="reh-bulk-spacer"></span>
<button class="btn-secondary btn-sm" id="reh-bulk-done" title="Leave bulk-edit mode"><span class="mdi mdi-check"></span> Done</button>
</div>
<!-- Tone / style warning (shown when backend doesn't support style instructions) -->
<div class="reh-tone-warn" id="reh-tone-warn" hidden>
<span class="mdi mdi-alert-outline"></span>
<span id="reh-tone-warn-txt">The current TTS backend has weak style support — tone selections may have little or no effect.</span>
<button class="reh-tone-warn-close" id="reh-tone-warn-close" title="Dismiss"></button>
</div>
<!-- Synthesis progress bar -->
<div class="reh-synth-bar" id="reh-synth-bar" hidden>
<span class="reh-imsdb-spinner" style="flex-shrink:0"></span>
<span class="reh-synth-bar-lbl"><span class="mdi mdi-lightning-bolt"></span> Synthesizing</span>
<div class="reh-synth-track"><div class="reh-synth-fill" id="reh-synth-fill"></div></div>
<span id="reh-synth-label" class="reh-synth-label">0 / 0</span>
<button class="btn-secondary btn-sm" id="reh-synth-cancel">Cancel</button>
</div>
<!-- Stage -->
<div class="reh-stage-area">
<!-- A4 script page -->
<div class="reh-page-wrap">
<div class="reh-a4-page" id="reh-a4-page">
<div class="reh-page-title" id="reh-page-title"></div>
<div class="reh-script-lines" id="reh-script-lines"></div>
</div>
</div>
</div>
<!-- TTS now-playing bar -->
<div class="reh-tts-status-bar" id="reh-tts-status-bar" hidden>
<span class="mdi mdi-volume-high" style="font-size:16px;color:var(--accent)"></span>
<span id="reh-tts-status-txt" style="flex:1;font-size:13px"></span>
<audio id="reh-tts-audio" controls style="max-width:240px;height:28px"></audio>
</div>
<!-- My-turn recording panel -->
<div class="reh-rec-overlay" id="reh-rec-overlay" hidden>
<div class="reh-rec-inner">
<div class="reh-rec-cue" id="reh-rec-cue"></div>
<div class="reh-rec-controls">
<div class="reh-rec-meter-col">
<div class="mic-monitor-head">
<span>Input level</span>
<span class="meter-readout" id="reh-db-readout">-∞ dB</span>
</div>
<div class="mic-meter" id="reh-mic-meter" aria-hidden="true"></div>
<canvas id="reh-live-wave" class="mic-live-wave" width="300" height="40" aria-hidden="true"></canvas>
</div>
<div class="reh-rec-btn-col">
<div class="btn-row" style="gap:8px;flex-wrap:wrap">
<button class="btn-red" id="reh-rec-start"><span class="mdi mdi-record-circle-outline"></span> Record</button>
<button class="btn-secondary" id="reh-rec-stop" disabled><span class="mdi mdi-stop-circle-outline"></span> Stop</button>
<span class="mic-timer" id="reh-rec-time">0:00</span>
<button class="btn-secondary" id="reh-skip-line">Skip</button>
</div>
<audio id="reh-rec-preview" controls style="display:none;width:100%;margin-top:8px"></audio>
<div class="btn-row" style="margin-top:8px" id="reh-rec-confirm-row" hidden>
<button class="btn-green" id="reh-rec-keep"><span class="mdi mdi-check"></span> Keep &amp; continue</button>
<button class="btn-secondary" id="reh-rec-redo"><span class="mdi mdi-refresh"></span> Re-record</button>
</div>
</div>
</div>
</div>
</div>
<!-- ── Train Mode panel ─────────────────────────────────────── -->
<div class="reh-train-panel" id="reh-train-panel" hidden>
<div class="reh-train-header">
<span class="reh-train-badge"><span class="mdi mdi-school-outline"></span> TRAIN</span>
<span id="reh-train-progress" class="reh-train-progress">Turn 1 / 1</span>
<div style="flex:1"></div>
<button class="btn-secondary btn-sm" id="reh-train-exit-btn"><span class="mdi mdi-close"></span> Exit train mode</button>
</div>
<!-- Cue card: what the other character says -->
<div class="reh-train-cue card" id="reh-train-cue">
<div class="reh-train-cue-head">
<span id="reh-train-cue-avatar" class="reh-train-cue-avatar"></span>
<span id="reh-train-cue-speaker" class="reh-train-cue-speaker"></span>
<span class="reh-train-cue-tag">Cue</span>
<span id="reh-train-cue-state" class="reh-train-cue-state"></span>
</div>
<div id="reh-train-cue-text" class="reh-train-cue-text"></div>
</div>
<!-- My line card -->
<div class="reh-train-myline card">
<div class="reh-train-myline-head">
<span class="mdi mdi-microphone" style="color:var(--accent)"></span>
<span id="reh-train-my-speaker" class="reh-train-cue-speaker"></span>
<span class="reh-train-cue-tag reh-train-me-tag">Your line</span>
</div>
<div id="reh-train-my-text" class="reh-train-my-text"></div>
</div>
<!-- Recording area -->
<div class="reh-train-rec card" id="reh-train-rec">
<div class="reh-train-rec-head">
<span id="reh-train-rec-state" class="reh-train-rec-state">Read the lines above · press ▶ to hear the cue, then 🎤 to record</span>
<span class="reh-train-rec-timer" id="reh-train-rec-timer" hidden>0:00</span>
</div>
<div class="reh-train-meters" id="reh-train-meters" hidden>
<div class="mic-monitor-head"><span>Input level</span><span class="meter-readout" id="reh-train-db">-∞ dB</span></div>
<div class="mic-meter" id="reh-train-meter"></div>
<canvas id="reh-train-wave" class="mic-live-wave" width="300" height="36"></canvas>
</div>
<audio id="reh-train-audio-preview" style="display:none;width:100%;margin-top:8px" controls></audio>
</div>
<!-- Comparison result -->
<div class="reh-train-result card" id="reh-train-result" hidden>
<div class="reh-train-result-head">
<span class="mdi mdi-compare-horizontal"></span> Result
<span id="reh-train-score" class="reh-train-score"></span>
</div>
<div id="reh-train-expected" class="reh-train-compare-row">
<span class="reh-train-compare-lbl">Script:</span>
<span id="reh-train-expected-text" class="reh-train-compare-text"></span>
</div>
<div id="reh-train-actual" class="reh-train-compare-row">
<span class="reh-train-compare-lbl">You said:</span>
<span id="reh-train-actual-text" class="reh-train-compare-text"></span>
</div>
</div>
<!-- Controls -->
<div class="reh-train-controls">
<button class="reh-tb-btn" id="reh-train-prev" title="Previous turn"><span class="mdi mdi-skip-previous"></span></button>
<button class="reh-tb-btn" id="reh-train-play" title="Play cue"><span class="mdi mdi-play"></span></button>
<button class="reh-tb-btn reh-train-rec-btn" id="reh-train-record" title="Start recording" disabled><span class="mdi mdi-microphone"></span></button>
<button class="reh-tb-btn" id="reh-train-stop-rec" title="Stop recording" disabled hidden><span class="mdi mdi-stop-circle-outline"></span></button>
<button class="reh-tb-btn" id="reh-train-next" title="Next turn"><span class="mdi mdi-skip-next"></span></button>
<button class="reh-tb-btn" id="reh-train-repeat" title="Repeat cue"><span class="mdi mdi-repeat"></span></button>
</div>
</div>
</div><!-- /phase-3 -->
<!-- ── Phase 4: Summary ───────────────────────────────────────── -->
<div class="reh-phase" id="reh-phase-4" hidden>
<div class="card">
<h2><span class="mdi mdi-check-circle-outline"></span> Session complete</h2>
<p class="card-subtitle">All recorded and synthesized clips from this session.</p>
<div id="reh-summary-list" class="reh-summary-list"></div>
<div class="btn-row" style="margin-top:14px;flex-wrap:wrap">
<button class="btn-primary" id="reh-save-session-btn"><span class="mdi mdi-content-save"></span> Save to library</button>
<button class="btn-secondary" id="reh-export-session-btn" title="Export full session with audio"><span class="mdi mdi-export"></span> .reh</button>
<button class="btn-secondary" id="reh-fountain-export-p4" title="Export script as .fountain text"><span class="mdi mdi-fountain-pen-tip"></span> .fountain</button>
<button class="btn-secondary" id="reh-fdx-export-btn" title="Export as Final Draft XML"><span class="mdi mdi-file-code-outline"></span> .fdx</button>
<button class="btn-secondary" id="reh-osf-export-btn" title="Export as Open Screenplay Format XML"><span class="mdi mdi-xml"></span> .osf</button>
<button class="btn-secondary" id="reh-resume-btn"><span class="mdi mdi-theater"></span> Resume</button>
<button class="btn-secondary" id="reh-new-session-btn"><span class="mdi mdi-refresh"></span> New script</button>
</div>
</div>
</div>
<!-- ── IMSDb browser modal (global, accessible from Library + Import/Export) ── -->
<div class="reh-imsdb-modal" id="reh-imsdb-modal" hidden>
<div class="reh-imsdb-box">
<div class="reh-imsdb-head">
<h3><span class="mdi mdi-movie-open-outline"></span> Script Library</h3>
<input type="text" id="reh-imsdb-search" class="reh-imsdb-search" placeholder="Search IMSDb titles…" spellcheck="false" autocomplete="off">
<span id="reh-imsdb-count" class="reh-imsdb-count"></span>
<a class="btn-secondary btn-sm reh-scripts-link" href="https://www.scripts.com" target="_blank" rel="noopener" title="Open Scripts.com"><span class="mdi mdi-open-in-new"></span> Scripts.com</a>
<div class="reh-imsdb-view-btns">
<button class="reh-imsdb-view-btn active" id="reh-imsdb-cover-btn" title="Cover view"><span class="mdi mdi-view-grid-outline"></span></button>
<button class="reh-imsdb-view-btn" id="reh-imsdb-list-btn" title="List view"><span class="mdi mdi-view-list-outline"></span></button>
</div>
<button class="btn-secondary btn-sm" id="reh-imsdb-close"><span class="mdi mdi-close"></span></button>
</div>
<div class="reh-imsdb-url-row">
<input type="text" id="reh-imsdb-url" class="reh-imsdb-url-input" placeholder="Paste IMSDb or Scripts.com URL…" spellcheck="false" autocomplete="off">
<button type="button" class="btn-primary btn-sm" id="reh-imsdb-url-fetch"><span class="mdi mdi-download"></span> Fetch URL</button>
</div>
<div class="reh-imsdb-grid" id="reh-imsdb-grid">
<div class="reh-imsdb-loading"><span class="reh-imsdb-spinner"></span> Loading catalogue…</div>
</div>
</div>
</div>
</div><!-- /tab-rehearser -->