tts-voice-creator-clone-and.../static/sections/s-magazine.html
mARTin-B78 5a7c73ea42 feat(export): provenance tags and optional disclosure for exported audio
ID3 provenance tags (synthetic speech, generator, version, date, opt-in
voice name) on magazine MP3/ZIP/EPUB exports via a stream-copied temp copy;
verify endpoint and CLI; AudioSeal tier is a documented stub.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 17:02:41 +02:00

463 lines
35 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="section-head">
<span class="section-icon"><span class="mdi mdi-newspaper-variant-outline"></span></span>
<div class="section-title">
<h2>Magazines</h2>
<p>Listen to a magazine one article at a time &mdash; from its true beginning to its true end, without adverts, sidebars or a neighbouring piece spliced into the middle.</p>
</div>
</div>
<!-- ── Library ──────────────────────────────────────────────────────── -->
<div id="mag-view-library">
<div class="card mag-new">
<h3>Add a magazine or paper</h3>
<div class="reader-source-grid">
<div class="reader-paste-panel">
<div class="reader-source-method">
<span class="mdi mdi-file-document-edit-outline"></span>
<div><strong>Import &amp; Metadata</strong><span>Select a PDF file or configure optional title and issue details.</span></div>
</div>
<div class="mag-new-grid" style="margin-top: 4px; margin-bottom: 4px;">
<label for="mag-new-title">Title <span class="muted">(optional)</span>
<input id="mag-new-title" type="text" placeholder="Auto-filled from PDF filename if blank" autocomplete="off">
</label>
<label for="mag-new-issue">Issue <span class="muted">(optional)</span>
<input id="mag-new-issue" type="text" placeholder="e.g. September 2026" autocomplete="off">
</label>
</div>
<div class="reader-paste-actions" style="margin-top: auto; padding-top: 6px;">
<label class="btn-primary btn-sm reader-file-pick" id="mag-browse-btn" title="Choose a PDF file or page images (PNG/JPEG) from your computer">
<span class="mdi mdi-folder-open-outline"></span> Durchsuchen
<input type="file" id="mag-new-file" accept="application/pdf,image/png,image/jpeg" multiple style="display:none">
</label>
</div>
</div>
<div class="reader-dropzone" id="mag-dropzone" style="cursor: pointer;">
<span class="mdi mdi-cloud-upload-outline reader-dropzone-icon" id="mag-dropzone-icon"></span>
<strong id="mag-dropzone-title">Drop a PDF or page images</strong>
<span class="note" id="mag-dropzone-note">Scanned issues work too &mdash; pages without selectable text are read with OCR.</span>
<div class="mag-dropzone-progress" id="mag-dropzone-progress" hidden>
<div class="mag-dropzone-progress-bar"></div>
</div>
<label class="btn-secondary btn-sm reader-file-pick" id="mag-dropzone-pick-btn" title="Choose a PDF file or page images (PNG/JPEG)">
<span class="mdi mdi-file-upload-outline"></span> Import PDF or images
</label>
</div>
</div>
</div>
<div class="card mag-find">
<h3>Find an issue online</h3>
<p class="note">Search the Internet Archive and any OPDS catalogue you have set up (Calibre-Web, Kavita, Komga). Only freely downloadable PDFs are listed; check the licence shown before you use one.</p>
<form class="mag-find-form" id="mag-find-form" onsubmit="magFindSearch(event)" role="search">
<label for="mag-find-source">Source
<select id="mag-find-source"></select>
</label>
<label for="mag-find-query" class="mag-find-query">Search
<input id="mag-find-query" type="search" maxlength="200" autocomplete="off" placeholder="e.g. Scientific American 1923">
</label>
<button type="submit" class="btn-primary btn-sm" id="mag-find-btn"><span class="mdi mdi-magnify" aria-hidden="true"></span> Search</button>
</form>
<details class="mag-cat" id="mag-cat">
<summary>Your catalogues (OPDS)</summary>
<p class="note">Add your own library (Calibre-Web, Kavita, Komga) or any OPDS address. If it needs a login, enter the username and the <strong>name of the environment variable</strong> that holds the password &mdash; the password itself is never stored here.</p>
<ul class="mag-cat-list" id="mag-cat-list"></ul>
<form class="mag-cat-form" id="mag-cat-form" onsubmit="magCatAdd(event)">
<label for="mag-cat-name">Name <input id="mag-cat-name" type="text" maxlength="80" autocomplete="off" placeholder="My NAS"></label>
<label for="mag-cat-url">Address <input id="mag-cat-url" type="url" required maxlength="500" autocomplete="off" placeholder="http://nas.local:8083/opds/"></label>
<label for="mag-cat-user">Username <span class="muted">(optional)</span> <input id="mag-cat-user" type="text" maxlength="120" autocomplete="off"></label>
<label for="mag-cat-env">Password variable <span class="muted">(optional)</span> <input id="mag-cat-env" type="text" maxlength="64" autocomplete="off" placeholder="NAS_OPDS_PASSWORD" pattern="[A-Z_][A-Z0-9_]*"></label>
<button type="submit" class="btn-secondary btn-sm"><span class="mdi mdi-plus" aria-hidden="true"></span> Add catalogue</button>
</form>
<p class="note" id="mag-cat-status" role="status" aria-live="polite"></p>
</details>
<p class="note" id="mag-find-status" role="status" aria-live="polite"></p>
<ul class="mag-find-results" id="mag-find-results"></ul>
</div>
<h3>Your magazines</h3>
<div id="mag-library-list" class="mag-grid"></div>
</div>
<!-- ── Contents ─────────────────────────────────────────────────────── -->
<div id="mag-view-contents" hidden>
<div class="mag-bar">
<button type="button" class="btn-sm" onclick="magBackToLibrary()">
<span class="mdi mdi-arrow-left"></span> All magazines
</button>
<h3 id="mag-doc-title" contenteditable="true" spellcheck="false" title="Click to edit the magazine title"
onblur="magCommitDocField(this, 'title')"
onkeydown="if(event.key==='Enter'){event.preventDefault();this.blur();}">Magazine</h3>
<input id="mag-doc-issue" type="text" class="mag-doc-issue-input" placeholder="Issue, e.g. September 2026"
title="Issue date -- used for the year/month in exported MP3 filenames"
onblur="magCommitDocField(this, 'issue')"
onkeydown="if(event.key==='Enter'){this.blur();}">
<div class="mag-bar-actions">
<button type="button" class="btn-sm" id="mag-quality-run-btn" onclick="magQualityRun()"
title="Fix every page automatically (boxes, inset pull quotes, missed text, misread words, spelling) and list the pages that still need a look">
<span class="mdi mdi-clipboard-check-outline"></span> <span class="mag-qrun-label">Auto-fix all pages</span>
</button>
<button type="button" class="btn-sm" id="mag-contents-view-toggle" onclick="magToggleContentsView()" title="Switch between an article list and a page-by-page thumbnail grid">
<span class="mdi mdi-view-grid-outline"></span> Thumbnails
</button>
<span class="mag-cols-control" id="mag-cols-control" hidden>
<label for="mag-cols-range">Columns</label>
<input type="range" id="mag-cols-range" min="1" max="12" step="1" value="8" oninput="magSetPagesCols(this.value)">
<span id="mag-cols-value" class="muted">8</span>
</span>
<button type="button" class="btn-sm" id="mag-contents-select-toggle" aria-pressed="false" onclick="magContentsToggleSelect()" title="Select several articles to approve or reject at once">
<span class="mdi mdi-checkbox-multiple-marked-outline"></span> Select
</button>
<button type="button" class="btn-sm" id="mag-playlist-toggle" aria-pressed="false" onclick="magTogglePlaylist()"
title="Show every article with a generated MP3, in reading order, with a player">
<span class="mdi mdi-playlist-music-outline"></span> Playlist
</button>
<button type="button" class="btn-sm" id="mag-driving-open" onclick="magOpenDriving()"
title="Open the magazine playlist with large, distraction-free controls">
<span class="mdi mdi-car-outline"></span> Driving mode
</button>
<button type="button" class="btn-sm" id="mag-share-book" onclick="magShare()"
aria-label="Share a link that opens this magazine in driving mode" title="Share a link that opens this magazine in driving mode">
<span class="mdi mdi-share-variant-outline" aria-hidden="true"></span> Share
</button>
<button type="button" class="btn-sm primary" onclick="magPlayAll()">
<span class="mdi mdi-playlist-play"></span> Play all articles
</button>
<button type="button" class="btn-sm" onclick="magIngest()">
<span class="mdi mdi-refresh"></span> Re-run detection
</button>
<button type="button" class="btn-sm" onclick="magReocrMagazine()" title="Send every page through the configured OCR engine again, then re-detect articles">
<span class="mdi mdi-text-recognition"></span> OCR again (whole magazine)
</button>
<button type="button" class="btn-sm" id="mag-refine-all-figures-btn" onclick="magRefineAllFigures()"
title="Batch-check figure boundaries on every page in this magazine">
<span class="mdi mdi-image-auto-adjust"></span> Fix all figure boundaries
</button>
</div>
</div>
<div id="mag-quality-report" class="mag-quality-report" role="region" aria-label="Quality check result" aria-live="polite" hidden></div>
<div id="mag-contents-bulkbar" class="mag-bulkbar" hidden></div>
<div class="mag-audio-export">
<label for="mag-audio-voice">Narrator for exported MP3s</label>
<select id="mag-audio-voice"></select>
<label for="mag-audio-interview-voice">Interview voice 2 (optional)</label>
<select id="mag-audio-interview-voice" title="When an article contains two recurring speaker labels, the second speaker uses this voice. Normal articles are unaffected.">
<option value="">— use narrator only —</option>
</select>
<button type="button" class="btn-sm" id="mag-audio-export-btn" onclick="magGenerateAllAudio()"
title="Render every approved article that doesn't already have an MP3 -- title, author, cover image and full text embedded as tags -- for a phone's own music/podcast player or a car head unit. Safe to click again after an aborted run: already-generated articles are skipped.">
<span class="mdi mdi-file-music-outline"></span> Generate all audio (MP3)
</button>
<button type="button" class="btn-sm" id="mag-audio-rebuild-btn" onclick="magGenerateAllAudio(true)"
title="Rebuild every approved MP3 using the latest OCR cleanup, pronunciation and interview-voice settings. Existing files are replaced.">
<span class="mdi mdi-refresh"></span> Regenerate all MP3s
</button>
<a class="btn-sm" id="mag-audio-zip-link" href="#" hidden download>
<span class="mdi mdi-folder-zip-outline"></span> Download all (ZIP)
</a>
<a class="btn-sm" id="mag-epub-link" href="#" hidden download
title="An EPUB 3 book whose text highlights while the audio plays (Media Overlays). Approved articles that already have audio.">
<span class="mdi mdi-book-open-page-variant-outline" aria-hidden="true"></span> EPUB with audio
</a>
<label class="muted" for="mag-prov-tags" title="Writes tags into the exported copy (stored audio is unchanged): synthetic speech, generator, version, date. No names or paths.">
<input type="checkbox" id="mag-prov-tags" checked onchange="magProvChanged()"> Mark as synthetic speech (tags)
</label>
<label class="muted" for="mag-prov-voice" title="Also write the voice name into the tags.">
<input type="checkbox" id="mag-prov-voice" onchange="magProvChanged()"> include voice name
</label>
<span class="mag-audio-export-progress-wrap" hidden id="mag-audio-export-progress-wrap">
<progress id="mag-audio-export-progress" max="1" value="0"></progress>
<span id="mag-audio-export-count" class="muted"></span>
</span>
<span id="mag-audio-export-status" class="muted" role="status" aria-live="polite"></span>
</div>
<div id="mag-playlist" class="mag-playlist" hidden>
<div class="mag-playlist-heading">
<div>
<strong>Magazine playlist</strong>
<span class="muted">Page · article · duration</span>
</div>
<label class="mag-karaoke-toggle" title="Highlight the sentence and word approximately as the MP3 plays">
<input type="checkbox" id="mag-playlist-karaoke" checked onchange="magPlaylistSync()">
Follow spoken text
</label>
</div>
<div class="mag-playlist-player">
<img id="mag-playlist-cover" class="mag-playlist-cover" alt="" hidden>
<div class="mag-playlist-nowplaying">
<strong id="mag-playlist-title">—</strong>
<span id="mag-playlist-sub" class="muted"></span>
<audio id="mag-playlist-audio" controls preload="none" style="width:100%"></audio>
</div>
<button type="button" class="btn-sm" onclick="magShareCurrent()" title="Share a link to this article" aria-label="Share a link to this article">
<span class="mdi mdi-share-variant-outline" aria-hidden="true"></span>
</button>
<button type="button" class="btn-sm" onclick="magTogglePlaylist()" title="Close playlist" aria-label="Close playlist">
<span class="mdi mdi-close"></span>
</button>
</div>
<ol id="mag-playlist-tracks" class="mag-playlist-tracks"></ol>
<div id="mag-playlist-companion" class="mag-playlist-companion" hidden>
<figure id="mag-playlist-visual" class="mag-playlist-visual" hidden></figure>
<div>
<div id="mag-playlist-sync-note" class="mag-playlist-sync-note muted">Text timing is estimated from the MP3 position.</div>
<article id="mag-playlist-transcript" class="mag-playlist-transcript" aria-label="Article transcript"></article>
</div>
</div>
</div>
<div id="mag-ingest-status" class="mag-status" hidden></div>
<!-- Decorative "watch it work" visualisation -- the essential
progress information (percentage, page count, done/failed) is
in #mag-ingest-status above, which is what a screen reader user
needs; this panel adds nothing beyond that but noisy churn. -->
<div id="mag-ingest-preview" class="mag-ingest-preview" hidden aria-hidden="true">
<div class="mag-ingest-preview-side">
<span class="mag-ingest-preview-label">Page <span id="mag-ingest-preview-stage"></span></span>
<div class="mag-ingest-preview-canvas">
<img id="mag-ingest-preview-img" alt="Page currently being read">
<div id="mag-ingest-preview-boxes" class="mag-ingest-preview-boxes"></div>
</div>
<div id="mag-ingest-preview-legend" class="mag-ingest-preview-legend"></div>
</div>
<div class="mag-ingest-preview-resize" id="mag-ingest-preview-resize" role="separator" aria-orientation="vertical" aria-label="Resize page and recognised text panes" title="Drag to resize page and recognised text panes"></div>
<div class="mag-ingest-preview-side">
<span class="mag-ingest-preview-label">Recognised text</span>
<div id="mag-ingest-preview-text" class="mag-ingest-preview-text"></div>
</div>
</div>
<div id="mag-contents"></div>
</div>
<!-- ── Review (Stage D) ─────────────────────────────────────────────── -->
<div id="mag-view-review" hidden>
<div class="mag-bar">
<h3>Review article boundaries</h3>
</div>
<div id="mag-review"></div>
</div>
<!-- ── Reading ──────────────────────────────────────────────────────── -->
<div id="mag-view-read" hidden>
<div class="mag-bar">
<button type="button" class="btn-sm" onclick="magBackToContents()">
<span class="mdi mdi-arrow-left"></span> Contents
</button>
<div class="mag-read-id">
<h3 id="mag-read-title">Article</h3>
<span id="mag-read-by" class="muted"></span>
<span id="mag-read-pages" class="muted"></span>
</div>
<button type="button" class="btn-sm" onclick="magToggleDriving()" title="Large controls for listening without looking at the screen">
<span class="mdi mdi-car-outline"></span> Driving mode
</button>
</div>
<div class="mag-controls">
<div class="mag-voice-pick">
<label for="mag-voice">Narrator</label>
<select id="mag-voice"></select>
</div>
<button type="button" class="btn primary" id="mag-play" onclick="magPlay()"
aria-label="Play narration">
<span class="mdi mdi-play"></span> Listen
</button>
<button type="button" class="btn" id="mag-prepare" onclick="magPrepareAudio()"
title="Synthesise the whole article now, so it plays straight through without waiting sentence by sentence">
<span class="mdi mdi-waveform"></span> Prepare audio
</button>
<span id="mag-prep-status" class="muted" role="status" aria-live="polite"></span>
<span id="mag-read-progress" class="muted" aria-live="polite"></span>
<span id="mag-queue-progress" class="muted" aria-live="polite"></span>
<label class="mag-karaoke-toggle" title="Highlight each word approximately as it is spoken">
<input type="checkbox" id="mag-karaoke-cb" checked onchange="TTVC.magazine.karaoke = this.checked">
Word highlighting
</label>
<label class="mag-karaoke-toggle" title="Speak each figure's description where it appears, if one has been generated in review. Takes effect next time this article is opened.">
<input type="checkbox" id="mag-read-descriptions">
Read figure descriptions
</label>
<div class="mag-pane-tabs" role="group" aria-label="Reading view">
<button type="button" class="btn-sm active" data-mag-pane="reflow"
aria-pressed="true" onclick="magSetPane('reflow')">Article</button>
<button type="button" class="btn-sm" data-mag-pane="pdf"
aria-pressed="false" onclick="magSetPane('pdf')">Original page</button>
</div>
</div>
<div id="mag-pane-reflow" class="mag-pane">
<div id="mag-read-image" class="mag-read-image" hidden></div>
<div id="mag-article" class="mag-article"></div>
</div>
<div id="mag-pane-pdf" class="mag-pane" hidden>
<div class="mag-page-wrap">
<img id="mag-page-img" alt="">
<div id="mag-page-box" class="mag-page-box" hidden></div>
</div>
<p id="mag-page-label" class="muted"></p>
</div>
<!-- Pronunciation and spelling -->
<details class="card mag-checks" id="mag-checks" ontoggle="magChecksToggled(this)">
<summary><span class="mdi mdi-spellcheck"></span> Pronunciation &amp; spelling &mdash; check this article</summary>
<div id="mag-checks-body" aria-live="polite"></div>
</details>
<!-- Podcast mode -->
<details class="card mag-podcast">
<summary><span class="mdi mdi-podcast"></span> Podcast mode &mdash; discuss this article</summary>
<p class="muted">Two or three hosts discuss the article for someone who has not read it. The script is written by the configured LLM from the article text; it will not invent facts, but it is a generated discussion, not the author&rsquo;s words.</p>
<div class="mag-hosts">
<div class="mag-voice-pick"><label for="mag-host-a">Host A</label><select id="mag-host-a"></select></div>
<div class="mag-voice-pick"><label for="mag-host-b">Host B</label><select id="mag-host-b"></select></div>
<div class="mag-voice-pick"><label for="mag-host-c">Host C <span class="muted">(optional)</span></label><select id="mag-host-c"></select></div>
</div>
<div class="mag-podcast-actions">
<button type="button" class="btn" id="mag-podcast-gen" onclick="magGeneratePodcast()">Generate script</button>
<button type="button" class="btn primary" id="mag-podcast-play" onclick="magPlayPodcast()" hidden>Play podcast</button>
</div>
<div id="mag-podcast-script"></div>
</details>
</div>
<div id="mag-share-sheet" class="mag-share-sheet" role="dialog" aria-label="Share link" hidden>
<label for="mag-share-link">Copy this link</label>
<input type="text" id="mag-share-link" readonly>
<button type="button" class="btn-sm" onclick="magShareClose()">Close</button>
</div>
<!-- ── Driving mode overlay ─────────────────────────────────────────── -->
<!-- Large controls, minimal text, no interaction required beyond play/
pause/skip -- reuses whatever is already playing rather than its
own playback path. -->
<div id="mag-driving" class="mag-driving" hidden role="dialog" aria-label="Driving mode" data-view="split">
<!-- Layout: top bar / flexible content / controls dock. The dock is never scrolled or overlapped. -->
<div class="mag-driving-top">
<button type="button" class="mag-driving-share" onclick="magShareCurrent()" aria-label="Share a link to this article" title="Share a link to this article">
<span class="mdi mdi-share-variant-outline" aria-hidden="true"></span>
</button>
<div class="mag-driving-menuwrap">
<button type="button" class="mag-driving-menubtn" id="mag-driving-menubtn" aria-expanded="false" aria-controls="mag-driving-menu"
aria-label="Display menu: Split" title="Display menu">
<span class="mdi mdi-view-split-horizontal" aria-hidden="true"></span><span class="mag-driving-view-label" id="mag-driving-menulabel">Split</span>
</button>
<div class="mag-driving-menu" id="mag-driving-menu" role="group" aria-label="Display options" hidden>
<div class="mag-menu-sec" id="mag-menu-sec-view">View</div>
<div role="radiogroup" aria-labelledby="mag-menu-sec-view" class="mag-menu-views">
<button type="button" role="radio" aria-checked="false" tabindex="-1" data-view="picture"><span class="mdi mdi-image-outline" aria-hidden="true"></span><span class="mag-menu-label">Picture<small>whole picture, no text</small></span><span class="mag-radio" aria-hidden="true"></span></button>
<button type="button" role="radio" aria-checked="false" tabindex="-1" data-view="text"><span class="mdi mdi-text-long" aria-hidden="true"></span><span class="mag-menu-label">Text<small>whole text, no picture</small></span><span class="mag-radio" aria-hidden="true"></span></button>
<button type="button" role="radio" aria-checked="true" tabindex="-1" data-view="split"><span class="mdi mdi-view-split-horizontal" aria-hidden="true"></span><span class="mag-menu-label">Split<small>picture and text, amount below</small></span><span class="mag-radio" aria-hidden="true"></span></button>
</div>
<hr role="separator">
<div class="mag-menu-sec" id="mag-menu-sec-amount">Text in Split view</div>
<div role="radiogroup" aria-labelledby="mag-menu-sec-amount" class="mag-seg mag-seg-amount">
<button type="button" role="radio" aria-checked="true" tabindex="-1" data-amount="sentence" title="Only the sentence being read, large"><span>Sentence</span><span class="mdi mdi-check mag-seg-check" aria-hidden="true"></span></button>
<button type="button" role="radio" aria-checked="false" tabindex="-1" data-amount="context" title="The sentence with the previous and next one dimmed"><span>Context</span><span class="mdi mdi-check mag-seg-check" aria-hidden="true"></span></button>
<button type="button" role="radio" aria-checked="false" tabindex="-1" data-amount="paragraph" title="The whole paragraph with the current sentence marked"><span>Paragraph</span><span class="mdi mdi-check mag-seg-check" aria-hidden="true"></span></button>
</div>
<hr role="separator">
<div class="mag-menu-sec" id="mag-menu-sec-show">Show</div>
<div role="group" aria-labelledby="mag-menu-sec-show">
<button type="button" role="switch" aria-checked="true" tabindex="-1" class="mag-menu-switch" id="mag-driving-text-toggle" onclick="magDrivingToggleText()"
title="Show or hide the text being read"><span class="mag-menu-label">Show text</span><span class="mag-sw" aria-hidden="true"><span class="mag-sw-thumb"><span class="mdi mdi-check mag-sw-on"></span><span class="mdi mdi-close mag-sw-off"></span></span></span></button>
<button type="button" role="switch" aria-checked="true" tabindex="-1" class="mag-menu-switch" id="mag-driving-image-toggle" onclick="magDrivingToggleImages()"
title="Show or hide the article's pictures"><span class="mag-menu-label">Show pictures</span><span class="mag-sw" aria-hidden="true"><span class="mag-sw-thumb"><span class="mdi mdi-check mag-sw-on"></span><span class="mdi mdi-close mag-sw-off"></span></span></span></button>
<button type="button" role="switch" aria-checked="false" tabindex="-1" class="mag-menu-switch" id="mag-driving-collapse" aria-controls="mag-driving-content"
onclick="magDrivingToggleCollapsed()"><span class="mag-menu-label">Minimize text and picture</span><span class="mag-sw" aria-hidden="true"><span class="mag-sw-thumb"><span class="mdi mdi-check mag-sw-on"></span><span class="mdi mdi-close mag-sw-off"></span></span></span></button>
</div>
<hr role="separator">
<div class="mag-menu-sec" id="mag-menu-sec-play">Playback</div>
<div role="group" aria-labelledby="mag-menu-sec-play">
<button type="button" role="switch" aria-checked="true" tabindex="-1" class="mag-menu-switch" id="mag-driving-autonext" onclick="magDrivingToggleAutonext()"
title="When an article ends, continue with the next one that has audio"><span class="mag-menu-label">Play next article automatically</span><span class="mag-sw" aria-hidden="true"><span class="mag-sw-thumb"><span class="mdi mdi-check mag-sw-on"></span><span class="mdi mdi-close mag-sw-off"></span></span></span></button>
</div>
<hr role="separator">
<div class="mag-menu-sec" id="mag-menu-sec-theme">Theme</div>
<div role="radiogroup" aria-labelledby="mag-menu-sec-theme" class="mag-seg">
<button type="button" role="radio" aria-checked="false" tabindex="-1" data-theme-choice="light"><span class="mdi mdi-white-balance-sunny" aria-hidden="true"></span><span>Light</span><span class="mdi mdi-check mag-seg-check" aria-hidden="true"></span></button>
<button type="button" role="radio" aria-checked="true" tabindex="-1" data-theme-choice="auto" title="Follow the system setting"><span class="mdi mdi-theme-light-dark" aria-hidden="true"></span><span>Auto</span><span class="mdi mdi-check mag-seg-check" aria-hidden="true"></span></button>
<button type="button" role="radio" aria-checked="false" tabindex="-1" data-theme-choice="dark"><span class="mdi mdi-weather-night" aria-hidden="true"></span><span>Dark</span><span class="mdi mdi-check mag-seg-check" aria-hidden="true"></span></button>
</div>
</div>
</div>
<button type="button" class="mag-driving-indexbtn" id="mag-driving-indexbtn" aria-haspopup="dialog" aria-expanded="false" aria-controls="mag-driving-index"
aria-label="Article index" title="Article index" onclick="magDrivingIndexToggle()">
<span class="mdi mdi-format-list-numbered" aria-hidden="true"></span><span class="mag-driving-view-label">Index</span>
</button>
<span class="mag-driving-topspacer"></span>
<button type="button" class="mag-driving-exit" onclick="magToggleDriving()" aria-label="Exit driving mode">
<span class="mdi mdi-close" aria-hidden="true"></span>
</button>
</div>
<div class="mag-driving-content" id="mag-driving-content">
<button type="button" class="mag-driving-start" id="mag-driving-start" onclick="magDrivingStart()" hidden>
<span class="mdi mdi-play-circle-outline" aria-hidden="true"></span> Tap to play
</button>
<div class="mag-driving-head">
<h2 id="mag-driving-title">Article</h2>
<p id="mag-driving-by" class="muted"></p>
<p id="mag-driving-endstate" class="mag-driving-endstate" hidden><span class="mdi mdi-flag-checkered" aria-hidden="true"></span> End of magazine</p>
<div id="mag-driving-announce" class="sr-only" role="status" aria-live="polite" aria-atomic="true"></div>
<div id="mag-driving-queue" class="mag-driving-queue" hidden>
<span id="mag-queue-progress-2" class="muted"></span>
</div>
</div>
<div class="mag-driving-stagewrap">
<figure id="mag-driving-visual" class="mag-driving-visual" hidden>
<div class="mag-driving-stage" id="mag-driving-stage" tabindex="0" role="group"
aria-label="Picture. Zoom with the buttons, the plus and minus keys, the mouse wheel or by pinching. Double-tap to zoom. Escape resets.">
<div class="mag-driving-pz" id="mag-driving-pz"></div>
</div>
<div class="mag-driving-zoomctl" role="group" aria-label="Zoom">
<button type="button" id="mag-driving-zoom-out" aria-label="Zoom out" title="Zoom out" onclick="magDrivingZoomBy(1/1.5)"><span class="mdi mdi-magnify-minus-outline" aria-hidden="true"></span></button>
<button type="button" id="mag-driving-zoom-in" aria-label="Zoom in" title="Zoom in" onclick="magDrivingZoomBy(1.5)"><span class="mdi mdi-magnify-plus-outline" aria-hidden="true"></span></button>
<button type="button" id="mag-driving-zoom-reset" aria-label="Reset zoom" title="Reset zoom" onclick="magDrivingZoomReset()"><span class="mdi mdi-fit-to-screen-outline" aria-hidden="true"></span></button>
</div>
<figcaption id="mag-driving-cap"></figcaption>
</figure>
<p id="mag-driving-noimg" class="mag-driving-noimg muted" hidden>No picture for this part of the article.</p>
</div>
<div id="mag-driving-lyrics" class="mag-driving-lyrics" role="group" aria-live="off" aria-label="Article text" hidden></div>
<div class="mag-driving-full-wrap">
<div id="mag-driving-full" class="mag-driving-full" role="group" aria-live="off" tabindex="0"
aria-label="Whole article text. Arrow keys move between sentences, Enter plays from the sentence."></div>
<button type="button" class="mag-driving-backcur" id="mag-driving-backcur" hidden onclick="magDrivingBackToCurrent()">
<span class="mdi mdi-crosshairs-gps" aria-hidden="true"></span> Back to current
</button>
</div>
</div>
<div class="mag-driving-index" id="mag-driving-index" role="dialog" aria-label="Article index" hidden>
<div class="mag-driving-index-head">
<h3 id="mag-driving-index-title">Articles</h3>
<button type="button" id="mag-driving-index-close" aria-label="Close the article index" title="Close" onclick="magDrivingIndexClose()"><span class="mdi mdi-close" aria-hidden="true"></span></button>
</div>
<ul class="mag-driving-index-list" id="mag-driving-index-list" aria-labelledby="mag-driving-index-title"></ul>
</div>
<div class="mag-driving-dock">
<div class="mag-driving-seek">
<input type="range" id="mag-driving-seek" min="0" max="1000" value="0" step="1"
aria-label="Position in article" oninput="magDrivingSeek(this.value)">
<div class="mag-driving-time" id="mag-driving-time" aria-live="off">0:00 / 0:00</div>
<button type="button" class="mag-driving-opt" id="mag-driving-speed" onclick="magDrivingCycleSpeed()"
aria-label="Playback speed 1×. Press to change" title="Playback speed">1×</button>
</div>
<div class="mag-driving-controls">
<button type="button" class="mag-driving-btn is-small" onclick="magDrivingPrevious()" aria-label="Previous article" title="Previous article">
<span class="mdi mdi-skip-previous"></span>
</button>
<button type="button" class="mag-driving-btn" onclick="magDrivingSkip(-15)" aria-label="Back 15 seconds" title="Back 15 seconds">
<span class="mdi mdi-rewind-15"></span>
</button>
<button type="button" class="mag-driving-btn mag-driving-play" id="mag-driving-play" onclick="magDrivingTogglePlayback()" aria-label="Play">
<span class="mdi mdi-play"></span>
</button>
<button type="button" class="mag-driving-btn" onclick="magDrivingSkip(15)" aria-label="Forward 15 seconds" title="Forward 15 seconds">
<span class="mdi mdi-fast-forward-15"></span>
</button>
<button type="button" class="mag-driving-btn is-small" onclick="magDrivingNext()" aria-label="Next article" title="Next article">
<span class="mdi mdi-skip-next"></span>
</button>
</div>
</div>
</div>