/* app.css — WBT Reader (3-pane workspace).
 *
 * Mobile-first, no build step. Dark is the default; a light theme mirrors every
 * token. The palette follows the reader prototype: warm parchment text, gold
 * accent, serif reading type. Layout is a flex workspace (sidebar · center)
 * that collapses to off-canvas drawers on narrow screens. */

:root {
    /* Dark (default) — warm parchment on near-black. */
    --bg: #0f1115;
    --panel: #171a21;
    --panel2: #1e222b;
    --line: #2a2f3a;
    --fg: #e7e3d8;
    --muted: #9aa0ac;
    --accent: #c9a24b;      /* gold */
    --accent-soft: #26210f;
    --accent2: #6db1ff;     /* blue — links */
    --accent2-soft: #12202f;
    --accent2-line: #23405c;
    --good: #6bd08a;
    --error: #e06b6b;
    --warn: #e0a458;

    --serif: "Iowan Old Style", "Palatino Linotype", Georgia, "Times New Roman", serif;
    --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    /* Reader typography — overridden per device by app.js. */
    --reader-font-size: 1.2rem;
    --reader-line-height: 1.72;

    --sidebar-w: 17rem;
}

@media (prefers-color-scheme: light) {
    :root {
        --bg: #f7f4ec;
        --panel: #fffdf7;
        --panel2: #f0ebdd;
        --line: #d9d2c0;
        --fg: #241f17;
        --muted: #7a7360;
        --accent: #9a7418;
        --accent-soft: #f3e8c9;
        --accent2: #2f6bb0;
        --accent2-soft: #e5eef8;
        --accent2-line: #bcd2ea;
        --good: #2e8b57;
        --error: #b23b3b;
        --warn: #b8791f;
    }
}

:root[data-theme="dark"] {
    --bg: #0f1115; --panel: #171a21; --panel2: #1e222b; --line: #2a2f3a;
    --fg: #e7e3d8; --muted: #9aa0ac; --accent: #c9a24b; --accent-soft: #26210f;
    --accent2: #6db1ff; --accent2-soft: #12202f; --accent2-line: #23405c;
    --good: #6bd08a; --error: #e06b6b; --warn: #e0a458;
}

:root[data-theme="light"] {
    --bg: #f7f4ec; --panel: #fffdf7; --panel2: #f0ebdd; --line: #d9d2c0;
    --fg: #241f17; --muted: #7a7360; --accent: #9a7418; --accent-soft: #f3e8c9;
    --accent2: #2f6bb0; --accent2-soft: #e5eef8; --accent2-line: #bcd2ea;
    --good: #2e8b57; --error: #b23b3b; --warn: #b8791f;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }
/* Doppeltipp-Zoom (iOS) unterbinden — kein versehentliches Reinzoomen beim
   schnellen Tippen auf die Kapitel-/Absatz-Tasten. */
html { background: var(--bg); touch-action: manipulation; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
    background: var(--bg);
    color: var(--fg);
    font-family: var(--sans);
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
}

button { font-family: inherit; cursor: pointer; }
a { color: var(--accent2); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 8px; }

.visually-hidden {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0, 0, 0, 0); border: 0;
}

/* --- Login ---------------------------------------------------------------- */

.login-card {
    width: 100%; max-width: 22rem;
    background: var(--panel); border: 1px solid var(--line);
    border-radius: 0.75rem; padding: 2rem 1.5rem; text-align: center;
}
.login-card h1 { margin: 0 0 0.25rem; font-family: var(--serif); color: var(--accent); font-size: 1.6rem; }
.login-hint { margin: 0 0 1.25rem; color: var(--muted); font-size: 0.95rem; }
.login-error { margin: 0 0 1rem; color: var(--error); font-size: 0.9rem; }
.login-form { display: flex; flex-direction: column; gap: 0.75rem; }
.login-form input {
    padding: 0.75rem; font-size: 1rem; border: 1px solid var(--line);
    border-radius: 0.5rem; background: var(--panel2); color: var(--fg);
}
.login-form button {
    padding: 0.75rem; font-size: 1rem; font-weight: 700; color: #20180a;
    background: var(--accent); border: none; border-radius: 0.5rem; cursor: pointer;
}
.login-form button:active { opacity: 0.85; }

/* Mehrbenutzer (Paket 012+): additiv zu .login-*, alles über die bestehenden
   Custom Properties — damit kommt Hell/Dunkel geschenkt. */
.auth-page { display: flex; min-height: 100vh; min-height: 100dvh; align-items: center; justify-content: center; padding: 1rem; }
.login-notice { margin: 0 0 1rem; color: var(--accent); font-size: 0.9rem; }
.auth-links { margin: 1.25rem 0 0; font-size: 0.85rem; color: var(--muted); }
.auth-links a { color: var(--muted); }
.auth-links a:hover { color: var(--accent); }
/* Der Abmelde-Knopf ist jetzt ein POST-Formular — es darf im Kopf keinen
   eigenen Platz beanspruchen. */
.logout-form { display: contents; }

/* --- Benutzerverwaltung (Paket 013) --------------------------------------
   Karten statt Tabelle: sechs Spalten sind auf dem iPhone unbrauchbar. Die
   Status-Chips folgen dem Vorbild aus dem Bibliotheks-Block (.lib-chip). */
/* Die Seite rendert unter die Statusleiste (viewport-fit=cover, in der iOS-Hülle
   zusätzlich ohne Browser-Chrome) — ohne Safe-Area-Polster liegt die Kopfzeile
   mit „← zum Reader" hinter Uhrzeit und Batterie und ist nicht antippbar. */
.admin-page {
    padding: calc(1rem + env(safe-area-inset-top)) calc(1rem + env(safe-area-inset-right))
             calc(1rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
}
.admin-wrap { max-width: 44rem; margin: 0 auto; }
.admin-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.admin-head h1 { font-family: var(--serif); color: var(--accent); font-size: 1.4rem; margin: 0 0 0.5rem; }
.admin-back { color: var(--muted); font-size: 0.85rem; }
.admin-count { color: var(--muted); font-size: 0.85rem; margin: 0 0 1rem; }
.admin-card {
    background: var(--panel); border: 1px solid var(--line);
    border-radius: 0.75rem; padding: 0.9rem 1rem; margin-bottom: 0.75rem;
}
.admin-card.is-me { border-color: var(--accent); }
.admin-card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
.admin-name { font-family: var(--serif); font-size: 1.02rem; font-weight: 600; }
.admin-you { color: var(--muted); font-weight: 400; font-size: 0.8rem; }
.lib-chip.is-active { color: var(--accent); border-color: var(--accent); background: transparent; }
.lib-chip.is-pending { color: var(--fg); }
.lib-chip.is-disabled { color: var(--error); border-color: var(--error); background: transparent; }
.admin-meta { color: var(--muted); font-size: 0.82rem; margin-top: 0.35rem; line-height: 1.5; }
.admin-meta a { color: var(--accent); }
.admin-books { color: var(--muted); font-size: 0.8rem; margin: 0.5rem 0 0; padding-left: 1.1rem; }
.admin-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.75rem; }
.admin-btn {
    padding: 0.4rem 0.7rem; font-size: 0.82rem; cursor: pointer;
    background: var(--panel2); color: var(--fg);
    border: 1px solid var(--line); border-radius: 0.5rem;
}
.admin-btn.is-primary { background: var(--accent); border-color: var(--accent); color: #20180a; font-weight: 700; }
.admin-btn.is-danger { color: var(--error); border-color: var(--error); }
.admin-btn:active { opacity: 0.85; }
a.admin-btn { display: inline-block; text-decoration: none; }
/* Die eigene Karte hat keine Knöpfe, sondern diesen Satz — leicht abgesetzt,
   damit er als Regel gelesen wird und nicht als weitere Meta-Zeile. */
.admin-selfnote {
    color: var(--muted); font-size: 0.82rem; line-height: 1.5;
    margin-top: 0.75rem; padding-left: 0.7rem;
    border-left: 2px solid var(--accent);
}
.admin-selfnote a { color: var(--accent); }

/* Offene Einladung: Angabe, Link zum Kopieren, Zurückziehen. Abgesetzt wie die
   Selbst-Notiz, damit mehrere Einladungen als Liste lesbar bleiben. */
.admin-invite {
    margin-top: 0.75rem; padding-left: 0.7rem;
    border-left: 2px solid var(--line);
    display: flex; flex-direction: column; gap: 0.4rem;
}
.admin-invite .admin-meta { margin-top: 0; }
.admin-invite-link {
    width: 100%; padding: 0.5rem; font-size: 0.78rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    border: 1px solid var(--line); border-radius: 0.5rem;
    background: var(--panel2); color: var(--muted);
    /* Der Link ist lang; im Umbruch wäre er unlesbar, also eine Zeile mit
       eigenem Scroll — antippen wählt ihn ohnehin komplett aus. */
    text-overflow: ellipsis;
}
.admin-invite .admin-btn { align-self: flex-start; }

/* Kontoseite (Paket 014): jeder Abschnitt ist ein eigenes kleines Formular. */
.account-form { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.7rem; }
.account-form input {
    padding: 0.6rem; font-size: 0.95rem; border: 1px solid var(--line);
    border-radius: 0.5rem; background: var(--panel2); color: var(--fg);
}
.account-form .admin-btn { align-self: flex-start; }

/* --- Reader shell / workspace -------------------------------------------- */

/* Als Home-Bildschirm-App auf iOS stimmte `100dvh` nach Rotation/Tastatur oft
   nicht mehr mit dem sichtbaren Fenster überein — unter der Build-Marke blieb
   ein leerer Streifen. `position: fixed; inset: 0` hängt sich am Fenster selbst
   fest statt an einer Maßeinheit, die nachrechnen müsste. */
body.reader-page {
    display: flex;
    flex-direction: column;
    position: fixed; inset: 0;
    height: auto; width: auto;
    overflow: hidden;
}
/* … und selbst `inset: 0` reichte nicht: als Home-Bildschirm-App hält iOS das
   Layout-Fenster nach Tastatur, Rotation oder Now-Playing-Wechsel gern ein
   Stück zu klein — unter der Build-Marke blieb wieder ein leerer Streifen.
   Darum misst assets/app.js (`fitViewport`) die sichtbare Höhe über
   `visualViewport` und schreibt sie in `--app-h`; hier zählt dann die Messung,
   nicht das, was das System behauptet. Ohne Messung gilt weiter `inset: 0`. */
body.reader-page.has-app-h { bottom: auto; height: var(--app-h); }

.app-header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: calc(0.5rem + env(safe-area-inset-top)) calc(0.75rem + env(safe-area-inset-right)) 0.5rem calc(0.75rem + env(safe-area-inset-left));
    border-bottom: 1px solid var(--line);
    background: var(--panel);
    z-index: 30;
}

.app-title {
    font-weight: 700;
    color: var(--accent);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 40vw;
}

.icon-btn {
    flex: 0 0 auto;
    min-width: 40px; min-height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.55rem; font-size: 1.05rem; line-height: 1; padding: 0;
}
.icon-btn:hover { border-color: var(--accent); }
.icon-btn.is-active { border-color: var(--accent); color: var(--accent); }

.header-progress {
    flex: 1 1 auto;
    display: flex; align-items: center; gap: 0.5rem;
    min-width: 0; max-width: 22rem;
}
.prog-text { color: var(--muted); font-size: 0.78rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.prog-bar { flex: 1 1 auto; height: 6px; min-width: 3rem; background: var(--panel2); border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.prog-bar > i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--accent), #e6c877); transition: width 0.2s; }

.header-controls { flex: 0 0 auto; display: flex; align-items: center; gap: 0.5rem; }
/* Logout is an icon-only button (⏻); "Abmelden" lives in title/aria-label. */
.logout-link { color: var(--accent2); text-decoration: none; font-size: 1.05rem; }

#workspace {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    position: relative;
}

.pane { overflow: auto; -webkit-overflow-scrolling: touch; min-height: 0; }

#sidebar {
    flex: 0 0 var(--sidebar-w);
    width: var(--sidebar-w);
    background: var(--panel);
    border-right: 1px solid var(--line);
    display: flex; flex-direction: column;
}
/* Mittelspalte: Lesetext + Player-Streifen als eigene Säule neben der
   Sidebar — so endet sie nicht über dem Streifen. */
#centerCol {
    flex: 1 1 auto;
    min-width: 0; min-height: 0;
    display: flex; flex-direction: column;
}
#center {
    flex: 1 1 auto;
    min-width: 0; min-height: 0;
    background: var(--bg);
    padding: 1.5rem calc(1.25rem + env(safe-area-inset-right)) 1.25rem calc(1.25rem + env(safe-area-inset-left));
}
/* Desktop collapse: the toggled pane is removed from the flex flow. */
#workspace.sidebar-collapsed > #sidebar { display: none; }

/* Die Build-Marke ist Beiwerk und darf keinen Platz kosten: sie ist genau so
   hoch wie ihre eine Textzeile. Die Home-Indicator-Zone (safe-area-inset-bottom,
   auf dem iPhone ~34 px) polstert sie bewusst NICHT mehr aus — das machte aus
   einer 0,7-rem-Zeile einen fingerhohen Streifen, und der fehlte dem Lesetext.
   Der Text ist nicht antippbar, er darf also unter dem Indicator liegen; der
   Player-Streifen darüber bleibt oberhalb der Zone bedienbar. */
.app-build {
    flex: 0 0 auto;
    padding: 0.1rem calc(1rem + env(safe-area-inset-right)) 0.1rem calc(1rem + env(safe-area-inset-left));
    line-height: 1.2;
    text-align: center; font-size: 0.68rem; letter-spacing: 0.03em;
    opacity: 0.4; user-select: none; -webkit-user-select: none; border-top: 1px solid var(--line); background: var(--panel);
}

/* --- Font-size control ---------------------------------------------------- */

.font-control { display: flex; align-items: center; gap: 0.2rem; flex-shrink: 0; }
.font-btn {
    min-width: 34px; min-height: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--line); background: var(--panel2); color: var(--fg);
    border-radius: 0.45rem; line-height: 1; padding: 0;
    font-size: 0.85rem; font-weight: 700;
}
.font-btn:disabled { opacity: 0.35; }

/* --- Sidebar: mode switch + chapter list + character index --------------- */

.side-modes { display: flex; flex-wrap: wrap; gap: 0.3rem; padding: 0.6rem 0.6rem 0.4rem; }
.side-mode {
    flex: 1 1 40%; min-height: 38px; padding: 0.4rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--muted);
    border-radius: 0.5rem; font-size: 0.8rem; font-weight: 600;
}
.side-mode.is-active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }

.side-search {
    margin: 0.2rem 0.6rem 0.5rem;
    padding: 0.55rem 0.7rem; background: var(--panel2); border: 1px solid var(--line);
    border-radius: 0.5rem; color: var(--fg); font-size: 0.9rem;
}
.side-search:focus { outline: none; border-color: var(--accent); }

.side-list { list-style: none; margin: 0; padding: 0 0.4rem 1rem; overflow: auto; flex: 1 1 auto; }
.side-list[hidden] { display: none; }

.ch-item {
    display: flex; gap: 0.5rem; align-items: baseline;
    width: 100%; text-align: left; min-height: 40px;
    padding: 0.5rem 0.6rem; margin: 0.1rem 0;
    background: none; border: 1px solid transparent; border-radius: 0.5rem;
    color: var(--muted); font-size: 0.88rem;
}
.ch-item:hover { background: var(--panel2); color: var(--fg); }
.ch-item.is-active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.ch-item .ch-n { flex: 0 0 auto; min-width: 2.6rem; color: var(--accent); font-variant-numeric: tabular-nums; }
.ch-item.is-read .ch-n::after { content: " ✓"; color: var(--good); }
.ch-item .ch-t { overflow-wrap: anywhere; }
.ch-item[hidden] { display: none; }

.char-item {
    display: flex; align-items: center; gap: 0.5rem; width: 100%; text-align: left;
    padding: 0.55rem 0.6rem; margin: 0.1rem 0;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 0.5rem;
    color: var(--fg); font-size: 0.9rem;
}
.char-item:hover { border-color: var(--accent2); }
.char-item .char-role { color: var(--muted); font-size: 0.78rem; margin-left: auto; }
.char-item[hidden] { display: none; }

/* --- Avatare: prozedurale SVG-Medaillons + Drop-in-Porträts --------------- */

.avatar {
    display: inline-flex; flex: 0 0 auto; border-radius: 50%; overflow: hidden;
    background: var(--panel2);
}
.avatar svg, .avatar img { width: 100%; height: 100%; display: block; object-fit: cover; }

.side-empty, .pane-empty {
    color: var(--muted); font-size: 0.85rem; text-align: center;
    padding: 2rem 1rem; line-height: 1.6;
}

/* --- Center: reader ------------------------------------------------------- */

.center-message { color: var(--muted); text-align: center; padding: 3rem 1rem; }

/* Offline: das angefragte Kapitel liegt nicht auf dem Gerät.
   Statt des rohen Fetch-Fehlers eine Auskunft plus der tatsächliche Vorrat. */
.offline-miss { max-width: 46rem; margin: 0 auto; padding: 2.5rem 1rem 3rem; }
.offline-miss-title { font-family: var(--serif); font-size: 1.4rem; color: var(--accent); margin: 0 0 0.6rem; }
.offline-miss-text { color: var(--muted); margin: 0 0 1.6rem; line-height: 1.5; }
.offline-miss-lead { color: var(--muted); font-size: 0.9rem; margin: 0 0 0.5rem; }
.offline-miss-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.offline-miss-item {
    width: 100%; text-align: left; background: none; border: 1px solid transparent;
    border-radius: 0.4rem; color: var(--fg); font: inherit; padding: 0.55rem 0.7rem; cursor: pointer;
}
.offline-miss-item:hover, .offline-miss-item:focus-visible { border-color: var(--accent); background: var(--accent-soft); }

/* Offline-Bestand in der Kapitelliste: Punkt = liegt auf dem Gerät,
   gedämpft = ohne Empfang nicht ladbar. Online wird nichts davon gesetzt. */
.ch-item.is-stored .ch-n::after { content: "\2009\25CF"; color: var(--accent); font-size: 0.62em; vertical-align: 0.18em; }
.ch-item.is-absent { opacity: 0.42; }

.reader { max-width: 46rem; margin: 0 auto; }
.reader-title { font-family: var(--serif); font-size: 1.7rem; line-height: 1.25; color: var(--accent); margin: 0 0 0.2rem; overflow-wrap: anywhere; }
.reader-sub { color: var(--muted); font-size: 0.9rem; margin: 0 0 1.5rem; }
.reader-body { font-family: var(--serif); font-size: var(--reader-font-size); line-height: var(--reader-line-height); }
.reader-body p { margin: 0 0 1.05em; overflow-wrap: anywhere; }
.reader-sep {
    text-align: center; color: var(--accent); letter-spacing: 0.4em; margin: 1.4em 0; font-size: 1.1rem;
    border-radius: 0.3rem;
    transition: background-color 0.35s ease, color 0.35s ease, transform 0.35s ease;
}
/* Der Szenenwechsel klingt gerade: die Rauten sind der „aktive Absatz". Gleiche
   Sprache wie p.tts-active, nur eine Spur deutlicher — hier passiert die Pause. */
.reader-sep.sep-active {
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    box-shadow: 0 0 0 8px color-mix(in srgb, var(--accent) 18%, transparent);
    transform: scale(1.12);
}

/* --- Reader modes: read-aloud + speed reading (shared bottom dock) -------- */

.reader-body p.tts-active {
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    border-radius: 0.3rem;
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 12%, transparent);
}

/* One jump marker per paragraph: "start here". What that means follows the
   running mode (read-aloud jumps in the audio, the speed reader picks up
   there) — but the marker no longer says so with a mode glyph. It shows the
   paragraph NUMBER instead: one shape everywhere, plus a piece of information
   worth having ("I stopped at 12"). The number comes from ::before via
   attr(data-n), so the button stays text-free and p.textContent remains the
   pure prose for read-aloud / speed reading / search.

   Der Knopf selbst ist der **Float-Kasten** und exakt eine Textzeile hoch; der
   sichtbare Kreis steckt im ::before und wird darin mittig gesetzt. Ein Float
   richtet seine Oberkante am Zeilenkasten aus — ein fester 30-px-Kasten klebte
   damit oben und wirkte hochgestellt, umso mehr je größer die Leseschrift. Über
   die Zeilenhöhe stimmt die Mitte bei jeder Größe. */
.para-jump {
    float: left;
    width: 30px; padding: 0; margin: 0 0.4rem 0 0;
    height: max(30px, calc(var(--reader-font-size) * var(--reader-line-height)));
    display: flex; align-items: center; justify-content: center;
    background: none; border: 0;
    color: var(--accent); opacity: 0.5;
    cursor: pointer;
}
.para-jump::before {
    content: attr(data-n);
    display: flex; align-items: center; justify-content: center;
    width: 30px; height: 30px;
    border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
    border-radius: 50%;
    font-family: var(--sans); font-size: 0.72rem; font-weight: 600;
    font-variant-numeric: tabular-nums; line-height: 1;
}
.para-jump:hover, .para-jump:focus-visible { opacity: 1; }
.para-jump:hover::before, .para-jump:focus-visible::before {
    background: var(--accent-soft); border-color: var(--accent);
}
/* Wo gerade gelesen wird, steht die Zahl gefüllt — die Marke ist damit auch
   die Positionsanzeige im Text. */
.reader-body p.tts-active .para-jump { opacity: 1; }
.reader-body p.tts-active .para-jump::before {
    background: var(--accent-soft); border-color: var(--accent);
}

/* Idle chooser in the dock: pick read-aloud or speed reading (the two buttons
   that used to sit under the title now live where the player strip is). */
.mode-chooser {
    display: flex; gap: 0.6rem; justify-content: center;
    max-width: 46rem; margin: 0 auto;
}
.mode-btn {
    min-height: 40px; padding: 0.4rem 1rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--muted);
    border-radius: 0.6rem; font-size: 0.9rem;
}
.mode-btn:hover { border-color: var(--accent); color: var(--fg); }

/* Speed-reader strip: the running word big, a thin progress bar, transport and
   options — same borderless podcast look as the read-aloud player. */
.sr-bar { display: flex; flex-direction: column; gap: 0.35rem; max-width: 46rem; margin: 0 auto; }
.sr-word {
    text-align: center; font-family: var(--serif);
    font-size: clamp(1.4rem, 5.5vw, 2.1rem); font-weight: 700; color: var(--accent);
    line-height: 1.15; min-height: 1.3em;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sr-progress { width: 100%; height: 4px; background: var(--panel2); border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.sr-progress > i { display: block; height: 100%; width: 0; background: var(--accent); }
.sr-opt-row { justify-content: center; }
.sr-wpm { font-variant-numeric: tabular-nums; }

/* Speed-reader fullscreen (opt-in): the running word fills the screen while it
   plays; a tap pauses (which drops back to the strip + text). */
.sr-overlay {
    position: fixed; inset: 0; z-index: 120; background: var(--bg); cursor: pointer;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.6rem;
    padding: 1rem calc(1rem + env(safe-area-inset-right)) calc(1rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
}
.sr-word-big {
    font-family: var(--serif); font-weight: 700; color: var(--accent);
    font-size: clamp(2.2rem, 9vw, 4rem); text-align: center; white-space: nowrap;
}
.sr-progress-big { max-width: 30rem; }
.sr-fs-hint { color: var(--muted); font-size: 0.85rem; }
.sr-fs-close {
    position: absolute;
    top: calc(0.8rem + env(safe-area-inset-top)); right: calc(0.8rem + env(safe-area-inset-right));
    width: 44px; height: 44px; padding: 0;
    background: none; border: none; color: var(--muted); font-size: 1.3rem; cursor: pointer;
}
.sr-fs-close:hover { color: var(--fg); }

/* Speed-reader settings: WpM slider row. */
.sr-wpm-slider { flex: 1 1 auto; min-width: 0; accent-color: var(--accent); }
.sr-wpm-val { flex: 0 0 auto; color: var(--muted); font-size: 0.85rem; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Read-aloud player: a fixed strip in the layout flow — below the reading text,
   above the build marker. Deliberately NOT an overlay: it used to float over the
   prose and swallow both the last lines and the version footer. */
.tts-dock {
    flex: 0 0 auto;
    position: relative;
    background: var(--panel); border-top: 1px solid var(--line);
    padding: 0.3rem calc(0.7rem + env(safe-area-inset-right)) 0.25rem calc(0.7rem + env(safe-area-inset-left));
}
.tts-dock[hidden] { display: none; }
.tts-bar {
    display: flex; flex-direction: column; gap: 0.4rem;
    max-width: 46rem; margin: 0 auto;
}
/* Row 1: elapsed · scrubber · total. Dragging the scrubber moves the text with
   it, so reading along stays in sync. */
.tts-seek-row { display: flex; align-items: center; gap: 0.5rem; }
.tts-time {
    flex: 0 0 auto; min-width: 3.1rem;
    color: var(--muted); font-size: 0.72rem; font-variant-numeric: tabular-nums;
}
.tts-time.is-total { text-align: right; }
.tts-seek {
    flex: 1 1 auto; min-width: 0; width: 100%; margin: 0;
    accent-color: var(--accent); height: 1.5rem;
}
/* Row 2: transport, centred like a podcast player. Borderless icon controls in
   the theme colour — the one filled element is the round play button. Chapter
   skip on the outside, paragraph skip flanking play. */
.tts-main-row { display: flex; align-items: center; justify-content: center; }
/* The transport fills the whole strip width: on a phone the five buttons sat
   shoulder to shoulder in the middle, so a thumb hit the neighbour. Each button
   is a flex cell — the tap area tiles the full row without gaps, and the icon
   stays centred in it. */
.tts-transport {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0; width: 100%; max-width: 30rem;
}
.tts-tbtn {
    flex: 1 1 0; min-width: 54px; height: 56px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; color: var(--muted);
    -webkit-tap-highlight-color: transparent;
    transition: color 0.12s, transform 0.08s;
}
.tts-tbtn svg { width: 28px; height: 28px; display: block; }
.tts-tbtn:hover:not(:disabled) { color: var(--fg); }
.tts-tbtn:active:not(:disabled) { transform: scale(0.9); color: var(--accent); }
.tts-tbtn:disabled { opacity: 0.28; cursor: default; }
/* Chapter jumps read a touch smaller than the paragraph steps. */
.tts-prev-ch svg, .tts-next-ch svg { width: 24px; height: 24px; }
/* Play/Pause — the one clear affordance: a filled accent disc. */
.tts-play {
    flex: 0 0 auto; width: 62px; height: 62px; margin: 0 0.2rem; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--accent); border: 0; color: var(--bg);
    border-radius: 999px; -webkit-tap-highlight-color: transparent;
    transition: transform 0.08s, filter 0.12s;
}
.tts-play svg { width: 28px; height: 28px; display: block; }
.tts-play:hover { filter: brightness(1.06); }
.tts-play:active { transform: scale(0.94); }
/* Speed: plain tappable text, no chrome. Muted → accent once off default. */
.tts-speed {
    min-height: 36px; padding: 0.2rem 0.4rem;
    background: none; border: 0; color: var(--muted);
    font-size: 0.92rem; line-height: 1; font-variant-numeric: tabular-nums;
}
.tts-speed:hover { color: var(--fg); }
.tts-speed.is-changed { color: var(--accent); }
/* Row 3: options — the speaker on the left, plain controls on the right. */
.tts-opt-row { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; }
/* Voice-name display (single-voice chapters). Plain muted label. */
.tts-voice {
    max-width: 12rem; min-height: 34px;
    display: inline-flex; align-items: center;
    color: var(--muted); font-size: 0.8rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tts-voice[hidden] { display: none; }
/* Voice picker: borderless text + a small caret — matches the speed text rather
   than an OS-boxed <select>. */
.tts-voice-select {
    -webkit-appearance: none; appearance: none;
    min-height: 34px; max-width: 12rem;
    padding: 0.2rem 1.05rem 0.2rem 0.35rem;
    background: none; border: 0; color: var(--fg);
    font-size: 0.85rem; line-height: 1; cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.5l4 4 4-4' fill='none' stroke='%239aa0ac' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 0.15rem center; background-size: 0.78rem;
}
.tts-voice-select:hover { color: var(--accent); }
.tts-voice-select[hidden] { display: none; }
/* Settings (sliders) + close (✕): borderless icons, muted → fg/accent. */
.tts-iconbtn {
    width: 40px; height: 40px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; color: var(--muted);
    -webkit-tap-highlight-color: transparent; transition: color 0.12s;
}
.tts-iconbtn svg { width: 22px; height: 22px; display: block; }
.tts-iconbtn:hover { color: var(--fg); }
.tts-settings-btn:hover { color: var(--accent); }
/* Total time doubles as a toggle to remaining time — hint it's tappable. */
.tts-time-toggle { cursor: pointer; }
.tts-time-toggle:hover { color: var(--accent); }
/* Sleep-timer countdown — a subtle tappable pill that jumps into its setting. */
.tts-sleep-ind {
    display: inline-flex; align-items: center; min-height: 34px;
    padding: 0.2rem 0.55rem; border-radius: 999px;
    color: var(--accent); border: 1px solid var(--accent); background: var(--accent-soft);
    font-size: 0.76rem; font-variant-numeric: tabular-nums; white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
}
.tts-sleep-ind:hover { filter: brightness(1.08); }
.tts-sleep-ind[hidden] { display: none; }
/* Die beiden Media-Blöcke stehen bewusst HINTER allen .tts-Grundregeln: gleiche
 * Spezifität, also gewinnt die spätere Regel (D-010). */
/* Handy: der Streifen kostet Lesehöhe — die drei Zeilen rücken enger zusammen,
   die Daumen-Ziele bleiben (Play 56 px, Transport 48 px). */
@media (max-width: 900px) {
    .tts-bar { gap: 0.15rem; }
    .tts-tbtn { height: 48px; }
    .tts-play { width: 56px; height: 56px; }
    .tts-seek { height: 1.2rem; }
}
/* Desktop: kompaktere Maße — die Daumen-Größen aus dem Mobil-Layout wirken
   mit Maus überproportional und fressen Lesehöhe. */
@media (min-width: 901px) {
    .tts-dock { padding: 0.3rem 0.7rem; }
    .tts-bar { gap: 0.25rem; }
    .tts-transport { max-width: 24rem; }
    .tts-tbtn { height: 38px; min-width: 44px; }
    .tts-tbtn svg { width: 21px; height: 21px; }
    .tts-prev-ch svg, .tts-next-ch svg { width: 18px; height: 18px; }
    .tts-play { width: 44px; height: 44px; }
    .tts-play svg { width: 20px; height: 20px; }
    .tts-seek { height: 1.1rem; }
    .tts-iconbtn { width: 34px; height: 34px; }
    .tts-iconbtn svg { width: 19px; height: 19px; }
    .tts-voice, .tts-voice-select, .tts-sleep-ind { min-height: 28px; }
    .tts-speed { min-height: 28px; }
}

/* Full-screen read-aloud settings: transition sound, multi-chapter auto-read
   and the sleep timer. Covers the whole viewport, dismiss by ✕ or backdrop. */
.tts-settings {
    position: fixed; inset: 0; z-index: 200;
    display: flex; align-items: flex-end; justify-content: center;
    background: rgba(0, 0, 0, 0.55);
    /* Die Statusleiste (Uhr, Akku) bleibt frei — sonst lag das ✕ darunter und
       war nur im Querformat zu treffen. */
    padding-top: calc(0.75rem + env(safe-area-inset-top));
}
.tts-settings-panel {
    width: min(34rem, 100%); max-height: 100%; overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--panel); border: 1px solid var(--line);
    border-radius: 1rem 1rem 0 0;
    padding: 0.9rem calc(1rem + env(safe-area-inset-right)) calc(1.2rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
}
@media (min-width: 40rem) {
    .tts-settings { align-items: center; }
    .tts-settings-panel { border-radius: 1rem; }
}
.tts-settings-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 0.5rem;
}
.tts-settings-title { margin: 0; font-size: 1.05rem; color: var(--fg); }
.tts-settings-done {
    min-width: 40px; min-height: 40px;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.6rem; font-size: 1rem;
}
.tts-settings-done:hover { border-color: var(--accent); }
.tts-set-section {
    padding: 0.7rem 0.5rem; border-top: 1px solid var(--line);
    border-radius: 0.5rem;
}
/* Opened via the 💤 chip → briefly flash the sleep-timer section. */
.tts-set-section.is-flash { animation: ttsSetFlash 1.4s ease; }
@keyframes ttsSetFlash {
    0%, 100% { background: transparent; }
    30% { background: var(--accent-soft); }
}
.tts-set-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.tts-set-text { min-width: 0; }
.tts-set-label { color: var(--fg); font-size: 0.92rem; }
/* Zwei Einstellungen in einem Abschnitt (Mitlaufen: Vorschau + Rücksprung):
   die zweite Überschrift braucht Luft zur Schalterzeile darüber. */
.tts-set-row + .tts-set-label { margin-top: 0.9rem; }
.tts-set-hint { color: var(--muted); font-size: 0.76rem; margin-top: 0.15rem; }
/* iOS-style on/off switch for "auto-read across chapters". */
.tts-switch {
    flex: 0 0 auto; width: 52px; height: 30px; border-radius: 999px;
    background: var(--panel2); border: 1px solid var(--line); position: relative;
    transition: background 0.15s, border-color 0.15s;
}
.tts-switch::after {
    content: ''; position: absolute; top: 2px; left: 2px;
    width: 24px; height: 24px; border-radius: 50%;
    background: var(--muted); transition: transform 0.15s, background 0.15s;
}
.tts-switch.is-on { background: var(--accent-soft); border-color: var(--accent); }
.tts-switch.is-on::after { transform: translateX(22px); background: var(--accent); }
/* Sleep-timer duration chips. */
.tts-set-choices { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.55rem; }
/* Chips direkt neben ihrer Zeilenbeschriftung (Pfeiltasten-Achsen) brauchen
   den Abstand nach oben nicht — sie stehen nicht unter, sondern neben ihr. */
.tts-set-row .tts-set-choices { margin-top: 0; justify-content: flex-end; }
.tts-chip {
    min-height: 40px; padding: 0.35rem 0.8rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.6rem; font-size: 0.85rem; line-height: 1;
}
.tts-chip:hover { border-color: var(--accent); }
.tts-chip.is-active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
/* Vorlese-Protokoll (Diagnose): Festbreitenschrift, damit Zeit und Tonspur-
   Position untereinander stehen — genau darin liest man die Lücken ab. */
.tts-trace-legend { margin-top: 0.55rem; }
.tts-trace-box {
    margin: 0.4rem 0 0; padding: 0.5rem 0.6rem;
    max-height: 42vh; overflow: auto; -webkit-overflow-scrolling: touch;
    background: var(--panel2); border: 1px solid var(--line);
    border-radius: 0.5rem; color: var(--fg);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.66rem; line-height: 1.5;
    white-space: pre; user-select: text; -webkit-user-select: text;
}
.tts-sleep-info:empty { display: none; }
.tts-sleep-info { margin-top: 0.5rem; color: var(--accent); }
/* Offline-Modus: Fortschrittszeile + „Speicher leeren". Die Zeile hat eine
   feste Mindesthöhe, damit der Dialog beim Umschalten von „bereit" auf
   „lädt … 3 von 10" nicht unter dem Finger springt. */
.tts-offline-info { margin-top: 0.5rem; color: var(--accent); min-height: 1.1em; }
.tts-offline-clear { margin-top: 0.55rem; }
.tts-offline-clear[hidden] { display: none; }
/* Transition-sound list (reused inside the settings dialog). */
.tts-chime-list {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.4rem;
    margin-top: 0.55rem;
}
.tts-chime-item {
    min-height: 42px; padding: 0.35rem 0.6rem; text-align: left;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.5rem; font-size: 0.82rem; line-height: 1.2; opacity: 0.8;
}
.tts-chime-item:hover { opacity: 1; }
.tts-chime-item.is-active {
    opacity: 1; color: var(--accent); border-color: var(--accent); background: var(--accent-soft);
}
/* Lade-/Pufferzustand in der freien Mitte der Optionszeile: nimmt den Platz
   zwischen Sprecher und den rechten Knöpfen ein und kostet keine eigene Zeile.
   Kein min-height nötig — die Zeilenhöhe hängt an den Knöpfen. */
.tts-status {
    flex: 1 1 auto; min-width: 0;
    text-align: center; color: var(--muted);
    font-size: 0.72rem; line-height: 1.3;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Sync-Knopf: schwebt über der rechten Ecke der Leiste und lädt ein, die Ansicht
   wieder an das Vorgelesene zu koppeln. Nur sichtbar, wenn die Kopplung ruht. */
.tts-sync-fab {
    position: absolute; right: calc(0.9rem + env(safe-area-inset-right));
    bottom: calc(100% + 0.6rem);
    width: 46px; height: 46px; padding: 11px;
    display: flex; align-items: center; justify-content: center;
    background: var(--accent); border: none; border-radius: 50%;
    color: var(--bg); cursor: pointer;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
    animation: tts-fab-in 0.18s ease-out;
}
.tts-sync-fab[hidden] { display: none; }
.tts-sync-fab:hover, .tts-sync-fab:focus-visible { filter: brightness(1.12); }
@keyframes tts-fab-in {
    from { opacity: 0; transform: scale(0.7); }
    to { opacity: 1; transform: scale(1); }
}

.reader-nav { display: flex; gap: 0.75rem; justify-content: space-between; margin: 2.5rem 0 1rem; max-width: 46rem; margin-left: auto; margin-right: auto; }
.nav-btn {
    flex: 1 1 0; min-height: 46px; padding: 0.75rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.6rem; font-size: 0.95rem;
}
.nav-btn:hover:not(:disabled) { border-color: var(--accent); }
.nav-btn:disabled { opacity: 0.35; cursor: default; }

/* --- Center: character / entry detail ------------------------------------ */

.detail-head { max-width: 52rem; margin: 0 auto 1rem; }
.detail-back {
    min-height: 40px; padding: 0.45rem 0.8rem; margin-bottom: 1rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--accent2);
    border-radius: 0.5rem; font-size: 0.9rem;
}
.detail-back:hover { border-color: var(--accent2); }
.detail-head-top { display: flex; align-items: center; gap: 1rem; }
.detail-head-text { min-width: 0; }
.detail-name { font-family: var(--serif); font-size: 1.7rem; color: var(--accent); margin: 0; overflow-wrap: anywhere; }
.detail-role { color: var(--muted); font-size: 0.95rem; margin: 0.15rem 0 0; }
.detail-aliases { color: var(--muted); font-size: 0.85rem; font-style: italic; margin: 0.35rem 0 0; }
.detail-asof { color: var(--muted); font-size: 0.8rem; margin: 0.5rem 0 0; }

/* Game-style tab bar: horizontal on desktop, horizontally scrollable on
   mobile (touch-friendly, generous tap targets). Active tab in gold. */
.detail-tabs {
    display: flex; gap: 0.4rem; margin-top: 0.7rem;
    overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 0.15rem;
}
.detail-tab {
    flex: 0 0 auto; min-height: 40px; padding: 0.4rem 0.95rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--muted);
    border-radius: 1rem; font-size: 0.82rem; font-weight: 600; white-space: nowrap;
}
.detail-tab.is-active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }

.detail-grid {
    max-width: 52rem; margin: 0 auto;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    gap: 0.9rem; align-content: start;
}
.detail-panel { background: var(--panel); border: 1px solid var(--line); border-radius: 0.7rem; padding: 0.8rem 0.95rem; min-width: 0; }
.detail-panel.wide { grid-column: 1 / -1; }
.panel-head { color: var(--accent2); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; margin: 0 0 0.6rem; }

.st-block { display: grid; grid-template-columns: auto 1fr; gap: 0.2rem 0.9rem; }
.st-label { color: var(--accent); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em; }
.st-val { color: var(--fg); font-size: 0.9rem; overflow-wrap: anywhere; }

.beast { margin: 0.4rem 0; }
.beast-name { font-weight: 600; color: var(--fg); font-size: 0.92rem; }
.beast-ab { margin: 0.2rem 0 0.5rem; padding-left: 1.1rem; }
.beast-ab li { font-size: 0.82rem; color: var(--fg); margin: 0.15rem 0; line-height: 1.45; }

.inv-list { margin: 0; padding-left: 1.1rem; }
.inv-list li { font-size: 0.82rem; color: var(--fg); margin: 0.2rem 0; line-height: 1.45; }
.inv-item { font-weight: 600; }
.inv-detail { color: var(--muted); }
.inv-worth { color: var(--accent); }

.ch-tag { color: var(--muted); font-size: 0.68rem; }

.bal-big { font-size: 0.9rem; margin: 0 0 0.6rem; padding: 0.5rem 0.65rem; background: var(--accent2-soft); border: 1px solid var(--accent2-line); border-radius: 0.5rem; }
.bal-big b { color: var(--accent); font-size: 1rem; }
.ledger { width: 100%; border-collapse: collapse; font-size: 0.78rem; margin: 0.3rem 0; }
.ledger th { text-align: left; color: var(--muted); font-weight: 600; border-bottom: 1px solid var(--line); padding: 0.25rem 0.4rem; font-size: 0.68rem; text-transform: uppercase; }
.ledger td { padding: 0.25rem 0.4rem; border-bottom: 1px solid var(--line); color: var(--fg); vertical-align: top; overflow-wrap: anywhere; }
.ledger .lg-ch { color: var(--accent); }
.ledger .lg-val { color: var(--accent); text-align: right; font-variant-numeric: tabular-nums; }

.fact { font-size: 0.85rem; color: var(--fg); margin: 0.4rem 0; line-height: 1.5; padding-left: 0.6rem; border-left: 2px solid var(--accent-soft); }
.fact b { color: var(--accent); }

/* Verwandte Beast-Formen (Evolutionskette) im Beast-Detail. */
.beast-link-row { display: flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; }
.beast-link-type { color: var(--accent); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; }

/* --- Steckbriefe+: Verbindungen / Gruppen --------------------------------- */

.rel-group { margin: 0 0 0.7rem; }
.rel-group:last-child { margin-bottom: 0; }
.rel-type { color: var(--accent); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; margin-bottom: 0.3rem; }
.rel-row { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; font-size: 0.85rem; margin: 0.2rem 0; }
.rel-name {
    background: none; border: none; padding: 0; color: var(--accent2); font-weight: 600;
    font-size: 0.85rem; text-decoration: underline; text-underline-offset: 0.15em;
}
.rel-name:hover { color: var(--accent); }
.rel-label { color: var(--fg); }

.grp-row { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; font-size: 0.85rem; margin: 0.35rem 0; }
.grp-name { font-weight: 600; color: var(--fg); }
.grp-kind { color: var(--muted); font-size: 0.7rem; border: 1px solid var(--line); border-radius: 0.5rem; padding: 0 0.4rem; }

/* --- Chronik: Codex-Facts als Timeline ------------------------------------ */

.diary-entry { margin: 0 0 1.1rem; }
.diary-entry:last-child { margin-bottom: 0; }
.diary-ch {
    display: inline-block; background: none; border: none; padding: 0;
    color: var(--accent); font-family: var(--serif); font-size: 1.05rem; font-weight: 700;
    text-decoration: underline; text-underline-offset: 0.2em; margin-bottom: 0.3rem;
}
.diary-ch:hover { color: var(--accent2); }
.diary-text { font-size: 0.9rem; color: var(--fg); line-height: 1.55; margin: 0.25rem 0; }

/* --- Bestiarium: Sidebar-Filter -------------------------------------------- */

.beast-filter-row { padding: 0.2rem 0.6rem 0.5rem; }
.beast-only-filter { display: flex; align-items: center; gap: 0.5rem; color: var(--muted); font-size: 0.82rem; cursor: pointer; user-select: none; -webkit-user-select: none; }
.beast-only-filter input { width: 1.05rem; height: 1.05rem; accent-color: var(--accent); }

/* --- Backdrop (mobile drawers) ------------------------------------------- */

#backdrop { display: none; }

/* --- Mobile: panes become off-canvas drawers ----------------------------- */

@media (max-width: 900px) {
    /* Tight header: give the chapter title the slack, keep the progress bar
       (no text), shrink the control cluster, logout becomes an icon. */
    .app-header { gap: 0.4rem; }
    .app-title { flex: 0 1 auto; max-width: 30vw; min-width: 2.5rem; }
    /* Nur die Kapitel-Nummer zeigen — "Kapitel" wird sonst zu "Kapitel …". */
    .app-title .hdr-kapitel { display: none; }
    .header-progress { flex: 0 0 auto; max-width: none; width: 3rem; }
    .prog-bar { min-width: 2.5rem; }
    .prog-text { display: none; }
    /* Die Knopfleiste ist auf schmalen Geräten breiter als der Kopf: statt die
       letzten Icons hinter dem Bildschirmrand verschwinden zu lassen (der Body
       hat overflow:hidden, sie waren also unerreichbar), wird der Streifen
       selbst waagerecht scrollbar. Er bekommt den ganzen Rest der Zeile —
       darum gibt der Titel oben Platz ab. Die Knöpfe schrumpfen dabei nicht
       (icon-btn/font-control stehen auf flex-shrink: 0). */
    .header-controls {
        gap: 0.3rem;
        flex: 1 1 auto;
        min-width: 0;
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }
    .header-controls::-webkit-scrollbar { display: none; }
    /* Rechtsbündig, solange alles passt — als auto-Rand statt justify-content,
       weil flex-end überlaufende Icons links aus dem Kasten schiebt, wo kein
       Scrollen sie zurückholt. Beim Überlauf wird der auto-Rand zu 0, der
       Streifen beginnt links und ist vollständig erreichbar. */
    .header-controls > :first-child { margin-left: auto; }
    .icon-btn { min-width: 34px; min-height: 34px; font-size: 1rem; }
    .font-control { gap: 0.12rem; }
    .font-btn { min-width: 26px; min-height: 34px; }

    #workspace { display: block; }

    #sidebar {
        position: fixed;
        top: 0; bottom: 0;
        width: min(86vw, 22rem);
        z-index: 45;
        transition: transform 0.22s ease;
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.45);
        padding-top: calc(0.5rem + env(safe-area-inset-top));
    }
    #sidebar { left: 0; transform: translateX(-100%); }
    #workspace.sidebar-open > #sidebar { transform: none; }
    /* On mobile the collapse class must not hide the drawer element itself. */
    #workspace.sidebar-collapsed > #sidebar { display: flex; }

    /* #workspace ist hier block — die Mittelspalte übernimmt die volle Höhe,
       #center bekommt den Rest über dem Streifen (flex aus der Grundregel). */
    #centerCol { height: 100%; }
    #center {
        padding: 1.25rem calc(1rem + env(safe-area-inset-right)) 0.9rem calc(1rem + env(safe-area-inset-left));
    }

    #backdrop.is-shown {
        display: block;
        position: fixed; inset: 0;
        background: rgba(6, 8, 12, 0.55);
        z-index: 40;
    }
}

/* --- Volltextsuche: In-Reader-Trefferhervorhebung ------------------------ */

/* Absatz, zu dem gesprungen wurde — kurzer Aufmerksamkeits-Puls. */
.reader-body p.search-hit {
    background: var(--accent-soft);
    box-shadow: 0 0 0 2px var(--accent);
    border-radius: 0.4rem;
    transition: background 0.6s ease, box-shadow 0.6s ease;
}
.search-mark {
    background: var(--accent);
    color: #1a1508;
    border-radius: 0.2rem;
    padding: 0 0.1em;
}
:root[data-theme="light"] .search-mark { color: #fff; }

/* --- Volltextsuche: Overlay ---------------------------------------------- */

.search-overlay {
    position: fixed; inset: 0;
    z-index: 60;
    background: rgba(6, 8, 12, 0.6);
    display: flex; justify-content: center;
    padding: calc(4.5rem + env(safe-area-inset-top)) calc(1rem + env(safe-area-inset-right))
             calc(1rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
    overflow-y: auto;
}
.search-overlay[hidden] { display: none; }

.search-box {
    width: 100%; max-width: 44rem;
    align-self: flex-start;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 0.8rem;
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
    max-height: calc(100vh - 6rem); max-height: calc(100dvh - 6rem);
    display: flex; flex-direction: column;
    overflow: hidden;
}

.search-bar { display: flex; gap: 0.5rem; padding: 0.85rem; border-bottom: 1px solid var(--line); }
.search-input {
    flex: 1 1 auto; min-height: 44px;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.55rem; padding: 0 0.8rem; font-size: 1.05rem;
}
.search-input:focus { outline: none; border-color: var(--accent); }
.search-close {
    flex: 0 0 auto; min-width: 44px; min-height: 44px;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.55rem; font-size: 1.1rem;
}
.search-close:hover { border-color: var(--accent); }

.search-all {
    display: flex; align-items: center; gap: 0.55rem;
    padding: 0.7rem 0.9rem;
    border-bottom: 1px solid var(--line);
    color: var(--error);
    font-size: 0.92rem; cursor: pointer;
}
.search-all input { width: 1.1rem; height: 1.1rem; accent-color: var(--error); flex: 0 0 auto; }
.search-all-txt { user-select: none; -webkit-user-select: none; }

.search-opts {
    display: flex; flex-wrap: wrap; gap: 0.5rem 1.4rem;
    padding: 0.65rem 0.9rem;
    border-bottom: 1px solid var(--line);
}
.search-opt {
    display: flex; align-items: center; gap: 0.45rem;
    color: var(--muted); font-size: 0.9rem; cursor: pointer; user-select: none; -webkit-user-select: none;
}
.search-opt input { width: 1.05rem; height: 1.05rem; accent-color: var(--accent); flex: 0 0 auto; }

.search-scope {
    padding: 0.55rem 0.9rem;
    color: var(--muted); font-size: 0.85rem;
    border-bottom: 1px solid var(--line);
}
.search-scope-all { color: var(--error); }

.search-results { padding: 0.6rem 0.9rem 1rem; overflow-y: auto; }
.search-hint { color: var(--muted); padding: 1rem 0.2rem; font-size: 0.95rem; }
.search-count { color: var(--muted); font-size: 0.82rem; margin: 0.2rem 0 0.7rem; }

/* Block „Im Codex" — Treffer aus Almanach, Steckbriefen und Bestiarium,
   oberhalb der Kapiteltext-Treffer. */
.search-codex { margin-bottom: 1.2rem; }
.search-codex-head {
    color: var(--accent); font-weight: 700; font-size: 0.9rem;
    padding-bottom: 0.35rem; margin-bottom: 0.45rem;
    border-bottom: 1px solid var(--line);
}
.search-codex-line {
    display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap;
    margin-bottom: 0.25rem;
}
.search-codex-name { color: var(--fg); font-weight: 700; font-size: 0.95rem; }
.search-codex-kind { color: var(--muted); font-size: 0.82rem; }
.search-codex-row .search-snippet { font-size: 0.92rem; }

.search-group { margin-bottom: 1.1rem; }
.search-group-head {
    display: flex; align-items: baseline; gap: 0.5rem;
    padding-bottom: 0.35rem; margin-bottom: 0.35rem;
    border-bottom: 1px solid var(--line);
}
.search-ch { color: var(--accent); font-weight: 700; font-size: 0.9rem; flex: 0 0 auto; }
.search-ch-title { color: var(--fg); font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-warn { color: var(--error); flex: 0 0 auto; }
.search-group.is-spoiler .search-ch { color: var(--error); }

.search-hit-row {
    display: block; width: 100%; text-align: left;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.5rem; padding: 0.6rem 0.75rem; margin-bottom: 0.4rem;
    font-family: var(--serif); font-size: 0.98rem; line-height: 1.5;
}
.search-hit-row:hover { border-color: var(--accent); }
.search-snippet { color: var(--fg); }
.search-more { color: var(--muted); font-size: 0.82rem; padding: 0.1rem 0.2rem 0.3rem; }

@media (max-width: 900px) {
    /* Vollbild, aber die Statusleiste bleibt frei — mit `padding: 0` saß die
       Suchzeile samt ✕ unter Uhr und Akku. */
    .search-overlay {
        padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
        background: var(--panel);
        overflow: hidden;
    }
    .search-box {
        max-width: none; height: 100%; max-height: none;
        border: 0; border-radius: 0; box-shadow: none;
    }
}
/* Nachladen / Zum Lesestand */
.search-tail { padding: 0.4rem 0 0.6rem; }
.search-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0.3rem 0 0.6rem; }
.search-action-btn {
    min-height: 40px; padding: 0 0.9rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.6rem; font-size: 0.9rem; cursor: pointer;
}
.search-action-btn:hover { border-color: var(--accent); }
.search-group.is-here .search-group-head { border-left: 3px solid var(--accent); padding-left: 0.4rem; }

/* --- Verbindungs-Streifen (App läuft aus dem Offline-Speicher) ------------ */
/* KEIN Overlay: der Streifen ist ein Geschwister von .app-header und #workspace
   und schiebt den Inhalt herunter. Ein schwebender Kasten lag genau über
   Kapiteltitel und ersten Zeilen — also über dem, was man gerade liest.
   Der Satz steht nur ein paar Sekunden, dann klappt alles bis auf den farbigen
   Strich zusammen: rot = keine Verbindung, orange = Versuch läuft, grün = wieder
   da. Die Farbe trägt den Zustand weiter, der Text muss dafür nicht stehen
   bleiben. */

.net-strip {
    flex: 0 0 auto;
    background: var(--panel);
    border-bottom: 1px solid var(--line);
    overflow: hidden;
    z-index: 29;   /* unter der Kopfleiste (30), damit deren Schatten oben bleibt */
}
.net-strip[hidden] { display: none; }

/* Der Strich IST der Knopf — zugeklappt ist er die einzige Fläche, die bleibt.
   6 px sind schmal genug, um nicht zu stören, und breit genug zum Treffen; die
   unsichtbare Vergrößerung per ::after macht daraus ein bequemes Ziel, ohne
   Platz zu kosten. */
.net-strip-bar {
    position: relative;
    height: 6px;
    background: var(--muted);
    cursor: pointer;
    transition: background 0.3s ease;
}
.net-strip-bar::after {
    content: ''; position: absolute; left: 0; right: 0; top: -6px; bottom: -6px;
}
.net-strip.is-offline .net-strip-bar { background: var(--error); }
.net-strip.is-trying  .net-strip-bar { background: var(--warn); animation: net-pulse 1.4s ease-in-out infinite; }
.net-strip.is-online  .net-strip-bar { background: var(--good); }
@keyframes net-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

.net-strip-body {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.4rem calc(0.75rem + env(safe-area-inset-right)) 0.4rem calc(0.75rem + env(safe-area-inset-left));
    font-family: var(--sans); font-size: 0.82rem; color: var(--muted);
    max-height: 4rem; opacity: 1;
    transition: max-height 0.28s ease, opacity 0.2s ease, padding 0.28s ease;
}
.net-strip.is-collapsed .net-strip-body {
    max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0;
}
.net-strip-text { flex: 1 1 auto; }
.net-strip-retry {
    flex: 0 0 auto;
    min-height: 30px; padding: 0 0.6rem;
    background: transparent; color: var(--fg);
    border: 1px solid var(--line); border-radius: 0.45rem;
    font-size: 0.8rem; cursor: pointer; white-space: nowrap;
}
.net-strip-retry:hover { border-color: var(--accent); }
.net-strip-retry[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
    .net-strip-body { transition: none; }
    .net-strip.is-trying .net-strip-bar { animation: none; }
}

/* --- Weiterlesen-Popup (Scroll-Sync über Geräte) -------------------------- */

.continue-banner {
    position: fixed;
    left: 50%;
    bottom: calc(1rem + env(safe-area-inset-bottom));
    transform: translateX(-50%);
    z-index: 70;
    width: calc(100% - 2rem);
    max-width: 30rem;
    display: flex; align-items: center; gap: 0.75rem;
    background: var(--panel);
    border: 1px solid var(--accent);
    border-radius: 0.7rem;
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.4);
    padding: 0.75rem 0.85rem;
    animation: continue-in 0.25s ease-out;
}
@keyframes continue-in {
    from { opacity: 0; transform: translateX(-50%) translateY(0.6rem); }
    to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.continue-text {
    flex: 1 1 auto; margin: 0;
    font-family: var(--serif); font-size: 0.92rem; line-height: 1.4;
    color: var(--fg);
}
.continue-delta {
    display: inline-block;
    font-family: var(--sans); font-weight: 700; font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    padding: 0.02rem 0.4rem; border-radius: 0.55rem;
    border: 1px solid currentColor; vertical-align: baseline;
    white-space: nowrap;
}
.continue-delta.is-ahead { color: var(--good); }
.continue-delta.is-behind { color: var(--error); }
.continue-actions { display: flex; align-items: center; gap: 0.4rem; flex: 0 0 auto; }
.continue-go {
    min-height: 40px; padding: 0 0.85rem;
    background: var(--accent); color: #20180a; border: none;
    border-radius: 0.5rem; font-weight: 700; font-size: 0.88rem; cursor: pointer;
    white-space: nowrap;
}
.continue-go:hover { filter: brightness(1.08); }
.continue-dismiss {
    min-width: 36px; min-height: 36px;
    background: var(--panel2); border: 1px solid var(--line); color: var(--muted);
    border-radius: 0.5rem; font-size: 0.9rem; cursor: pointer;
}
.continue-dismiss:hover { border-color: var(--accent); color: var(--fg); }

@media (max-width: 900px) {
    .continue-banner {
        left: 0.75rem; right: 0.75rem; bottom: calc(0.75rem + env(safe-area-inset-bottom));
        transform: none;
        width: auto; max-width: none;
        flex-wrap: wrap;
    }
    @keyframes continue-in {
        from { opacity: 0; transform: translateY(0.6rem); }
        to { opacity: 1; transform: translateY(0); }
    }
}

/* --- "Weiterlesen" — Recent-Menü (Dropdown unter dem 📍-Button) ------------ */

.recent-menu {
    position: fixed;
    z-index: 80;
    width: min(20rem, calc(100vw - 1.5rem));
    max-height: 60vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 0.6rem;
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.4);
    padding: 0.35rem;
    animation: recent-in 0.14s ease-out;
}
@keyframes recent-in {
    from { opacity: 0; transform: translateY(-0.35rem); }
    to { opacity: 1; transform: translateY(0); }
}

/* Handy: Dropdown wird zum Bottom-Sheet über die volle Breite — nichts ragt mehr
   aus dem Viewport. Backdrop dimmt den Hintergrund und schließt bei Außentap. */
.recent-backdrop {
    position: fixed; inset: 0; z-index: 79;
    background: rgba(0, 0, 0, 0.45);
    animation: recent-in 0.14s ease-out;
}
.recent-menu--sheet {
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto; max-width: none;
    max-height: 72vh;
    border-radius: 0.9rem 0.9rem 0 0;
    border-left: none; border-right: none; border-bottom: none;
    padding: 0.4rem 0.7rem calc(0.7rem + env(safe-area-inset-bottom));
    animation: recent-sheet-in 0.2s ease-out;
}
/* Griff-Andeutung oben am Sheet. */
.recent-menu--sheet::before {
    content: ""; display: block;
    width: 2.4rem; height: 0.28rem; margin: 0.15rem auto 0.35rem;
    background: var(--line); border-radius: 999px;
}
.recent-menu--sheet .recent-item { padding: 0.7rem 0.6rem; }
@keyframes recent-sheet-in {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}
.recent-menu-head {
    padding: 0.4rem 0.55rem 0.5rem;
    font-size: 0.72rem; letter-spacing: 0.04em; text-transform: uppercase;
    color: var(--muted);
}
.recent-empty { padding: 0.3rem 0.55rem 0.6rem; color: var(--muted); font-size: 0.88rem; }
.recent-item {
    display: flex; align-items: baseline; gap: 0.5rem;
    width: 100%; text-align: left;
    padding: 0.55rem 0.55rem;
    background: transparent; border: none; border-radius: 0.45rem;
    color: var(--fg); font-family: var(--serif); font-size: 0.95rem; cursor: pointer;
}
.recent-item:hover, .recent-item:focus-visible { background: var(--accent-soft); outline: none; }
.recent-item-main { flex: 1 1 auto; }
.recent-item-sub { color: var(--muted); font-size: 0.85em; }
.recent-item-delta {
    flex: 0 0 auto;
    font-family: var(--sans); font-weight: 700; font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
    padding: 0.02rem 0.4rem; border-radius: 0.5rem; border: 1px solid currentColor;
    white-space: nowrap;
}
.recent-item-delta.is-ahead { color: var(--good); }
.recent-item-delta.is-behind { color: var(--error); }
.recent-item-here {
    flex: 0 0 auto;
    font-family: var(--sans); font-weight: 600; font-size: 0.72rem;
    color: var(--accent); background: var(--accent-soft);
    padding: 0.02rem 0.4rem; border-radius: 0.5rem; white-space: nowrap;
}
.recent-item-time { flex: 0 0 auto; color: var(--muted); font-size: 0.74rem; white-space: nowrap; }

/* --- Bibliothek: das Regal ------------------------------------------------
 *
 * Buchkarten statt Listenzeilen: das Cover trägt die Wiedererkennung, Titel und
 * Autor stehen daneben wie auf dem Buchrücken. Fehlt ein Cover, springt der
 * Platzhalter (zwei Buchstaben in Serifen) ein — die Karte behält ihre Form,
 * damit das Regal nicht ausfranst. */

.lib-wrap { max-width: 52rem; margin: 0 auto; padding: 1.2rem 1rem 3rem; }
.lib-head {
    margin: 0 0 1rem; font-family: var(--serif); font-size: 1.5rem; font-weight: 600;
    color: var(--fg); letter-spacing: 0.01em;
}
.lib-loading { color: var(--muted); font-size: 0.95rem; }

.lib-grid { display: flex; flex-direction: column; gap: 0.7rem; }

.lib-card {
    display: flex; align-items: stretch; gap: 0.9rem; position: relative;
    width: 100%; text-align: left; padding: 0.8rem;
    background: var(--panel); border: 1px solid var(--line); border-radius: 0.7rem;
    color: var(--fg); font-family: inherit; cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.lib-card:hover, .lib-card:focus-within { border-color: var(--accent); outline: none; }
.lib-card.is-current { border-color: var(--accent); background: var(--accent-soft); }

/* Öffnen liegt als unsichtbarer Knopf ÜBER der ganzen Karte, damit der
 * Lesestand-Knopf daneben ein eigenes Ziel sein kann (Knopf im Knopf wäre
 * ungültiges HTML). Die Karteninhalte darunter nehmen keine Klicks an. */
.lib-open {
    position: absolute; inset: 0; z-index: 1;
    background: none; border: 0; border-radius: inherit; padding: 0;
    cursor: pointer; color: inherit; font: inherit;
}
.lib-open:disabled { cursor: default; }
.lib-card > .lib-cover, .lib-card > .lib-body, .lib-card > .lib-badge { pointer-events: none; }

/* Lesestand anfassen: unten rechts, ruhig, erst beim Darüberfahren betont. */
.lib-adjust {
    position: absolute; right: 0.45rem; bottom: 0.45rem; z-index: 2;
    width: 2rem; height: 2rem; padding: 0.35rem;
    display: flex; align-items: center; justify-content: center;
    background: none; border: 0; border-radius: 50%;
    color: var(--muted); cursor: pointer;
}
.lib-adjust:hover, .lib-adjust:focus-visible {
    color: var(--accent); background: var(--panel2); outline: none;
}

/* Cover: feste 2:3-Fläche. Das Bild liegt darüber, der Platzhalter darunter —
 * bricht das Bild weg (img.remove()), steht die Fläche trotzdem. */
.lib-cover {
    position: relative; flex: 0 0 auto; width: 3.6rem; aspect-ratio: 2 / 3;
    display: flex; align-items: center; justify-content: center; overflow: hidden;
    background: var(--panel2); border: 1px solid var(--line); border-radius: 0.35rem;
}
.lib-cover img {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.lib-cover-fallback {
    font-family: var(--serif); font-size: 1.1rem; font-weight: 600;
    color: var(--accent); text-transform: uppercase; letter-spacing: 0.04em;
}

/* Rechts bleibt Luft für den Lesestand-Knopf, damit die letzte Zeile
 * (Features/Chips) nicht unter ihm verschwindet. */
.lib-body {
    display: flex; flex-direction: column; gap: 0.22rem;
    min-width: 0; flex: 1 1 auto; padding-right: 2.2rem;
}
.lib-title { font-family: var(--serif); font-size: 1.02rem; font-weight: 600; line-height: 1.3; }
.lib-author { color: var(--muted); font-size: 0.85rem; }
.lib-meta { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.15rem; }
.lib-chip {
    font-size: 0.72rem; font-weight: 600; font-variant-numeric: tabular-nums;
    padding: 0.08rem 0.42rem; border-radius: 0.5rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--muted);
}
.lib-chip.is-progress { color: var(--accent); border-color: var(--accent); background: transparent; }
.lib-feats { color: var(--muted); font-size: 0.76rem; margin-top: 0.1rem; }

.lib-badge {
    position: absolute; top: 0.55rem; right: 0.6rem;
    font-size: 0.68rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--accent);
}

/* Lesefortschritt-Dialog: nutzt die Vollbild-Einstellungen aus dem Vorlesen
 * (.tts-settings*), setzt nur das Eigene obendrauf. */
.lib-reset .lib-reset-sub { margin-top: 1rem; }
.lib-reset-input {
    min-height: 40px; width: 6rem; padding: 0.35rem 0.6rem;
    background: var(--panel2); border: 1px solid var(--line); color: var(--fg);
    border-radius: 0.6rem; font-size: 0.85rem; font-family: inherit;
    font-variant-numeric: tabular-nums;
}
.lib-reset-input:focus { border-color: var(--accent); outline: none; }
.lib-reset-err:empty { display: none; }
.lib-reset-err { color: var(--error); margin-top: 0.6rem; }
.lib-reset-actions {
    display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.1rem;
}
.tts-chip.is-danger { color: var(--error); border-color: var(--error); }
.tts-chip.is-danger:hover { border-color: var(--error); background: var(--panel2); }
.tts-chip:disabled { opacity: 0.5; }

/* Eingetragen, aber noch nicht geholt: sichtbar (es kommt ja), nur nicht
 * anklickbar — ein Tipp liefe sonst in einen Fehler. */
.lib-card.is-pending { opacity: 0.55; cursor: default; }
.lib-card.is-pending:hover { border-color: var(--line); }

/* Comics (Paket 032): Serien-Kachel und Heft-Raster. Die Karten sind die der
 * Bibliothek; hier steht nur der Kopf der Serie und was ein Comic NICHT hat. */
.lib-chip.is-comic { color: var(--accent); border-color: var(--accent); background: transparent; }
.issues-head { display: flex; gap: 1rem; align-items: flex-start; margin-bottom: 1.2rem; }
.issues-cover { width: 5.5rem; }
.issues-meta { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; flex: 1 1 auto; }
.issues-meta .lib-head { margin: 0; }
.issues-summary { margin: 0.4rem 0 0.2rem; color: var(--muted); font-size: 0.9rem; line-height: 1.45; }
.issues-resume { align-self: flex-start; margin-top: 0.4rem; }
/* Ein Comic hat keine Kapitelliste, keinen Codex, kein Vorlesen, keine Schrift,
 * keine Textsuche und keine Lese-Historie nach Absätzen: die Bedienelemente
 * wegzulassen ist ehrlicher als sie anzubieten, damit sie in einen 400 laufen. */
body.is-comic #toggleSidebar,
body.is-comic #sidebar,
body.is-comic #toggleSearch,
body.is-comic #toggleRecent,
body.is-comic #fontControl,
body.is-comic #toggleSettings,
body.is-comic #ttsDock,
body.is-comic #headerProgress { display: none; }

/* --- Comic-Reader (Paket 033): Overlay über der ganzen App ------------------- */
body.comic-open { overflow: hidden; }
.comic-reader { position: fixed; inset: 0; z-index: 1000; background: #000; color: #fff; }
.comic-reader .cr-scroll {
    position: absolute; inset: 0; overflow: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch; touch-action: pan-x pan-y pinch-zoom;
}
.comic-reader .cr-img { display: block; margin: 0 auto; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
/* Hochformat: ganze Seite eingepasst; Doppeltipp schaltet auf Breite füllen. */
.comic-reader.is-fit .cr-img { width: 100%; height: 100vh; height: 100dvh; object-fit: contain; }
.comic-reader:not(.is-fit) .cr-img { width: 200%; max-width: none; height: auto; margin: 0; }
/* Querformat: immer volle Breite, die Seite scrollt senkrecht — auch ohne is-fit
 * (sonst schlüge :not(.is-fit) mit höherer Spezifität durch, D-011). */
@media (orientation: landscape) {
    .comic-reader .cr-img, .comic-reader.is-fit .cr-img, .comic-reader:not(.is-fit) .cr-img { width: 100vw; height: auto; margin: 0; object-fit: fill; }
}
.comic-reader .cr-bar {
    position: absolute; left: 0; right: 0; display: flex; align-items: center; gap: 0.8rem;
    padding: 0.5rem 1rem; background: rgba(0, 0, 0, 0.78);
    opacity: 0; pointer-events: none; transition: opacity 0.15s;
}
.comic-reader.bar-on .cr-bar { opacity: 1; pointer-events: auto; }
.comic-reader .cr-top { top: 0; padding-top: calc(0.5rem + env(safe-area-inset-top)); padding-left: calc(1rem + env(safe-area-inset-left)); padding-right: calc(1rem + env(safe-area-inset-right)); }
.comic-reader .cr-bottom { bottom: 0; padding-bottom: calc(0.7rem + env(safe-area-inset-bottom)); padding-left: calc(1rem + env(safe-area-inset-left)); padding-right: calc(1rem + env(safe-area-inset-right)); }
.comic-reader .cr-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.comic-reader .cr-count { flex: none; font-variant-numeric: tabular-nums; }
.comic-reader .cr-close { flex: none; width: 2.4rem; height: 2.4rem; border: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.16); color: #fff; font-size: 1.1rem; cursor: pointer; }
.comic-reader .cr-range { width: 100%; }
.comic-reader .cr-toast {
    position: absolute; left: 50%; bottom: calc(1.6rem + env(safe-area-inset-bottom)); transform: translateX(-50%);
    padding: 0.4rem 0.9rem; border-radius: 1rem; background: rgba(0, 0, 0, 0.82); font-size: 0.9rem;
    opacity: 0; pointer-events: none; transition: opacity 0.2s;
}
.comic-reader .cr-toast.is-on { opacity: 1; }
