/*
 * Radio GUDE Webplayer – die Oberfläche (Issue #112).
 *
 * Eine App und keine Webseite. Das ist keine Stilfrage, sondern die Vorgabe
 * des Auftrags, und sie hat konkrete Folgen:
 *
 *  - Es gibt **einen** Bildschirm, und er füllt genau das Fenster. Gescrollt
 *    wird nirgends im Ganzen; was nicht passt, bekommt einen eigenen
 *    Bildlauf (der Sendeplan) oder wird kleiner (Cover, Schriftgrade).
 *  - Die Fläche ist dunkel und bleibt es. Ein heller Systemmodus schaltet
 *    hier nichts um – ein Radio ist kein Dokument.
 *  - Die Atmosphäre kommt aus dem Cover: dasselbe Bild, groß, weichgezeichnet
 *    und abgedunkelt hinter allem. Keine gerechnete Farbe, kein Canvas – das
 *    Cover liegt auf radio-gude.de und wäre in einem Canvas nicht auslesbar.
 *
 * Die Markenfarbe steht über der Atmosphäre (Martin, 12.09.2026)
 * ---------------------------------------------------------------
 * Aus der Abnahme kamen zwei Sätze, die zusammengehören: Der dynamische
 * Hintergrund aus den Coverfarben **bleibt** – weich, gedämpft, dunkel. Und:
 * „Radio-GUDE-Rot #da0000 muss als feste Markenfarbe deutlich stärker sichtbar
 * bleiben, unabhängig davon, welche Coverfarben gerade dominieren."
 *
 * Beides zugleich geht nur, wenn das Rot **nicht** aus dem Bild kommt. Es
 * liegt deshalb an festen Stellen, die kein Cover erreicht:
 *
 *   1. eine durchgehende rote Kante ganz oben (`.rgp-body::before`) – das
 *      Senderzeichen, das immer da ist;
 *   2. ein roter Schimmer im Schleier über **jedem** Cover, nicht nur im
 *      Rückfall;
 *   3. die Bedienelemente selbst: Play-Knopf, LIVE-Marke, Coverring,
 *      Panelkante, Chat-Knopf, Fortschritt, Marken und Fokus.
 *
 * Die dritte Gruppe zieht an, sobald wirklich Ton läuft (`data-ton="1"` am
 * Körper): Ein Radio, das spielt, darf man ansehen. Das ist derselbe Gedanke
 * wie bei der LIVE-Marke, nur konsequent über die ganze Oberfläche.
 *
 * Fünf Formate, und jedes ist eigens gebaut – nicht eines gedreht:
 *
 *  1. Telefon hochkant      Grundfassung dieser Datei
 *  2. Telefon quer          `(orientation: landscape) and (max-height: 540px)`
 *  3. Tablet hochkant       `(min-width: 700px) and (orientation: portrait)`
 *  4. Tablet quer           `(min-width: 900px)`  – zwei Spalten
 *  5. Schreibtisch          `(min-width: 1200px)` – dieselben zwei Spalten,
 *                           großzügiger, mit stehendem Sendeplan
 *
 * Die 44-px-Tippfläche aus Issue #35 gilt hier wie überall; der Play-Knopf
 * ist deutlich größer, weil er auf dem Telefon das Bedienelement ist.
 */

/* ══════════════════════════════════════════════════════════════════════════
   Grundwerte
   ══════════════════════════════════════════════════════════════════════════ */

.rgp {
    /* Die Hausfarbe. Sie steht ein zweites Mal in `app/routers/player.py`
       (das Manifest kann kein Stylesheet lesen); die Prüfung vergleicht. */
    --rgp-rot: #da0000;
    --rgp-rot-hell: #ff3b30;
    --rgp-rot-tief: #9d0000;

    /* Die Markenfarbe in ihren Abstufungen – eine Zeile je Aufgabe, damit
       „mehr Rot" nicht heißt, an zwanzig Stellen eine Zahl zu ändern. */
    --rgp-rot-flaeche: rgba(218, 0, 0, 0.22);
    --rgp-rot-kante: rgba(218, 0, 0, 0.55);
    --rgp-rot-schimmer: rgba(218, 0, 0, 0.34);

    --rgp-flaeche: #0b0b0d;
    --rgp-karte: rgba(255, 255, 255, 0.07);
    --rgp-kante: rgba(255, 255, 255, 0.13);
    --rgp-text: #f5f5f7;
    --rgp-gedaempft: rgba(245, 245, 247, 0.62);
    --rgp-leise: rgba(245, 245, 247, 0.42);

    --rgp-rand: 20px;
    --rgp-radius: 18px;
    --rgp-tippflaeche: 44px;

    /* Die beiden Schriftgrößen der Titelzeile. Sie stehen als Größen da, weil
       aus ihnen die **feste Höhe** des Kastens gerechnet wird – siehe dort. */
    --rgp-titelgroesse: 21px;
    --rgp-interpretgroesse: 15px;

    /* Die sichere Fläche. Sie steht als eigene Größe da, damit jede Regel
       darunter sie addieren kann, statt `env()` zu wiederholen. */
    --rgp-sicher-oben: env(safe-area-inset-top, 0px);
    --rgp-sicher-unten: env(safe-area-inset-bottom, 0px);
    --rgp-sicher-links: env(safe-area-inset-left, 0px);
    --rgp-sicher-rechts: env(safe-area-inset-right, 0px);

    color-scheme: dark;
    background: var(--rgp-flaeche);
    /* 100dvh statt 100vh: Auf dem Telefon wächst und schrumpft die
       Adressleiste, und mit `vh` stünde die Bedienung mal unter dem Rand. */
    height: 100%;
}

*,
*::before,
*::after { box-sizing: border-box; }

.rgp-body {
    margin: 0;
    min-height: 100dvh;
    height: 100dvh;
    overflow: hidden;
    background: var(--rgp-flaeche);
    color: var(--rgp-text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                 "Helvetica Neue", Arial, sans-serif;
    font-size: 16px;
    line-height: 1.4;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    /* Ein Doppeltipp auf das Cover soll den Display-Modus umschalten und
       nicht hineinzoomen. */
    touch-action: manipulation;
}

/*
 * `hidden` muss `hidden` bleiben.
 *
 * Mehrere Bedienelemente dieser App stehen im Dokument und werden erst
 * freigegeben, wenn die Plattform sie wirklich kann – Lautstärke, AirPlay,
 * Teilen. Das Attribut allein genügt dafür nicht: Es setzt `display: none`
 * aus dem Browser-Stylesheet, und jede Regel hier mit `display: grid` oder
 * `display: flex` gewinnt gegen sie. Ohne diese Zeile stünde auf dem
 * Schreibtisch ein AirPlay-Knopf, den es dort nicht gibt – genau die
 * Fake-Funktionalität, die der Auftrag ausschließt.
 */
.rgp-body [hidden] { display: none !important; }

/*
 * Die rote Kante ganz oben – das Senderzeichen dieser App.
 *
 * Sie ist der eine Ort, an dem das Radio-GUDE-Rot völlig unabhängig vom Cover
 * steht: über der Bühne, über dem Panel, über dem Display-Modus. Ein dunkles
 * Cover, ein blaues, ein grünes – die Kante bleibt. Sie sitzt in der sicheren
 * Fläche, damit sie auf dem iPhone nicht unter der Statusleiste verschwindet,
 * und nimmt keine Tipps entgegen.
 */
.rgp-body::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: calc(var(--rgp-sicher-oben) + 3px);
    z-index: 8;
    background: linear-gradient(90deg,
        var(--rgp-rot-tief), var(--rgp-rot) 30%,
        var(--rgp-rot-hell) 52%, var(--rgp-rot) 74%, var(--rgp-rot-tief));
    pointer-events: none;
}

.rgp-nurlesen {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   Der Hintergrund aus dem Cover
   ══════════════════════════════════════════════════════════════════════════ */

.rgp-hintergrund {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    background: var(--rgp-flaeche);
}

.rgp-hintergrund__ebene {
    position: absolute;
    /* Über den Rand hinaus: Ein weichgezeichnetes Bild wird an seinen Kanten
       durchsichtig, und darunter käme die nackte Fläche zum Vorschein. */
    inset: -12%;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    filter: blur(48px) saturate(1.5);
    transform: scale(1.15);
    opacity: 0;
    transition: opacity 900ms ease;
    will-change: opacity;
}

.rgp-hintergrund__ebene.is-aktiv { opacity: 1; }

/*
 * Der Schleier. Ohne ihn stünde weißer Text auf einem hellen Cover – und seit
 * dem 12.09.2026 trägt er zusätzlich die Markenfarbe.
 *
 * Die beiden roten Verläufe liegen **über** dem Cover und sind von ihm
 * unabhängig: oben ein Schimmer, unten ein Saum. Damit bleibt die Atmosphäre
 * aus den Coverfarben erhalten – sie scheint durch –, und trotzdem ist jede
 * Ansicht auf den ersten Blick Radio GUDE und nicht die Farbstimmung einer
 * Plattenhülle. Genau das war Martins Ergänzung zur Abnahme.
 */
.rgp-hintergrund__schleier {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(150% 78% at 50% -12%,
            var(--rgp-rot-schimmer), rgba(218, 0, 0, 0) 60%),
        radial-gradient(130% 62% at 50% 112%,
            rgba(218, 0, 0, 0.24), rgba(218, 0, 0, 0) 58%),
        radial-gradient(120% 90% at 50% 12%, rgba(11, 11, 13, 0.30), rgba(11, 11, 13, 0.84) 72%),
        linear-gradient(180deg, rgba(11, 11, 13, 0.50), rgba(11, 11, 13, 0.90));
}

/* Ohne Cover trägt die Fläche das Branding allein – kein schwarzes Blatt. */
.rgp-body[data-cover="fallback"] .rgp-hintergrund__schleier {
    background:
        radial-gradient(130% 92% at 50% -6%, rgba(218, 0, 0, 0.46), rgba(11, 11, 13, 0.90) 66%),
        radial-gradient(130% 62% at 50% 112%, rgba(218, 0, 0, 0.28), rgba(218, 0, 0, 0) 58%),
        linear-gradient(180deg, rgba(11, 11, 13, 0.50), rgba(11, 11, 13, 0.94));
}

/* ══════════════════════════════════════════════════════════════════════════
   Die Bühne – Telefon hochkant (Grundfassung)
   ══════════════════════════════════════════════════════════════════════════ */

.rgp-buehne {
    position: relative;
    z-index: 1;
    /*
     * Die Bühne endet über der Bereichsleiste – sie ist seit dem 14.09.2026
     * die untere Kante dieser App (`--rgp-navraum`, weiter unten). Am
     * Schreibtisch steht die Leiste in der Kopfzeile; dort ist der Raum null,
     * und diese Zeile rechnet wieder mit der vollen Fensterhöhe.
     *
     * Eine Rechnung an **einer** Stelle und nicht vier Abstände in vier
     * Formaten: Jedes Format hat sein eigenes `padding-bottom`, und ein
     * fünftes Format wäre die Stelle, an der man es vergisst.
     */
    height: calc(100dvh - var(--rgp-navraum, 0px));
    display: grid;
    /* Kopf – Cover – Titel – Bedienung. Das Cover bekommt den Rest und ist
       damit so groß wie möglich; genau das verlangt der Auftrag für das
       Telefon im Hochformat. */
    grid-template-rows: auto minmax(0, 1fr) auto auto;
    gap: 12px;
    /* Unten der Platz für den zusammengeschobenen Sendeplan. Er ist `fixed`
       und nimmt deshalb keine Zeile im Raster ein – ohne diesen Abstand läge
       er über dem Play-Knopf. Die Safe Area steht hier seit dem 14.09.2026
       nicht mehr: Sie gehört jetzt der Bereichsleiste ganz unten, und zweimal
       gerechnet wäre sie ein Streifen Luft, den niemand bestellt hat. */
    padding:
        calc(var(--rgp-sicher-oben) + 14px)
        calc(var(--rgp-sicher-rechts) + var(--rgp-rand))
        calc(var(--rgp-griffhoehe, 84px) + 6px)
        calc(var(--rgp-sicher-links) + var(--rgp-rand));
}

/* ── Kopf ──────────────────────────────────────────────────────────────── */

.rgp-kopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 32px;
}

.rgp-marke {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.rgp-marke__signet {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    display: block;
    /* Der rote Ring gehört zur Marke und nicht zum Bild: Das Signet selbst ist
       rot auf dunkel und verschwindet sonst auf einem dunklen Cover. */
    box-shadow: 0 0 0 1.5px var(--rgp-rot-kante);
}

.rgp-marke__name { color: var(--rgp-text); }

/* Der rote Strich unter dem Sendernamen – klein, fest, coverunabhängig. */
.rgp-marke__name::after {
    content: "";
    display: block;
    height: 2px;
    margin-top: 3px;
    border-radius: 1px;
    background: var(--rgp-rot);
}

/* Die LIVE-Marke: dezent, ohne Blinken und ohne Verlauf. Sie ist gedämpft,
   solange nichts läuft, und leuchtet erst, wenn wirklich Ton kommt. */
.rgp-live {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 11px;
    border: 1px solid var(--rgp-kante);
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.14em;
    color: var(--rgp-leise);
    background: rgba(0, 0, 0, 0.25);
    transition: color 300ms ease, border-color 300ms ease;
}

.rgp-live__punkt {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

/* Auf Sendung ist die Marke rot gefüllt und nicht nur rot umrandet. Sie war
   vorher eine dunkle Pille mit einem roten Punkt darin – aus zwei Metern sah
   das aus wie „aus". */
.rgp-live[data-an="1"] {
    color: #fff;
    background: var(--rgp-rot);
    border-color: var(--rgp-rot-hell);
    box-shadow: 0 4px 16px rgba(218, 0, 0, 0.45);
}

.rgp-live[data-an="1"] .rgp-live__punkt {
    background: #fff;
    box-shadow: 0 0 9px rgba(255, 255, 255, 0.85);
}

/* ── Cover ─────────────────────────────────────────────────────────────── */

.rgp-cover {
    display: grid;
    place-items: center;
    min-height: 0;
}

.rgp-cover__flaeche {
    position: relative;
    display: block;
    /* Quadratisch, so groß wie die Zeile es zulässt – begrenzt von der
       Höhe der Zeile und der Breite der Spalte. */
    aspect-ratio: 1 / 1;
    height: 100%;
    max-height: 100%;
    max-width: 100%;
    margin: 0 auto;
    padding: 0;
    border: 0;
    border-radius: 22px;
    background: rgba(0, 0, 0, 0.3);
    /* Der rote Ring um das Cover: die Fassung, in der das Bild sitzt. Er ist
       immer da und zieht an, sobald wirklich Ton läuft. */
    box-shadow: 0 26px 60px rgba(0, 0, 0, 0.55),
                0 0 0 2px var(--rgp-rot-kante);
    overflow: hidden;
    cursor: pointer;
    touch-action: manipulation;
    transition: box-shadow 320ms ease;
}

.rgp-body[data-ton="1"] .rgp-cover__flaeche {
    box-shadow: 0 26px 60px rgba(0, 0, 0, 0.55),
                0 0 0 2px var(--rgp-rot),
                0 0 34px rgba(218, 0, 0, 0.45);
}

.rgp-cover__bild {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: opacity 400ms ease;
}

/* Das Fallback-Signet ist ein Logo und kein Foto – es wird nicht beschnitten. */
.rgp-body[data-cover="fallback"] .rgp-cover__bild {
    object-fit: contain;
    padding: 12%;
    background: rgba(0, 0, 0, 0.35);
}

/* Die Audioaktivität. Fünf Striche, die nur laufen, wenn `data-an="1"` –
   und sie stehen still, wenn das Gerät weniger Bewegung wünscht. */
.rgp-pegel {
    position: absolute;
    left: 14px;
    bottom: 14px;
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 20px;
    padding: 6px 8px;
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.42);
    opacity: 0;
    transition: opacity 300ms ease;
}

.rgp-pegel[data-an="1"] { opacity: 1; }

.rgp-pegel i {
    display: block;
    width: 3px;
    height: 4px;
    border-radius: 2px;
    background: var(--rgp-rot-hell);
}

.rgp-pegel[data-an="1"] i { animation: rgp-pegeln 900ms ease-in-out infinite; }
.rgp-pegel i:nth-child(2) { animation-delay: 120ms; }
.rgp-pegel i:nth-child(3) { animation-delay: 240ms; }
.rgp-pegel i:nth-child(4) { animation-delay: 360ms; }
.rgp-pegel i:nth-child(5) { animation-delay: 480ms; }

@keyframes rgp-pegeln {
    0%, 100% { height: 4px; }
    50%      { height: 18px; }
}

/* ── Titel und Interpret ───────────────────────────────────────────────── */

/*
 * Titel und Interpret stehen in einem Kasten mit **fester** Höhe.
 *
 * Martins Abnahme vom 14.09.2026 (Issue #132): „Der eigentliche Player-Inhalt
 * … springt wiederholt vertikal. In einer Frame-Analyse liegt der Versatz der
 * Player-Bedienzone wiederholt bei ungefähr 18 px." Hier war eine der Ursachen:
 * `min-height` ist eine Untergrenze und keine Höhe. Ein einzeiliger Titel
 * blieb bei 62 Punkten, ein zweizeiliger wuchs auf gut 74 – und weil das Cover
 * darüber die freie Zeile des Rasters füllt (`minmax(0, 1fr)`), schrumpfte es
 * um genau diese Differenz und alles darunter rückte nach. Bei jedem
 * Titelwechsel, also im Takt der Musik.
 *
 * Mit fester Höhe passiert nichts mehr: Der Titel ist ohnehin auf zwei Zeilen
 * begrenzt (`-webkit-line-clamp: 2`), der Interpret auf eine – der Kasten ist
 * so hoch wie sein größtmöglicher Inhalt und bleibt es. Der Inhalt steht darin
 * unten, damit ein einzeiliger Titel nicht in der Luft hängt, sondern über dem
 * Interpreten sitzt.
 */
.rgp-titelzeile {
    display: grid;
    align-content: center;
    text-align: center;
    /* Zwei Zeilen Titel (`line-height: 1.25`), drei Punkte Abstand, eine Zeile
       Interpret (`line-height: 1.4`). Gerechnet aus den beiden Schriftgrößen
       und nicht getippt: In vier Formaten stehen dort vier andere Größen, und
       eine fünfte Zahl daneben wäre die, die beim nächsten Mal nicht
       mitwandert. */
    height: calc(2.5 * var(--rgp-titelgroesse) + 3px
                 + 1.4 * var(--rgp-interpretgroesse));
}

.rgp-titel {
    margin: 0;
    font-size: var(--rgp-titelgroesse);
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -0.01em;
    /* Zwei Zeilen, dann Auslassung: Ein dritter Titelumbruch schöbe die
       Bedienung aus dem Bild. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.rgp-interpret {
    margin: 3px 0 0;
    font-size: var(--rgp-interpretgroesse);
    line-height: 1.4;
    color: var(--rgp-gedaempft);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Bedienung ─────────────────────────────────────────────────────────── */

.rgp-bedienung {
    display: grid;
    gap: 10px;
    justify-items: center;
}

/*
 * Die Zustandszeile – **eine** Zeile, immer.
 *
 * `min-height` war hier eine Untergrenze und keine Höhe: „Live" blieb bei 18
 * Punkten, „Verbindung unterbrochen – neuer Versuch in 4 s (2/6)" brach auf
 * einem Telefon um und wurde 36. Die ganze Bedienzone rückte dabei nach, und
 * das Cover darüber schrumpfte mit – einer der Wege, auf denen der Player im
 * Ruhezustand sprang (Martins Abnahme vom 14.09.2026).
 *
 * Also feste Höhe und kein Umbruch. Was nicht hineinpasst, endet mit einer
 * Auslassung; die Meldung ist ohnehin nur so lange da, bis der nächste Versuch
 * anläuft, und dieselbe Auskunft steht als Zahl im Knopf daneben.
 */
.rgp-zustand {
    margin: 0;
    height: 18px;
    max-width: 100%;
    font-size: 12.5px;
    line-height: 18px;
    letter-spacing: 0.03em;
    color: var(--rgp-leise);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rgp-knoepfe {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 26px;
}

.rgp-knopf {
    position: relative;
    display: grid;
    place-items: center;
    border: 0;
    background: transparent;
    color: var(--rgp-text);
    cursor: pointer;
    padding: 0;
}

.rgp-knopf svg { width: 22px; height: 22px; fill: currentColor; display: block; }

.rgp-knopf--klein {
    width: var(--rgp-tippflaeche);
    height: var(--rgp-tippflaeche);
    border-radius: 50%;
    color: var(--rgp-text);
    background: var(--rgp-karte);
    /* Rot umrandet statt weiß umrandet: Die kleinen Knöpfe stehen links und
       rechts vom Play-Knopf und gehören zu derselben Konsole. */
    border: 1px solid var(--rgp-rot-kante);
    transition: color 200ms ease, background 200ms ease, border-color 200ms ease;
}

.rgp-knopf--klein:hover { color: #fff; background: var(--rgp-rot-flaeche); }
.rgp-knopf--klein[aria-expanded="true"],
.rgp-knopf--klein.is-an {
    color: #fff;
    background: var(--rgp-rot);
    border-color: var(--rgp-rot-hell);
}

.rgp-knopf__marke {
    position: absolute;
    right: -2px;
    top: -2px;
    min-width: 20px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--rgp-rot);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 18px;
}

/* Der Play-Knopf. Deutlich größer als die Tippfläche – auf dem Telefon ist er
   das eine Bedienelement, das man ohne Hinsehen trifft. */
.rgp-knopf--spielen {
    width: 78px;
    height: 78px;
    border-radius: 50%;
    background: radial-gradient(120% 120% at 50% 0%,
        var(--rgp-rot-hell), var(--rgp-rot) 48%, var(--rgp-rot-tief));
    box-shadow: 0 12px 34px rgba(218, 0, 0, 0.55),
                0 0 0 4px rgba(218, 0, 0, 0.22);
    color: #fff;
    transition: transform 140ms ease, box-shadow 200ms ease;
}

/* Auf Sendung liegt ein deutlich weiterer roter Hof um den Knopf – er ist das
   eine Bedienelement, das man auf dem Telefon ohne Hinsehen trifft. */
.rgp-body[data-ton="1"] .rgp-knopf--spielen {
    box-shadow: 0 12px 40px rgba(218, 0, 0, 0.7),
                0 0 0 7px rgba(218, 0, 0, 0.3);
}

.rgp-knopf--spielen:active { transform: scale(0.94); }
.rgp-knopf--spielen svg { width: 34px; height: 34px; }
.rgp-knopf--spielen .rgp-knopf__pause { display: none; }
.rgp-knopf--spielen[aria-pressed="true"] .rgp-knopf__spielen { display: none; }
.rgp-knopf--spielen[aria-pressed="true"] .rgp-knopf__pause { display: block; }

/* Der Ladering. Er erscheint zwischen Tippen und erstem Ton – und nur dort. */
.rgp-knopf__laden {
    position: absolute;
    inset: -5px;
    border-radius: 50%;
    border: 2px solid transparent;
    border-top-color: rgba(255, 255, 255, 0.9);
    opacity: 0;
}

.rgp-knopf--spielen[data-laedt="1"] .rgp-knopf__laden {
    opacity: 1;
    animation: rgp-drehen 900ms linear infinite;
}

.rgp-knopf--spielen[data-laedt="1"] .rgp-knopf__spielen,
.rgp-knopf--spielen[data-laedt="1"] .rgp-knopf__pause { opacity: 0.35; }

@keyframes rgp-drehen { to { transform: rotate(360deg); } }

/*
 * Die Zusatzzeile: Lautstärke oder Tastenhinweis, dazu AirPlay.
 *
 * Sie hat seit dem 14.09.2026 eine **feste** Höhe, und zwar die der
 * Tippfläche. Der Grund steht in Martins Befund vom selben Tag: AirPlay
 * meldet sich auf einem iPhone von selbst an und wieder ab – WebKit sucht im
 * Hintergrund nach Zielen im Netz –, und mit ihm erschien und verschwand ein
 * 44 Punkte hoher Knopf in dieser Zeile. Die ganze Bedienzone rückte dabei
 * rhythmisch nach oben und unten, ohne dass jemand etwas angefasst hätte.
 *
 * Der Platz ist deshalb reserviert, sobald überhaupt etwas darin stehen kann.
 * Kann es nichts (kein AirPlay, kein Regler, kein Hinweis – ein Browser am
 * Schreibtisch ohne Lautstärkeanspruch), bleibt die Zeile leer und flach:
 * `:empty` greift nur, wenn wirklich kein Kind sichtbar ist.
 */
.rgp-zusatz {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    min-height: var(--rgp-tippflaeche);
}

/*
 * Und der AirPlay-Knopf selbst behält seinen Platz, auch wenn gerade kein Ziel
 * im Netz ist.
 *
 * `hidden` heißt hier weiterhin „dieses Gerät kann kein AirPlay" – das steht
 * einmal fest, bevor irgendetwas gemessen wird. Ob gerade ein Ziel **da** ist,
 * steht dagegen in `data-da`, und das nimmt dem Knopf nur die Sichtbarkeit,
 * nicht seinen Kasten. So bleibt die Zusage aus Issue #112 („ein AirPlay-Symbol
 * ohne Empfänger wäre Fake-Funktionalität") vollständig erhalten, ohne dass
 * die Bedienzone dabei wandert.
 */
.rgp-knopf[data-da="0"] {
    visibility: hidden;
    pointer-events: none;
}

.rgp-lautstaerke {
    display: flex;
    align-items: center;
    gap: 10px;
    width: min(240px, 70vw);
}

.rgp-lautstaerke__symbol { width: 18px; height: 18px; fill: var(--rgp-leise); flex: none; }

.rgp-lautstaerke input[type="range"] {
    flex: 1 1 auto;
    height: var(--rgp-tippflaeche);
    accent-color: var(--rgp-rot);
    background: transparent;
    cursor: pointer;
}

/*
 * Der Satz, der auf dem iPhone anstelle des Reglers steht.
 *
 * Martins Abnahme vom 12.09.2026, Punkt 4: Dort ließ sich die Lautstärke „nur
 * mit den Hardware-Tasten regeln; der Slider im Player bewirkt nichts". Der
 * Regler ist deshalb weg – und an seiner Stelle steht kein Loch, sondern die
 * Auskunft. Sie ist leise gesetzt: eine Zeile, keine Warnung.
 */
.rgp-tastenhinweis {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    min-height: 28px;
    font-size: 12.5px;
    color: var(--rgp-leise);
}

/* ══════════════════════════════════════════════════════════════════════════
   Guder Draht als Player-Aktion (Issue #113, umgestellt mit #132)
   ══════════════════════════════════════════════════════════════════════════
 *
 * Bis zum 14.09.2026 stand hier ein Balken in der Hausfarbe unter der
 * Bedienung. Martins Festlegung von diesem Tag hat ihn abgeräumt:
 *
 *   „Der aktuelle breite Guder-Draht-Balken unter dem Desktop-Player passt
 *   optisch nicht ins Player-Design und verschwendet Platz. Auf Desktop/Laptop
 *   Guder Draht als kompakte Player-Aktion nahe der Playersteuerung
 *   integrieren, z. B. Sprechblasen-Icon + klarer Status. Kein breiter
 *   dauerhafter Statusstreifen über fast die ganze Breite."
 *
 * Geblieben ist ein Knopf in der Reihe der Playersteuerung – dieselbe Form und
 * dieselbe Größe wie Teilen und Sleep-Timer, damit er dazugehört und nicht
 * daneben steht. Was er über den Zustand sagt, sagt er an seinem Zeichen: ein
 * Punkt in der Hausfarbe, wenn ein Chat läuft, und die Zahl der Leute darin
 * als kleine Marke.
 *
 * **Der Einstieg bleibt sichtbar, auch wenn nichts läuft.** Das ist die
 * Festlegung vom 12.09.2026 und gilt unverändert; ausgegraut heißt dabei
 * wirklich ohne Funktion (`chat-hoerer.js` setzt `disabled`).
 */

/*
 * **Nur am Schreibtisch.** Martins Festlegung nennt ihn ausdrücklich für
 * „Desktop/Laptop", und auf dem Telefon wäre er der zweite Weg zu derselben
 * Fläche: Dort ist die Kachel `Guder Draht` in der Bereichsleiste der
 * Einstieg. Im Querformat käme dazu, dass die Bedienzeile dort 190 Punkte
 * breit ist – ein vierter Knopf liefe über die Kante.
 *
 * Dieselbe Grenze wie für die Leiste (1024 px): Ab dort steht die Navigation
 * im Kopf, und die Bedienzeile hat den Platz.
 */
.rgp-draht { display: none; }

@media (min-width: 1024px) {
    .rgp-draht { display: grid; }
}

.rgp-draht__punkt {
    position: absolute;
    /* Unten rechts und nicht oben: Oben sitzt die Marke mit der Zahl
       (`.rgp-knopf__marke`), und zwei Zeichen auf einem Fleck sind eines zu
       viel. */
    bottom: 5px;
    right: 5px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--rgp-rot);
    box-shadow: 0 0 0 2px rgba(11, 11, 13, 0.9), 0 0 10px rgba(218, 0, 0, 0.9);
    /* Kein Chat, kein Punkt – und zwar wirklich keiner. Ein ausgegrauter Punkt
       sähe aus wie ein ungeklärtes Statussymbol; genau so einen hat Martin am
       14.09.2026 am Studiologo abbestellt. */
    opacity: 0;
    transition: opacity 220ms ease-out;
}

.rgp-body[data-draht="1"] .rgp-draht__punkt { opacity: 1; }

/* Die Zahl der Leute im Chat sitzt an derselben Ecke wie die Marke des
   Sleep-Timers – dieselbe Sprache für dieselbe Sorte Auskunft. */
.rgp-draht__zahl { font-variant-numeric: tabular-nums; }

.rgp-draht:disabled {
    opacity: 0.45;
    cursor: default;
}

@media (prefers-reduced-motion: reduce) {
    .rgp-draht__punkt { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   „Aktuell im Programm" – auf dem Telefon ein Panel von unten
   ══════════════════════════════════════════════════════════════════════════ */

.rgp-plan {
    position: fixed;
    left: 0;
    right: 0;
    /* Über der Bereichsleiste und nicht darunter: Sie ist die untere Kante
       dieser App. Am Schreibtisch ist der Raum null und das Panel steht
       ohnehin als Spalte im Fluss. */
    bottom: var(--rgp-navraum, 0px);
    z-index: 3;
    background: rgba(18, 18, 22, 0.92);
    backdrop-filter: blur(22px);
    -webkit-backdrop-filter: blur(22px);
    /* Die Kante des Panels trägt die Hausfarbe – auf dem Telefon ist sie der
       sichtbarste waagerechte Strich der ganzen Oberfläche. */
    border-top: 2px solid var(--rgp-rot);
    border-radius: 22px 22px 0 0;
    /* Die Safe Area trägt die Bereichsleiste darunter – hier wäre sie
       doppelt. */
    padding-bottom: 0;
    transform: translateY(calc(100% - var(--rgp-griffhoehe, 84px)));
    transition: transform 320ms cubic-bezier(0.32, 0.72, 0, 1);
}

.rgp-plan[data-offen="1"] { transform: translateY(0); }

/*
 * Die Lasche ist ein einziger Knopf über die volle Breite – Issue #129.
 *
 * Nicht der Strich allein: Wer ein Bottom-Sheet aufziehen will, tippt irgendwo
 * auf seinen Kopf, und ein 40 Punkte breites Griffchen als einziges Ziel wäre
 * genau die Bedienung, die Martin auf dem iPhone nicht gefunden hat. `width:
 * 100%` und die 84 Punkte Höhe sind deshalb Absicht und keine Großzügigkeit –
 * sie sind das Tap-Ziel.
 */
.rgp-plan__griff {
    display: grid;
    justify-items: center;
    gap: 4px;
    width: 100%;
    min-height: 84px;
    padding: 10px var(--rgp-rand) 12px;
    border: 0;
    background: transparent;
    color: var(--rgp-text);
    cursor: pointer;
    text-align: center;
}

.rgp-plan__strich {
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: var(--rgp-rot);
}

/* Wort und Chevron gehören zusammen in eine Zeile: Der Pfeil sagt etwas über
   genau diese Beschriftung, nicht über die Zeile mit der Sendung darunter. */
.rgp-plan__zeile {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    max-width: 100%;
}

.rgp-plan__wort {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--rgp-rot-hell);
}

/*
 * Der Zustand als **Form**, nicht als Farbe: eingeklappt zeigt der Chevron
 * nach oben („hier geht es hinauf"), aufgeklappt nach unten („hier geht es
 * wieder zu"). Gedreht wird er von `data-offen` am Panel – derselbe Schalter,
 * der das Panel verschiebt und den `aria-expanded` des Knopfes begleitet. So
 * gibt es genau eine Quelle für den Zustand und keine zweite, die ihr
 * widersprechen könnte.
 */
.rgp-plan__pfeil {
    width: 17px;
    height: 17px;
    fill: var(--rgp-rot-hell);
    flex: none;
    transition: transform 320ms cubic-bezier(0.32, 0.72, 0, 1);
}

.rgp-plan[data-offen="1"] .rgp-plan__pfeil { transform: rotate(180deg); }

.rgp-plan__jetzt {
    font-size: 14px;
    color: var(--rgp-text);
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rgp-plan__inhalt {
    display: grid;
    gap: 12px;
    max-height: min(58dvh, 460px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0 var(--rgp-rand) 18px;
}

.rgp-sendung {
    padding: 13px 15px;
    border-radius: var(--rgp-radius);
    background: var(--rgp-karte);
    border: 1px solid transparent;
}

.rgp-sendung--jetzt {
    background: var(--rgp-rot-flaeche);
    border-color: var(--rgp-rot-kante);
    /* Der rote Balken links: „das läuft gerade" auf einen Blick, ohne dass
       man die Marke darüber lesen muss. */
    border-left: 4px solid var(--rgp-rot);
    padding-left: 12px;
}

.rgp-sendung__marke {
    margin: 0 0 4px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--rgp-leise);
}

.rgp-sendung--jetzt .rgp-sendung__marke { color: var(--rgp-rot-hell); }

.rgp-sendung__titel {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    line-height: 1.3;
}

.rgp-sendung__zeit {
    margin: 3px 0 0;
    font-size: 13px;
    color: var(--rgp-gedaempft);
}

/*
 * Die beiden Marken des Sidebar-Widgets – „Morgen“/„Freitag“ und „Wdh.“.
 *
 * Sie stehen hier, weil der Player seit dem 12.09.2026 dieselben öffentlichen
 * Anzeigeinformationen zeigt wie das Widget auf radio-gude.de. Ohne das
 * Tageskennzeichen wäre „ca. 06:15 Uhr“ am späten Abend irreführend – genau
 * die Begründung, die im Widget steht.
 */
.rgp-marke-tag,
.rgp-marke-wdh {
    display: inline-block;
    margin-right: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--rgp-rot);
    color: #fff;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    vertical-align: 2px;
}

.rgp-marke-wdh {
    margin-right: 0;
    margin-left: 7px;
    background: transparent;
    border: 1px solid var(--rgp-rot-kante);
    color: var(--rgp-rot-hell);
}

.rgp-fortschritt { margin-top: 10px; }

.rgp-fortschritt__bahn {
    height: 4px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.16);
    overflow: hidden;
}

.rgp-fortschritt__balken {
    height: 100%;
    width: 0;
    border-radius: 2px;
    background: var(--rgp-rot-hell);
    transition: width 800ms linear;
}

.rgp-fortschritt__rest {
    margin: 5px 0 0;
    font-size: 12px;
    color: var(--rgp-leise);
}

/*
 * „Zuletzt gespielt" – Martins Abnahme vom 12.09.2026 in drei Punkten.
 *
 * 1. **Kein harter Schnitt.** Die Kacheln trugen `object-fit: cover`; ein
 *    Cover, das nicht genau quadratisch ist, verlor damit an zwei Seiten
 *    Bild – in Martins Bildschirmfoto sichtbar abgeschnitten. `contain` zeigt
 *    es vollständig, und was daneben frei bleibt, ist eine ruhige dunkle
 *    Fläche statt eines beschnittenen Motivs.
 * 2. **Größer.** 48 statt 34 Punkte, auf dem Telefon wie auf dem
 *    Schreibtisch. Die Zeile bleibt dadurch kompakt: Die Kachel ist ohnehin
 *    das höchste Element darin.
 * 3. **Antippbar.** Die Kachel ist ein Knopf und öffnet den Display-Modus mit
 *    genau diesem Titel (`player.js`, `displaymodus()`). 48 Punkte sind
 *    dabei knapp unter der 44er-Regel aus Issue #35 – der Knopf bekommt
 *    deshalb seine Tippfläche über `padding` dazu, ohne dass das Bild wächst.
 */
.rgp-verlauf {
    padding: 13px 15px;
    border-radius: var(--rgp-radius);
    background: var(--rgp-karte);
    border: 1px solid transparent;
    border-top: 2px solid var(--rgp-rot-kante);
    /* Zwei Zeilen: die Marke und die Liste. Die Liste darf schrumpfen – das
       ist die Voraussetzung dafür, dass sie in der stehenden Spalte einen
       eigenen Bildlauf bekommt (siehe die Formate 2, 4 und 5 unten). */
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    min-height: 0;
}

.rgp-verlauf__liste {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 9px;
    align-content: start;
    min-height: 0;
}

.rgp-verlauf__liste li {
    display: grid;
    grid-template-columns: 48px 1fr auto;
    align-items: center;
    gap: 11px;
    font-size: 13.5px;
}

.rgp-verlauf__knopf {
    -webkit-appearance: none;
    appearance: none;
    display: block;
    width: 48px;
    height: 48px;
    padding: 0;
    margin: 0;
    border: 0;
    border-radius: 10px;
    background: none;
    cursor: pointer;
    /* Die Tippfläche wächst über das Bild hinaus, ohne die Zeile zu dehnen –
       so bleibt die 44-px-Regel erfüllt und die Liste trotzdem kompakt. */
    position: relative;
}

.rgp-verlauf__knopf::after {
    content: "";
    position: absolute;
    inset: -3px -4px;
}

.rgp-verlauf__bild {
    display: block;
    width: 48px;
    height: 48px;
    border-radius: 10px;
    /* `contain` und nicht `cover`: siehe Punkt 1 im Kopf dieses Abschnitts. */
    object-fit: contain;
    background: rgba(0, 0, 0, 0.42);
    border: 1px solid var(--rgp-kante);
    transition: transform 160ms ease, border-color 160ms ease;
}

.rgp-verlauf__knopf:hover .rgp-verlauf__bild,
.rgp-verlauf__knopf:focus-visible .rgp-verlauf__bild {
    transform: scale(1.06);
    border-color: var(--rgp-rot-kante);
}

.rgp-verlauf__knopf:focus-visible {
    outline: 2px solid var(--rgp-rot-hell);
    outline-offset: 2px;
}

/*
 * Der eigene Bildlauf der Historie – Martins Abnahme vom 12.09.2026, Punkt 5.
 *
 * „Nur der Bereich `Zuletzt gespielt` soll intern scrollbar sein. `Jetzt on
 * Air`, `Als Nächstes` und `Danach` bleiben oberhalb sichtbar und werden
 * durch das Scrollen der Historie nicht weggeschoben."
 *
 * Bis dahin scrollte die **ganze** Spalte: `.rgp-plan__inhalt` trug den
 * Bildlauf, und darin stehen alle vier Karten. Wer den zehnten Titel sehen
 * wollte, schob damit die laufende Sendung aus dem Bild.
 *
 * Gilt für alle drei Formate mit einer **stehenden** Spalte: Tablet quer,
 * Schreibtisch – und seit Martins Abnahme vom 13.09.2026 auch das Telefon im
 * Querformat. Dort stand am 12.09.2026 noch das Gegenteil: Auf gut 300
 * Punkten Höhe gingen drei Sendungen und eine Liste mit eigenem Bildlauf
 * nicht beide hinein. Das Ergebnis war die Liste, die Martin gesehen hat –
 * angeschnitten an der Bildschirmkante. Die Karten des Sendeplans sind
 * seitdem im Querformat schlanker, und damit passt beides; die Regeln dafür
 * stehen im Abschnitt „Telefon quer" weiter unten.
 *
 * Ein Format bleibt ausdrücklich draußen: **Telefon hochkant** – dort ist der
 * Sendeplan ein Panel, das von unten kommt, und sein Bildlauf ist der, den
 * Martin ausdrücklich als „perfekt" abgenommen hat.
 *
 * Umgesetzt als Flexspalte und nicht über `grid-template-rows`: Die Zahl der
 * Karten hängt am Sendeplan (eine Sendung ohne Nachfolger fehlt, die Historie
 * fehlt, solange sie leer ist), und eine gezählte Zeilenvorgabe ginge bei der
 * ersten Lücke daneben.
 */
@media (min-width: 900px) and (orientation: landscape), (min-width: 1100px) {
    .rgp-plan__inhalt {
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    .rgp-plan__inhalt > .rgp-sendung { flex: 0 0 auto; }

    .rgp-verlauf {
        flex: 1 1 auto;
        min-height: 92px;
        overflow: hidden;
    }

    .rgp-verlauf__liste {
        overflow-y: auto;
        overscroll-behavior: contain;
        /* Platz für die Leiste, damit sie nicht auf der Uhrzeit liegt. */
        padding-right: 6px;
        /* Dezent, aber bedienbar – kein verstecktes Scrollen. */
        scrollbar-width: thin;
        scrollbar-color: var(--rgp-rot-kante) transparent;
    }

    .rgp-verlauf__liste::-webkit-scrollbar { width: 6px; }

    .rgp-verlauf__liste::-webkit-scrollbar-track { background: transparent; }

    .rgp-verlauf__liste::-webkit-scrollbar-thumb {
        border-radius: 999px;
        background: var(--rgp-rot-kante);
    }
}

.rgp-verlauf__text {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rgp-verlauf__text b { font-weight: 600; }
.rgp-verlauf__text span { color: var(--rgp-gedaempft); }
.rgp-verlauf__zeit { font-size: 12px; color: var(--rgp-leise); }

/* ══════════════════════════════════════════════════════════════════════════
   Display-Modus
   ══════════════════════════════════════════════════════════════════════════ */

.rgp-display {
    position: fixed;
    inset: 0;
    z-index: 5;
    background: rgba(6, 6, 8, 0.72);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}

.rgp-display__flaeche {
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 14px;
    width: 100%;
    height: 100%;
    padding:
        calc(var(--rgp-sicher-oben) + 24px)
        calc(var(--rgp-sicher-rechts) + 24px)
        calc(var(--rgp-sicher-unten) + 24px)
        calc(var(--rgp-sicher-links) + 24px);
    border: 0;
    background: transparent;
    color: var(--rgp-text);
    cursor: pointer;
    text-align: center;
}

.rgp-display__cover {
    width: min(72vh, 82vw, 620px);
    height: min(72vh, 82vw, 620px);
    object-fit: cover;
    border-radius: 26px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}

.rgp-body[data-cover="fallback"] .rgp-display__cover {
    object-fit: contain;
    padding: 10%;
    background: rgba(0, 0, 0, 0.4);
}

.rgp-display__titel {
    margin: 4px 0 0;
    font-size: clamp(20px, 3.4vw, 34px);
    font-weight: 700;
    line-height: 1.2;
}

.rgp-display__interpret {
    margin: 0;
    font-size: clamp(15px, 2.2vw, 22px);
    color: var(--rgp-gedaempft);
}

.rgp-live--gross { font-size: 12px; padding: 6px 14px; }

.rgp-display__uhr {
    margin: 6px 0 0;
    font-size: clamp(13px, 1.8vw, 18px);
    font-variant-numeric: tabular-nums;
    color: var(--rgp-leise);
}

/* ══════════════════════════════════════════════════════════════════════════
   Dialog und Meldung – kein alert, kein confirm, kein prompt
   ══════════════════════════════════════════════════════════════════════════ */

.rgp-dialog {
    width: min(360px, calc(100vw - 32px));
    padding: 22px;
    border: 1px solid var(--rgp-kante);
    border-radius: 22px;
    background: #16161a;
    color: var(--rgp-text);
}

.rgp-dialog::backdrop { background: rgba(0, 0, 0, 0.6); }

.rgp-dialog__titel { margin: 0; font-size: 18px; font-weight: 700; }

.rgp-dialog__text {
    margin: 6px 0 16px;
    font-size: 13.5px;
    color: var(--rgp-gedaempft);
}

.rgp-dialog__wahl {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 9px;
}

.rgp-dialog__knopf {
    min-height: var(--rgp-tippflaeche);
    border: 1px solid var(--rgp-kante);
    border-radius: 12px;
    background: var(--rgp-karte);
    color: var(--rgp-text);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.rgp-dialog__knopf.is-an { background: rgba(218, 0, 0, 0.3); border-color: var(--rgp-rot); }

.rgp-dialog__fuss {
    display: flex;
    justify-content: flex-end;
    gap: 9px;
    margin-top: 16px;
}

.rgp-dialog__aus,
.rgp-dialog__abbrechen {
    min-height: var(--rgp-tippflaeche);
    padding: 0 16px;
    border-radius: 12px;
    border: 1px solid var(--rgp-kante);
    background: transparent;
    color: var(--rgp-gedaempft);
    font-size: 14px;
    cursor: pointer;
}

.rgp-dialog__aus { color: var(--rgp-rot-hell); border-color: rgba(218, 0, 0, 0.45); }

.rgp-meldung {
    position: fixed;
    left: 50%;
    bottom: calc(var(--rgp-unterkante) + 104px);
    z-index: 9;
    transform: translateX(-50%);
    margin: 0;
    max-width: calc(100vw - 40px);
    padding: 11px 18px;
    border-radius: 999px;
    background: rgba(28, 28, 32, 0.95);
    border: 1px solid var(--rgp-kante);
    font-size: 13.5px;
    text-align: center;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
}

/* ══════════════════════════════════════════════════════════════════════════
   2) Telefon quer – ein echtes Zweispaltenlayout
   ══════════════════════════════════════════════════════════════════════════
   Nicht die gedrehte Hochkantansicht: Dort bliebe vom Cover ein Streifen
   übrig und die Bedienung stünde unter dem Rand. Links das Cover über die
   volle Höhe, rechts Titel, Bedienung und der Sendeplan als stehende Spalte.
   Das Panel von unten gibt es hier nicht – es verdeckte die halbe Höhe. */

@media (orientation: landscape) and (max-height: 540px) {
    .rgp { --rgp-rand: 14px; }

    .rgp-buehne {
        /* Drei echte Spalten und drei Zeilen. Das Cover steht links über
           beide Inhaltszeilen, in der Mitte Titel und Bedienung
           untereinander, rechts der Sendeplan als stehende Spalte.

           Die beiden Inhaltszeilen sind seit Martins Abnahme vom 12.09.2026
           **gleich** gewichtet (`1fr 1fr` statt `1fr auto`). Vorher nahm die
           obere allen freien Platz, und Titel samt Bedienung standen als
           Block im unteren Drittel – darüber ein handbreites Loch neben dem
           Cover. Jetzt teilen sich beide Zeilen die Höhe, und das Paar sitzt
           dort, wo das Auge es sucht: in der Mitte.

           Die drei Spalten sind seit Martins Abnahme vom 13.09.2026 **Anteile**
           und keine Inhaltsbreiten mehr. Zwei Gründe, und beide waren am
           kleinsten Telefon quer (667 × 375) zu sehen:

           * Die Sendeplanspalte war 190 Punkte breit. Davon blieb für
             „Erfundener Vortitel 11 · Erfundene Vorgruppe 11" so wenig übrig,
             dass „Erfunde…" dastand – eine Liste, die ihre eigenen Inhalte
             nicht mehr lesbar macht, ist kein gestalteter Bereich.
           * Die mittlere Spalte hatte keine Untergrenze. Das Cover nahm als
             `auto`-Spalte seine volle Kantenlänge, und für Titel und
             Bedienung blieben 100 Punkte – bei einem Knopfpaar, das allein
             190 braucht.

           Jetzt hat jede Spalte ihren Anteil und ihre Untergrenze, und das
           Cover richtet sich danach (siehe unten). */
        grid-template-columns:
            minmax(0, 1.18fr) minmax(190px, 0.78fr) minmax(216px, 1fr);
        grid-template-rows: auto minmax(0, 1fr) minmax(0, 1fr);
        grid-template-areas:
            "kopf   kopf       kopf"
            "cover  titel      plan"
            "cover  bedienung  plan";
        column-gap: 16px;
        row-gap: 6px;
        padding-bottom: calc(var(--rgp-sicher-rest) + 10px);
    }

    .rgp-kopf { grid-area: kopf; min-height: 24px; }
    .rgp-cover { grid-area: cover; align-self: stretch; }

    /*
     * Das Cover bleibt der größte Gegenstand des Querformats – und es bleibt
     * vor allem **quadratisch**.
     *
     * Die Grundfassung setzt `height: 100%` und begrenzt die Breite mit
     * `max-width: 100%`. Das geht gut, solange die Spalte breiter ist als die
     * Zeile hoch. Ist sie es nicht – und auf 667 × 375 ist sie es nicht –,
     * bleibt die Höhe stehen und nur die Breite wird gekappt: Aus dem Quadrat
     * wird ein Hochkantstreifen, und das Bild darin verliert links und rechts.
     * Genau die Art Quetschung, die Martin in diesem Format nicht sehen will.
     *
     * Hier gilt deshalb die umgekehrte Richtung: Die Breite entscheidet, die
     * Höhe folgt ihr über `aspect-ratio` aus der Grundfassung. Gedeckelt wird
     * sie von der Höhe der beiden Inhaltszeilen – Fensterhöhe ohne die
     * sichere Fläche, den Rand oben, den Kopf und den Zeilenabstand. Der Wert
     * ist absichtlich eine Spur zu klein gerechnet: Das Quadrat wird dadurch
     * höchstens ein, zwei Punkte kleiner als die Zeile, aber nie höher als
     * sie.
     */
    .rgp-cover__flaeche {
        height: auto;
        max-height: 100%;
        width: min(100%, calc(100dvh - var(--rgp-navraum, 0px)
                              - var(--rgp-sicher-oben)
                              - var(--rgp-sicher-rest) - 60px));
    }
    .rgp-titelzeile {
        grid-area: titel;
        align-self: end;
        text-align: left;
    }
    .rgp-bedienung {
        grid-area: bedienung;
        align-self: start;
        justify-items: start;
        gap: 6px;
        min-height: 0;
    }

    .rgp { --rgp-titelgroesse: 19px; --rgp-interpretgroesse: 14px; }

    .rgp-knoepfe { gap: 20px; }
    .rgp-knopf--spielen { width: 62px; height: 62px; }
    .rgp-knopf--spielen svg { width: 27px; height: 27px; }
    .rgp-lautstaerke { width: min(190px, 28vw); }
    /* Der Regler braucht seine Tippfläche, die Zeile darunter aber nicht die
       volle Höhe eines Knopfes – im Querformat ist jede Zeile knapp. */
    .rgp-lautstaerke input[type="range"] { height: 34px; }

    /* Der Sendeplan ist hier kein Panel mehr, sondern die dritte Spalte –
       offen, ohne Griff, ohne Verschieben. Ein Panel von unten verdeckte im
       Querformat die halbe Höhe. */
    .rgp-plan {
        position: relative;
        grid-area: plan;
        left: auto; right: auto; bottom: auto;
        align-self: stretch;
        width: auto;
        border-radius: var(--rgp-radius);
        border: 1px solid var(--rgp-kante);
        /* Die rote Kante bleibt auch hier: Sie ist in jedem der fünf Formate
           dieselbe Marke und nicht eine Eigenheit des Telefons. */
        border-top: 2px solid var(--rgp-rot);
        transform: none;
        background: rgba(18, 18, 22, 0.78);
        padding-bottom: 0;
        overflow: hidden;
    }

    .rgp-plan__griff { display: none; }

    /*
     * Die Spalte scrollt nicht mehr als Ganzes – Martins Abnahme vom
     * 13.09.2026.
     *
     * Sein Befund: „Der Sendeplan rechts ist gut, die Historie sitzt darunter
     * in einem sehr kleinen Restbereich, dadurch wirkt sie gequetscht /
     * angeschnitten und nicht hochwertig; der erste Titel ist nur noch
     * teilweise sichtbar." Genau das war die Folge des alten Aufbaus: Alle
     * vier Karten standen in einem einzigen Bildlauf, und wo er unten an der
     * Bildschirmkante endete, endete auch die Liste – mitten in einer Zeile.
     *
     * Jetzt gilt hier dasselbe wie am Schreibtisch, nur auf knapper Höhe: Die
     * Spalte ist eine Flexspalte ohne eigenen Bildlauf, die drei Sendungen
     * stehen fest darin, und **nur** „Zuletzt gespielt" bekommt den Rest –
     * als eigene Karte mit eigener Kante, eigenem Bildlauf und einem Ende,
     * das im Bild liegt. Am 12.09.2026 war das hier noch ausdrücklich
     * ausgenommen („auf gut 300 Punkten gehen beide nicht hinein"); das
     * stimmte für die damaligen Karten und stimmt seit ihrer Verschlankung
     * nicht mehr.
     */
    .rgp-plan__inhalt {
        display: flex;
        flex-direction: column;
        max-height: 100%;
        height: 100%;
        overflow: hidden;
        /* Enger als vor dem 15.09.2026 (9 px / 5 px), und das ist kein
           Geschmack: Die Fußleiste steht im Querformat seit Martins Befund
           wieder unten und nimmt der Spalte fünfzig Punkte. Sie kommen hier
           zurück – an Abständen, die niemand zählt, und nicht an den Zeilen
           von „Zuletzt gespielt", die ihr Tippziel von 40 Punkten behalten
           müssen. */
        padding: 7px;
        gap: 4px;
    }

    /* Die drei Sendungen behalten ihre Höhe – sie sind der feste Teil. */
    .rgp-plan__inhalt > .rgp-sendung { flex: 0 0 auto; }

    /* Und sie sind schlanker geworden, damit für die Liste wirklich etwas
       übrig bleibt: **zwei** Zeilen statt dreier. Oben die Marke und – an
       derselben Zeile rechts – der Zeittext, darunter der Titel in einer
       Zeile. Gespart ist damit ein Drittel der Höhe je Karte, ohne dass eine
       Angabe wegfällt. Was nicht hineinpasst, endet in drei Punkten; der
       ganze Sendeplan steht eine Drehung weiter im Hochformat. */
    .rgp-sendung {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-areas:
            "marke zeit"
            "titel titel";
        align-items: baseline;
        column-gap: 8px;
        padding: 4px 10px;
    }
    .rgp-sendung--jetzt { padding-left: 8px; }
    /* Ausdrücklich als Kind der Karte und nicht über die Klasse allein: Die
       Überschrift von „Zuletzt gespielt" trägt dieselbe Klasse, steht aber in
       einer anderen Karte – mit einem `grid-area` aus diesem Aufbau landete
       sie dort in einer Zeile, die es nicht gibt. */
    .rgp-sendung > .rgp-sendung__marke { grid-area: marke; font-size: 9.5px; margin: 0; }
    .rgp-sendung > .rgp-sendung__titel {
        grid-area: titel;
        font-size: 12.5px;
        line-height: 1.3;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .rgp-sendung > .rgp-sendung__zeit {
        grid-area: zeit;
        margin: 0;
        font-size: 10.5px;
        text-align: right;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* Den Fortschrittsbalken gibt es erst mit Issue #70. Er steht dann unter
       beiden Zeilen und nicht neben einer davon. */
    .rgp-sendung > .rgp-fortschritt { grid-column: 1 / -1; margin-top: 6px; }

    /* „Zuletzt gespielt" bekommt den Rest der Spalte. Auf einem iPhone quer
       (390 Punkte hoch) sind das gemessene 103 Punkte Liste, auf dem kleinsten
       (375 Punkte) 88 – in beiden Fällen zwei ganze Zeilen zu 40 Punkten und
       darunter der Anfang der dritten. Abgeschnitten wirkt keine davon, dafür
       sorgt der weiche Abschluss unten.

       Es waren bis zum 15.09.2026 drei ganze Zeilen, und die fünfzig Punkte
       Unterschied sind die Fußleiste: Sie steht seit Martins Querformat-Befund
       auch im Querformat unten und nicht mehr in der Kopfzeile (siehe den
       Block „Die Bereichsleiste"). Zurückgeholt ist der Unterschied, soweit er
       sich holen ließ, an den Abständen dieser Spalte – nicht an der Zeile
       selbst: Ihre 40 Punkte sind das Tippziel des Covers und stehen in
       `tests/browser_player.mjs` als eigene Prüfung (`-25`).

       Die Untergrenze ist dabei bewusst niedrig: Sie muss **irgendeine** Zahl
       sein, weil ein Flexelement sonst nicht unter seinen Inhalt schrumpft
       (zehn Zeilen), und sie darf auf einem sehr flachen Fenster nicht selbst
       zum Überlauf führen. Im Betrieb entscheidet ohnehin `flex: 1 1 auto`. */
    .rgp-verlauf {
        flex: 1 1 auto;
        min-height: 96px;
        overflow: hidden;
        padding: 5px 10px 4px;
    }

    .rgp-verlauf > .rgp-sendung__marke { margin-bottom: 3px; }

    .rgp-verlauf__liste {
        gap: 4px;
        overflow-y: auto;
        overscroll-behavior: contain;
        scroll-snap-type: y proximity;
        padding-right: 6px;
        scrollbar-width: thin;
        scrollbar-color: var(--rgp-rot-kante) transparent;
        /* Der weiche Abschluss: Was unten noch kommt, verläuft, statt
           abgeschnitten zu werden. Eine kurze Liste merkt davon nichts – dort
           ist der untere Rand ohnehin leer.

           Der Fuß darunter gehört dazu: Am Ende des Bildlaufs steht die letzte
           Zeile dadurch **über** dem Verlauf und nicht in ihm. Sonst wäre
           ausgerechnet der letzte Titel der einzige, der halb verblasst
           dasteht – und damit wieder der Eindruck, hier sei etwas
           abgeschnitten. */
        padding-bottom: 10px;
        -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 12px),
                                            transparent);
        mask-image: linear-gradient(to bottom, #000 calc(100% - 12px),
                                    transparent);
    }

    .rgp-verlauf__liste::-webkit-scrollbar { width: 5px; }
    .rgp-verlauf__liste::-webkit-scrollbar-track { background: transparent; }
    .rgp-verlauf__liste::-webkit-scrollbar-thumb {
        border-radius: 999px;
        background: var(--rgp-rot-kante);
    }

    /*
     * Zwei Zeilen je Titel statt einer – der zweite Teil von Martins Befund.
     * In einer Spalte dieser Breite blieb von „Titel · Interpret" der Titel
     * als Wortanfang übrig. Untereinander steht beides ganz da: oben der
     * Titel, darunter der Interpret, rechts daneben die Uhrzeit. Das
     * Trennzeichen entfällt dabei – es gehört in die eine Zeile der anderen
     * Formate, nicht an ein Zeilenende.
     */
    .rgp-verlauf__liste li {
        grid-template-columns: 40px minmax(0, 1fr) auto;
        gap: 10px;
        font-size: 12.5px;
        /* Ein Wischen hält an einer ganzen Zeile an und nicht in ihrer Mitte –
           dieselbe Absicht wie beim weichen Abschluss: Diese Liste soll nie
           aussehen, als sei sie abgeschnitten. */
        scroll-snap-align: start;
    }
    .rgp-verlauf__knopf,
    .rgp-verlauf__bild { width: 40px; height: 40px; }
    .rgp-verlauf__text { white-space: normal; }
    .rgp-verlauf__text b,
    .rgp-verlauf__interpret {
        display: block;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .rgp-verlauf__interpret { font-size: 11px; line-height: 1.3; }
    .rgp-verlauf__trenner { display: none; }
    .rgp-verlauf__zeit { font-size: 11px; align-self: center; }

    .rgp-meldung { bottom: calc(var(--rgp-unterkante) + 16px); }
}

/* ══════════════════════════════════════════════════════════════════════════
   3) Tablet hochkant – großzügige Konsole, Sendeplan steht offen
   ══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 700px) and (orientation: portrait) {
    .rgp { --rgp-rand: 40px; }

    .rgp-buehne {
        grid-template-rows: auto minmax(0, 1fr) auto auto auto;
        gap: 20px;
        max-width: 780px;
        margin: 0 auto;
        /* Der Sendeplan steht hier im Fluss und braucht keinen reservierten
           Platz mehr – er bringt seinen eigenen Abstand mit. */
        padding-bottom: 0;
    }

    /*
     * Auch hier gilt seit dem 17.09.2026 der Deckel in beide Richtungen
     * (Issue #145). Der Grund steht ausführlich im Schreibtischblock weiter
     * unten; die 560 Punkte sind dieselbe Obergrenze wie vorher, sie hängen
     * jetzt nur an der Fläche und nicht mehr am Knopf. Nachgemessen auf dem
     * laufenden Stand: 820 × 1180 ergab 452 × 452 Punkte – richtig –, 820 ×
     * 1600 aber 560 × 872. Ein hohes Tablet ist kein Grund für ein
     * Hochkantcover.
     */
    .rgp-cover {
        align-self: center;
        justify-self: center;
        width: 100%;
        max-width: 560px;
        aspect-ratio: 1 / 1;
        max-height: 100%;
    }

    .rgp-cover__flaeche { max-width: 100%; }
    .rgp { --rgp-titelgroesse: 30px; --rgp-interpretgroesse: 18px; }
    .rgp-knopf--spielen { width: 92px; height: 92px; }
    .rgp-knopf--spielen svg { width: 40px; height: 40px; }
    .rgp-knoepfe { gap: 40px; }

    /* Das Panel bleibt ein Panel, steht aber von Anfang an offen: Auf einem
       Tablet ist genug Höhe da, und ein Griff, den niemand zieht, ist ein
       Bedienelement ohne Aufgabe. */
    .rgp-plan {
        position: relative;
        transform: none;
        border-radius: var(--rgp-radius);
        border: 1px solid var(--rgp-kante);
        /* Die rote Kante bleibt auch hier: Sie ist in jedem der fünf Formate
           dieselbe Marke und nicht eine Eigenheit des Telefons. */
        border-top: 2px solid var(--rgp-rot);
        background: rgba(18, 18, 22, 0.7);
        margin: 0 auto;
        width: 100%;
        max-width: 780px;
        padding-bottom: 0;
        margin-bottom: calc(var(--rgp-sicher-rest) + 18px);
    }

    .rgp-plan__griff { display: none; }

    .rgp-plan__inhalt {
        grid-template-columns: 1fr 1fr;
        max-height: 240px;
        padding: 16px;
    }

    .rgp-sendung--jetzt { grid-column: 1 / -1; }
    .rgp-verlauf { grid-column: 1 / -1; }
}

/* ══════════════════════════════════════════════════════════════════════════
   4) Tablet quer und 5) Schreibtisch – die Radio-Konsole in zwei Spalten
   ══════════════════════════════════════════════════════════════════════════
   `min-height: 541px` seit dem 15.09.2026, und die Zahl ist genau die
   Gegenseite von „Telefon quer" weiter oben (`max-height: 540px`).

   Ohne sie fiel ein großes Telefon im Querformat in **dieses** Layout: Ein
   iPhone Pro Max ist quer 932 Punkte breit und damit nach der alten Bedingung
   ein „Tablet quer" – bei 430 Punkten Höhe. In einer Spalte stehen hier Kopf,
   Cover, Titel und Bedienung untereinander, und für das Cover blieb die Zeile
   `1fr` dazwischen: 132 Punkte, solange die Fußleiste oben in der Kopfzeile
   stand, und **null**, seit sie wieder unten steht. Ein Cover ohne Höhe ist
   kein knappes Cover, sondern keines.

   Die richtige Antwort darauf ist nicht, hier ein paar Punkte zu sparen,
   sondern das Format zu nennen, was es ist: Ein 430 Punkte hohes Fenster ist
   ein Telefon quer, gleich wie breit es ist. Dort gilt das Dreispaltenlayout
   von oben, in dem das Cover seine Höhe aus der Breite bekommt.

   Die zweite Bedingung (`min-width: 1100px`) bleibt ohne Höhengrenze: Sie ist
   der Schreibtisch, und ein 1100 Punkte breites Fenster im Hochformat hat
   Höhe im Überfluss.
   ══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 900px) and (orientation: landscape) and (min-height: 541px),
       (min-width: 1100px) {
    .rgp { --rgp-rand: 40px; }

    .rgp-buehne {
        grid-template-columns: minmax(0, 1.05fr) minmax(320px, 0.95fr);
        grid-template-rows: auto minmax(0, 1fr) auto auto;
        grid-template-areas:
            "kopf       kopf"
            "cover      plan"
            "titel      plan"
            "bedienung  plan";
        column-gap: 44px;
        row-gap: 16px;
        max-width: 1400px;
        margin: 0 auto;
        padding-bottom: calc(var(--rgp-sicher-rest) + 28px);
    }

    .rgp-kopf { grid-area: kopf; min-height: 40px; }
    .rgp-cover { grid-area: cover; }
    .rgp-titelzeile { grid-area: titel; text-align: left; }
    .rgp-bedienung { grid-area: bedienung; justify-items: start; gap: 14px; }

    .rgp-marke { font-size: 17px; }
    .rgp-marke__signet { width: 34px; height: 34px; }

    /*
     * Das Cover bleibt hier ein Quadrat – in **jeder** Fensterhöhe.
     *
     * Martins Befund vom 16.09.2026 (Issue #145): Auf einem sehr großen
     * Browserfenster stand auf `live.radio-gude.de/player` kein Quadrat mehr,
     * sondern ein Hochkantrechteck; erst wer das Fenster niedriger zog, sah
     * wieder ein Cover. Nachgemessen auf dem laufenden Stand: 1920 × 1080
     * ergab 641 × 641 Punkte, 1920 × 1440 aber 670 × 1001 und 1600 × 2000
     * sogar 670 × 1561.
     *
     * Die Ursache ist dieselbe wie beim Telefon quer weiter oben, nur
     * andersherum: Die Grundfassung setzt `height: 100%` und begrenzt allein
     * die Breite (`max-width: 100%`). Die Höhe kommt damit aus der freien
     * Zeile des Rasters (`minmax(0, 1fr)`), die Breite aus der Spalte – und
     * sobald die Zeile höher wird als die Spalte breit ist, kappt nur die
     * Breite. Aus dem Quadrat wird ein Streifen. Am Schreibtisch tritt das
     * ein, sobald das Fenster hoch genug ist: Die Bühne ist auf 1400 Punkte
     * begrenzt, die Spalte hört also bei rund 670 Punkten auf zu wachsen, die
     * Zeile wächst mit dem Fenster weiter.
     *
     * Deshalb wird hier **beides** gedeckelt, und zwar an zwei Stellen:
     *
     *   * Die Coverfläche des Rasters (`.rgp-cover`) nimmt die Breite ihrer
     *     Spalte, leitet daraus über `aspect-ratio` ihre Höhe ab und wird von
     *     der Höhe ihrer Zeile gedeckelt (`max-height: 100%`). Ihre Höhe ist
     *     damit immer der **kleinere** der beiden Werte.
     *   * Der Knopf darin nimmt genau diese Höhe und daraus wieder seine
     *     Breite. Er kann also nicht höher werden als die Zeile und nicht
     *     breiter als die Spalte – keine der beiden Richtungen zwingt die
     *     andere in ein Rechteck.
     *
     * `align-self: center` gehört dazu: Ohne die Angabe zöge das Raster die
     * Fläche auf die volle Zeilenhöhe (`stretch`), und eine gesetzte Höhe
     * schlägt jedes Seitenverhältnis. Zusätzliche Fensterhöhe wird damit zu
     * Freiraum über und unter dem Cover – genau das, was der Auftrag verlangt:
     * mehr Luft, aber kein aufgeblasenes Cover.
     *
     * Die drei Zeilen am Knopf setzen die Grundfassung ausdrücklich noch
     * einmal: In einem breiten, aber sehr **niedrigen** Fenster (etwa
     * 1200 × 500) gilt zusätzlich der Block „Telefon quer" von oben, und
     * dessen `width: min(100%, …)` rechnet mit dessen drei Zeilen. Hier ist
     * die Höhe das Maß.
     */
    .rgp-cover {
        align-self: center;
        width: 100%;
        max-width: 100%;
        aspect-ratio: 1 / 1;
        max-height: 100%;
    }

    .rgp-cover__flaeche {
        height: 100%;
        width: auto;
        max-width: 100%;
    }

    .rgp {
        --rgp-titelgroesse: clamp(26px, 2.4vw, 38px);
        --rgp-interpretgroesse: clamp(16px, 1.3vw, 20px);
    }

    .rgp-knoepfe { gap: 34px; }
    .rgp-knopf--spielen { width: 84px; height: 84px; }
    .rgp-knopf--spielen svg { width: 36px; height: 36px; }
    .rgp-zusatz { justify-content: flex-start; }

    /* Der Sendeplan ist hier eine stehende Spalte und kein Panel. */
    .rgp-plan {
        position: relative;
        grid-area: plan;
        transform: none;
        align-self: stretch;
        border: 1px solid var(--rgp-kante);
        border-top: 2px solid var(--rgp-rot);
        border-radius: var(--rgp-radius);
        background: rgba(18, 18, 22, 0.66);
        padding-bottom: 0;
        overflow: hidden;
    }

    .rgp-plan__griff { display: none; }

    .rgp-plan__inhalt {
        max-height: 100%;
        height: 100%;
        padding: 18px;
        gap: 13px;
        align-content: start;
    }

    .rgp-meldung { bottom: calc(var(--rgp-unterkante) + 28px); }
}

@media (min-width: 1400px) {
    .rgp-plan__inhalt { padding: 24px; gap: 16px; }
    .rgp-sendung { padding: 16px 18px; }
    .rgp-sendung__titel { font-size: 18px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Die Fehlerseite dieses Hauses
   ══════════════════════════════════════════════════════════════════════════ */

.rgp-buehne--fehler {
    display: grid;
    place-items: center;
    grid-template-rows: none;
    padding: var(--rgp-rand);
}

.rgp-fehler {
    display: grid;
    justify-items: center;
    gap: 10px;
    max-width: 420px;
    text-align: center;
}

.rgp-fehler__signet { width: 64px; height: 64px; border-radius: 16px; }
.rgp-fehler__titel { margin: 8px 0 0; font-size: 22px; font-weight: 700; }
.rgp-fehler__text { margin: 0; color: var(--rgp-gedaempft); font-size: 15px; }

.rgp-fehler__weg {
    margin-top: 10px;
    min-height: var(--rgp-tippflaeche);
    display: inline-flex;
    align-items: center;
    padding: 0 22px;
    border-radius: 999px;
    background: var(--rgp-rot);
    color: #fff;
    font-weight: 600;
    text-decoration: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   Rücksicht
   ══════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
    .rgp-hintergrund__ebene,
    .rgp-plan,
    .rgp-plan__pfeil,
    .rgp-cover__bild,
    .rgp-fortschritt__balken { transition: none; }

    .rgp-pegel[data-an="1"] i,
    .rgp-knopf--spielen[data-laedt="1"] .rgp-knopf__laden { animation: none; }
}

/* Ein sichtbarer Fokus. Er ist in einer App nicht weniger wichtig als in
   einem Formular – hier wird mit der Tastatur gespielt und angehalten. */
.rgp-body :focus-visible {
    outline: 2px solid var(--rgp-rot-hell);
    outline-offset: 3px;
    border-radius: 8px;
}

/* ══════════════════════════════════════════════════════════════════════════
   Guder Draht im Player: die Bereichsleiste und das Blatt (Issue #132)
   ══════════════════════════════════════════════════════════════════════════ */
/*
 * Die Chatfläche bringt ihr eigenes Stylesheet mit (`chat.css`) – sie steckt
 * wörtlich genauso auf `draht.radio-gude.de` und im Rahmen auf radio-gude.de,
 * und dort gibt es diese Datei nicht. Was hier steht, ist ausschließlich ihre
 * **Einordnung** in den Player.
 *
 * Der breite Aufrufbalken ist seit Martins Festlegung vom 14.09.2026 weg
 * („Kein breiter dauerhafter Statusstreifen über fast die ganze Breite"), und
 * damit auch aus der Bühne: `#rgc` steht seitdem außerhalb von
 * `.rgp-buehne` (`app/templates/player.html`) und enthält nur noch das Blatt,
 * das ohnehin fest positioniert ist. Es kann die Bühne damit nicht mehr
 * bewegen – das war eine der Stellen, an denen der ruhende Player seine Höhe
 * änderte.
 */
.rgp-body .rgc-cta { display: none; }

/*
 * ── Die Bereichsleiste ─────────────────────────────────────────────────────
 *
 * Dieselbe Leiste wie auf `/draht`, aus derselben Vorlage und mit demselben
 * Stylesheet (`chat.css`, Block `.rgd-tabs`). Seit Issue #133 trägt sie fünf
 * Punkte auf dem Telefon und vier am Schreibtisch; welche das sind und in
 * welcher Reihenfolge, steht dort. Hier steht nur, **wo** sie im Player
 * liegt:
 *
 *   * Telefon hochkant, Telefon quer und Tablet: fest am unteren Rand, wie in
 *     einer App. Sie liegt über dem Programmpanel und unter dem Display-Modus
 *     – dieselbe Ordnung wie überall in dieser Datei.
 *   * Ab Laptopbreite: dort, wo sie im Dokument steht – rechts in der
 *     Kopfzeile, „an exakt derselben Position und im selben Design" wie auf
 *     `/draht`.
 *
 * Das Umschalten macht ausschließlich die Positionierung. Ein zweiter Satz
 * Kacheln für das zweite Format wäre die Doppelpflege, die die gemeinsame
 * Vorlage gerade vermeidet.
 */
/*
 * Der Platz, den die Leiste unten belegt – **einmal** gerechnet und viermal
 * gebraucht: von der Bühne, vom Programmpanel, vom Chatblatt und von der
 * Meldezeile. Am Schreibtisch steht sie in der Kopfzeile und belegt unten
 * nichts; dann ist dieser Raum null, und alle vier rechnen wieder wie vorher.
 *
 * `--rgp-sicher-rest` ist die Safe Area, die danach **noch übrig** ist. Sie
 * wird gebraucht, weil die Bühne ihre Höhe bereits um den Raum der Leiste
 * kürzt: Steht die Leiste unten, trägt sie die Safe Area schon; steht sie im
 * Kopf, muss die Bühne sie selbst freihalten. Ein zweites Mal gerechnet wäre
 * sie ein Streifen Luft unter dem Play-Knopf, und vergessen ein Bedienelement
 * unter der Home-Anzeige des iPhones.
 */
.rgp-body {
    --rgp-navhoehe: 60px;
    --rgp-navraum: calc(var(--rgp-navhoehe) + var(--rgp-sicher-unten));
    --rgp-sicher-rest: max(0px, calc(var(--rgp-sicher-unten) - var(--rgp-navraum)));
    /* Wo für ein fest positioniertes Stück (die Meldezeile) die Unterkante der
       App liegt: über der Leiste, sonst über der Safe Area. */
    --rgp-unterkante: max(var(--rgp-navraum), var(--rgp-sicher-unten));
}

.rgp-tabs {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* Über dem Programmpanel (3) und unter dem Display-Modus (5): Wer das
       Cover groß macht, will es ganz sehen und nicht mit einer Navigation
       darüber. */
    z-index: 4;
}

/*
 * ── Die Leiste hat in der App genau zwei Höhen ──────────────────────────────
 *
 * Und das ist keine Kosmetik, sondern die Bedingung dafür, dass `--rgp-navhoehe`
 * oben überhaupt stimmen darf: Die Zahl ist die Rechnung, mit der die Bühne,
 * das Blatt und die Meldezeile ihre Unterkante finden. Weicht die wirkliche
 * Höhe von ihr ab, liegt entweder ein Bedienelement unter dem Balken oder ein
 * Streifen Luft über ihm – sichtbar wird beides erst auf einem Gerät.
 *
 * `chat.css` kennt drei Höhen, weil es dieselbe Leiste auch auf der
 * eigenständigen Hörerseite zeichnet: 52 Punkte je Kachel, 42 im Querformat
 * (Zeichen und Wort nebeneinander) und 56 ab 820 px, wo die Seite ein Tablet
 * vermutet. In der App-Schale bleiben davon zwei:
 *
 *   * **hochkant 52** – die Daumenzone, in jeder Breite dieselbe. Ein iPhone
 *     quer ist 844 Punkte breit und damit nach der 820er-Regel ein „Tablet";
 *     die dritte Höhe wäre hier also keine Tabletgröße, sondern ein Zufall der
 *     Gerätebreite.
 *   * **quer 42** – dort ist Höhe das knappe Gut. Die Bedingung ist wörtlich
 *     die aus `chat.css`; zwei Grenzen für dieselbe Umstellung wären ein
 *     Fensterausschnitt, in dem die Leiste schon flach ist und die Bühne noch
 *     mit der hohen rechnet.
 *
 * Zweimal vier Punkte Innenabstand der Leiste kommen dazu – 60 und 50, genau
 * die beiden Zahlen von `--rgp-navhoehe`.
 *
 * Aus demselben Block stammt die Breitenbegrenzung auf 820 Punkte: Auf der
 * Hörerseite ist sie die Lesespalte, unter der die Leiste bündig endet. In der
 * App ist die Leiste die **Unterkante des Fensters**; mittig gesetzt stünde ein
 * dunkler Balken mit zwölf Punkten Hintergrund links und rechts daneben.
 */
.rgp-body .rgp-tabs {
    max-width: none;
    margin: 0;
}

.rgp-body .rgp-tabs .rgd-tab { min-height: 52px; }

@media (orientation: landscape) and (max-height: 500px) {
    .rgp-body { --rgp-navhoehe: 50px; }
    .rgp-body .rgp-tabs .rgd-tab { min-height: 42px; }
}

/*
 * Die **eine** Lage, in der die Leiste nicht unten liegt: ab Laptopbreite.
 * Dort ist sie eine Bereichsnavigation in der Kopfzeile, „an exakt derselben
 * Position und im selben Design" wie auf `/draht`.
 *
 * ── Warum das Querformat des Telefons hier nicht mehr steht ─────────────────
 *
 * Bis zum 15.09.2026 galt dieselbe Regel auch für `(orientation: landscape)
 * and (max-height: 540px)`, und zwar mit einem Argument, das stimmt: Im
 * Querformat ist Höhe die knappe Größe, und eine Leiste am unteren Rand nimmt
 * sechzig Punkte von dreihundertneunzig.
 *
 * Nur ging die Rechnung in der Breite nicht auf. In der Kopfzeile stehen neben
 * der Leiste die Marke und die LIVE-Anzeige; für die fünf Punkte blieben auf
 * einem iPhone quer nach Abzug der seitlichen Aussparungen rund fünfhundert
 * Punkte, gebraucht hätten sie siebenhundert. Die Kacheln schrumpfen dabei
 * nicht – sie haben ihr Wort in einer Zeile und `flex: 0 0 auto` –, und weil
 * die Leiste ihre Einträge rechtsbündig setzt, tritt der Überlauf eines
 * Flexkastens **nach links** aus. Genau das hat Martin am 15.09.2026 gemeldet:
 * „In der Kopf-/Navigationszone überlagern sich links `Radio GUDE`,
 * `Webplayer` und der `LIVE`-Status deutlich." Gemessen lag die Kachel
 * `Webplayer` bei 112–254 px, die Marke bei 14–130 px und die LIVE-Anzeige bei
 * 142–214 px – drei Dinge übereinander, und kein waagerechter Bildlauf, an dem
 * die Prüfung es gemerkt hätte.
 *
 * Deshalb bleibt die Leiste im Querformat da, wo sie auf dem Telefon hingehört
 * – unten. Das ist zugleich das, was der Auftrag wörtlich verlangt: „Footer
 * auf iPhone-PWA/Standalone, Safari, Android/Chrome sowie Hoch-/Querformat
 * identisch/stabil; Safe-Area korrekt." Bezahlt wird das mit fünfzig Punkten
 * Höhe – nicht sechzig: Die Leiste ist im Querformat flacher (Zeichen und Wort
 * nebeneinander, 42 statt 52 Punkte Kachelhöhe, siehe oben). Die Bühne rechnet
 * diesen Raum über `--rgp-navraum` ohnehin heraus, das Cover richtet sich in
 * dieser Lage nach der Breite, und was der Sendeplanspalte fehlt, holt sie
 * sich an ihren Abständen zurück.
 *
 * ── Warum hier überall `.rgp-body` davorsteht ───────────────────────────────
 *
 * Die Leiste trägt beide Klassen: `.rgd-tabs` aus `chat.css` und `.rgp-tabs`
 * aus dieser Datei. Beide wiegen gleich viel – und `chat.css` wird in
 * `player.html` **nach** `player.css` geladen. Bei Gleichstand gewinnt damit
 * die Fußleistenform aus `chat.css`: dunkler Balken, Raster mit vier gleich
 * breiten Spalten, eigener Innenabstand.
 *
 * Am Schreibtisch fiel das nicht auf, weil `chat.css` ab 1024 px dieselbe
 * Umstellung selbst noch einmal vornimmt – dort sind beide Dateien einig. Die
 * Angabe steht trotzdem vollständig hier, einschließlich `display`: `.rgp-body`
 * davor wiegt eine Klasse mehr und entscheidet ohne Rücksicht auf die
 * Ladereihenfolge. Eine Regel, die sich darauf verlässt, dass eine andere Datei
 * den Rest erledigt, ist genau die, die im nächsten Format fehlt.
 */
@media (min-width: 1024px) {
    .rgp-body { --rgp-navraum: 0px; }

    .rgp-body .rgp-tabs {
        position: static;
        /* Kein Raster mit gleich breiten Spalten mehr, sondern eine Reihe, die
           nur so breit ist wie ihre Einträge. */
        display: flex;
        justify-content: flex-end;
        align-items: center;
        gap: 4px;
        width: auto;
        max-width: none;
        /* Dieselben Werte, mit denen `chat.css` die Leiste ab 1024 px in die
           Kopfzeile setzt – damit beide Oberflächen sie wirklich gleich
           zeichnen und nicht nur beinahe. */
        padding: 0 calc(var(--rgc-rand) + var(--rgd-sicher-rechts)) 0 0;
        border-top: 0;
        border-bottom: 1px solid var(--rgc-kante);
        background: transparent;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        /* Rechts in der Kopfzeile – zwischen Marke und LIVE-Marke bleibt der
           Platz, den `justify-content: space-between` ohnehin verteilt. */
        margin: 0 0 0 6px;
    }

    /* Aus der Kachel wird ein Eintrag einer Navigation: Zeichen und Wort
       nebeneinander, in Lesegröße, mit Tippziel. Wörtlich dieselben Werte wie
       auf `/draht` ab 1024 px (`chat.css`) – sie stehen hier noch einmal, weil
       dieselbe Leiste dort in einem Raster und hier in einem Flexkasten
       steckt. */
    .rgp-body .rgp-tabs .rgd-tab {
        flex: 0 0 auto;
        flex-direction: row;
        gap: 8px;
        min-height: 44px;
        padding: 8px 14px;
        font-size: 0.875rem;
    }

    /* Das Wort bekommt seinen Platz zurück: In der Fußleiste ist es auf die
       Kachelbreite gekürzt, in der Kopfzeile steht es ganz da. */
    .rgp-body .rgp-tabs .rgd-tab span {
        max-width: none;
        overflow: visible;
        text-overflow: clip;
        white-space: nowrap;
    }

    .rgp-body .rgp-tabs .rgd-tab.is-aktiv {
        border-radius: 999px;
        background: rgba(218, 0, 0, 0.16);
    }
}

/*
 * Das Blatt endet über der Bereichsleiste – sie bleibt sichtbar und
 * bedienbar. Wer den Chat aufgezogen hat, muss mit **einem** Griff zurück zum
 * Player kommen; das ist der halbe Sinn der gemeinsamen Leiste.
 *
 * Ab Tabletbreite ist das Blatt eine Spalte am rechten Rand (`chat.css`) und
 * überlagert dort die Programm-/Historienfläche – genau das verlangt Martins
 * Festlegung vom 14.09.2026: „Programm-/Historienfläche sinnvoll
 * nutzen/überlagern, ohne den Player zu zerlegen." Der Player bleibt links
 * vollständig stehen, und der Ton läuft weiter: Es wird nichts geladen und
 * nichts ausgetauscht, nur ein Blatt aufgezogen.
 */
.rgp-body .rgc {
    /* Genau diese Höhe bleibt unten frei – `chat.css` rechnet damit für
       `bottom` **und** für die Höhe des Blattes. Seit es fast den ganzen
       Bildschirm füllt (Martins Abnahme vom 15.09.2026), muss beides aus
       derselben Zahl kommen; sonst stünde sein Kopf über dem Fensterrand. */
    --rgc-blatt-unten: var(--rgp-navraum, 0px);
}

.rgp-body .rgc-blatt {
    /* Die Safe Area trägt schon die Leiste darunter; ein zweites Mal wäre ein
       Streifen Luft, den niemand bestellt hat. */
    padding-bottom: 6px;
}

@media (min-width: 820px) {
    /* Als rechte Spalte reicht das Blatt von oben bis zur Leiste. `height:
       auto` statt `100dvh`: Mit fester Höhe **und** einem Abstand nach unten
       stünde sein Kopf über dem Fensterrand. */
    .rgp-body .rgc-blatt { height: auto; }
}

/*
 * ── Der Schreibmodus (Issue #171) ──────────────────────────────────────────
 *
 * Unter `live.radio-gude.de` ist Guder Draht ein **Bereich** dieser App, und
 * die Bereichsleiste steht auf dem Telefon am unteren Rand. Sobald die
 * Bildschirmtastatur aufgeht, ist sie genau dort im Weg: sechzig Punkte
 * zwischen Eingabezeile und Tastatur, für eine Navigation, die niemand
 * braucht, solange er einen Satz tippt. Martins mobiler Praxistest vom
 * 22.09.2026 nennt beides – „viel ungenutzte vertikale Fläche" und „die untere
 * Hauptnavigation beansprucht im aktiven Schreibmodus Platz".
 *
 * Also geht sie, und zwar vollständig: `--rgp-navraum` ist der Raum, den sie
 * unten belegt, und er wird von der Bühne, vom Programmpanel, vom Chatblatt
 * und von der Meldezeile gebraucht. Die Leiste verschwinden zu lassen, ohne
 * diese Zahl mitzunehmen, hinterließe genau den leeren Streifen, um den es
 * geht. Eine Zahl, vier Nutzer – das ist der Grund, warum sie eine Variable
 * ist.
 *
 * Wann der Zustand gilt, entscheidet `static/chat-hoerer.js` und sonst
 * niemand: Er steht als `data-schreibt="1"` am `<html>` und wird nur auf
 * Telefonbreiten gesetzt. Die Leiste ist mit dem Schließen der Tastatur ohne
 * Neuaufbau wieder da – sie war nie fort, sie war ungezeichnet.
 */
html[data-schreibt="1"] .rgp-body { --rgp-navraum: 0px; }
html[data-schreibt="1"] .rgp-body .rgp-tabs { display: none; }
