/* ── Die Farben: eine Quelle, zwei Modi (Issue #65) ───────────────────────
 *
 * Jede Farbe dieser Oberfläche steht **hier** und nirgendwo sonst. Weiter unten
 * gibt es keinen festen Farbwert mehr – nur noch `var(--…)`. Das ist die
 * Bedingung dafür, dass ein zweiter Modus überhaupt möglich ist: Wären die
 * Werte über 5000 Zeilen verstreut, bräuchte jede Regel eine zweite Fassung,
 * und die erste Regel ohne zweite wäre der helle Fremdkörper im dunklen Bild.
 *
 * Die Namen sagen, **wozu** eine Farbe da ist, nicht wie sie aussieht:
 * `--flaeche-karte` und nicht `--weiss`. Nur so kann derselbe Name im Dunkeln
 * etwas anderes bedeuten, ohne zu lügen.
 *
 * **Keine Invertierung.** Der dunkle Modus ist kein umgedrehter heller: Die
 * Flächen sind gestuft (Seite dunkler als Karte, Karte dunkler als Eingabefeld),
 * damit die Hierarchie erhalten bleibt, und nirgends steht reines Schwarz.
 * Umgekehrt werden Signalfarben im Dunkeln aufgehellt statt abgedunkelt – ein
 * Rot, das auf Weiß gut liest, verschwindet auf Dunkelgrau.
 *
 * **Was der helle Modus war, bleibt er.** Die Werte unter `:root` sind exakt
 * die, die vorher im Stylesheet standen. Zusammengelegt wurde nur, was sich
 * nicht unterscheiden ließ – etwa fünf fast gleiche Weißtöne für dieselbe
 * zurückgenommene Fläche.
 *
 * **Umgeschaltet wird nichts von Hand.** Es gibt keinen Schalter und keine
 * Einstellung; es gilt, was das Gerät sagt (`prefers-color-scheme`). Ein
 * Schalter wäre ein zweiter Zustand, den man speichern, übertragen und
 * beantworten müsste – der Auftrag verlangt ihn ausdrücklich nicht.
 *
 * `color-scheme` steht dabei nicht zur Zierde: Es sagt dem Browser, in welchem
 * Modus er seine **eigenen** Teile zeichnen soll – Scrollbalken, Datumswähler,
 * die aufgeklappte Liste eines `<select>`, den Hintergrund eines `<dialog>`.
 * Ohne diese eine Zeile bliebe genau das hell und stünde weiß im dunklen Bild.
 */
:root {
    color-scheme: light;

    /* Flächen, von der Seite nach innen gestuft */
    --flaeche-seite: #f4f5f7;
    --flaeche-karte: #fff;
    --flaeche-still: #fafbff;          /* zurückgenommen: Kind, intern, inaktiv */
    --flaeche-zart: #f8f9ff;           /* Hover, Hinweiskasten, Tagesspalte */
    --flaeche-sanft: #f3f4f6;          /* Merkmal, Badge, gesperrtes Feld */
    --flaeche-gewaehlt: #eef0ff;       /* ausgewählte Option */
    --flaeche-neutral: #e5e7eb;        /* neutrale Schaltfläche */
    --flaeche-neutral-stark: #d1d5db;  /* dieselbe beim Überfahren */
    --flaeche-eingabe: #fff;           /* Eingabefelder */
    --flaeche-gesperrt: #f3f4f6;       /* deaktivierte und schreibgeschützte */
    --flaeche-bild: #eef0f4;           /* Platzhalterfläche hinter Porträts */

    /* Text, von stark nach still */
    --text-stark: #1a1a2e;
    --text-lesetext: #1f2937;          /* Fließtext des Handbuchs */
    --text-normal: #374151;
    --text-mittel: #4b5563;
    --text-leise: #6b7280;
    --text-still: #9ca3af;
    --text-platzhalter: #9ca3af;       /* Vorbelegung in einem leeren Feld */
    --platzhalter-text: #b6bcc8;       /* Initialen statt Porträt */

    /* Rahmen und Trenner */
    --rand: #e5e7eb;
    --rand-stark: #d1d5db;
    --rand-sanft: #d7dbe3;
    --rand-zart: #f0f0f4;
    --rand-still: #9ca3af;
    --rand-akzent: #c7cbf5;

    /* Der Kopfbereich – in beiden Modi dunkel, deshalb eigene Namen */
    --kopf-flaeche: #1a1a2e;
    --kopf-text: #a8b2d8;
    --kopf-text-hell: #e8ecf8;
    --kopf-akzent: #e63946;

    /* Gefüllte Flächen: primäre Knöpfe, aktive Schalter, Tabellenkopf */
    --fuellung: #1a1a2e;
    --fuellung-text: #fff;
    --fuellung-text-leise: #c7cbf5;
    /*
     * Die leise Zusatzzeile in einem Spaltenkopf. Sie braucht ein eigenes
     * Token: `--text-still` liest sich auf Weiß und auf dem tiefdunklen
     * Kopf des hellen Modus, aber nicht mehr auf der aufgehellten Füllung
     * des dunklen – dort kam sie auf 2,8:1 statt der 5,6:1, die sie im
     * hellen Modus hat. Im Browser gemessen (`tests/bildbeleg_dunkelmodus`).
     */
    --fuellung-text-still: #9ca3af;

    /* Zustände: Fokus, Auswahl, Bedienfarbe */
    --kontur: #1a1a2e;
    --akzent: #e63946;                 /* Fläche und Kante der Marke */
    --akzent-text: #e63946;            /* dieselbe Marke als Schrift */
    --verweis: #1d4ed8;                /* Verweise im Fließtext */

    /* Erfolg */
    --erfolg-flaeche: #dcfce7;
    --erfolg-rand: #86efac;
    --erfolg-text: #166534;
    --erfolg-kraeftig: #16a34a;
    --erfolg-leise: #4d7c5f;
    --erfolg-zart-flaeche: #ecfdf5;
    --erfolg-zart-rand: #6ee7b7;
    --erfolg-zart-text: #047857;
    --erfolg-zart-kante: #059669;

    /* Fehler und Gefahr */
    --fehler-flaeche: #fee2e2;
    --fehler-flaeche-zart: #fdecec;
    --fehler-flaeche-stark: #fca5a5;
    --fehler-rand: #fca5a5;
    --fehler-text: #b91c1c;
    --fehler-kraeftig: #dc2626;
    --gefahr-flaeche-zart: #fff5f5;    /* Löschbereich, Konflikt, Warnkasten */
    --gefahr-rand-zart: #f0d8d8;

    /* Warnung und Hervorhebung */
    --warnung-flaeche: #fef3c7;
    --warnung-flaeche-zart: #fef9c3;
    --warnung-flaeche-blass: #fffbeb;
    --warnung-text: #92400e;
    --warnung-text-tief: #854d0e;
    --warnung-mittel: #b45309;
    --warnung-kraeftig: #d97706;
    --treffer-flaeche: #fde68a;        /* der Suchtreffer im Handbuch */
    --band-ausfall-flaeche: #fdf6ec;
    --band-ausfall-rand: #ead9bd;
    --band-ausfall-text: #7c5a1e;

    /* Einordnung: Rolle, Hinweis, Kategorie */
    --info-flaeche: #e0e7ff;
    --info-flaeche-zart: #eef2ff;
    --info-text: #3730a3;
    --info-text-tief: #1e3a8a;
    --info-marke: #4c51bf;
    --info-kante: #4338ca;
    --initialen-text: #6b70c4;
    --blau-flaeche: #dbeafe;
    --blau-text: #1e40af;
    --violett-flaeche: #f3e8ff;
    --violett-text: #6b21a8;
    --hinweis-kante: #2563eb;
    --hinweis-flaeche: #eff6ff;
    --hinweis-text: #1d4ed8;
    --voraussetzung-kante: #7c3aed;
    --voraussetzung-flaeche: #f5f3ff;
    --voraussetzung-text: #6d28d9;

    /* Ausgefallene Termine und freie Zeiten – beides tritt zurück */
    --ausfall-flaeche: #fbfbfd;
    --ausfall-rand: #cbd0dd;
    --ausfall-rand-hover: #a3aabd;
    --ausfall-text: #9096a6;
    --ausfall-marke-flaeche: #e6e8ee;
    --ausfall-marke-rand: #e0e2e8;
    --ausfall-marke-text: #5d6472;
    --frei-streifen-hell: #fafbfd;
    --frei-streifen-dunkel: #f1f3f7;
    --frei-text: #8b93a3;

    /* Das Wochenraster */
    --raster-heute: #fbfcff;
    --raster-linie-stunde: #dfe2ec;
    --raster-linie-halb: #f1f2f7;
    --raster-spaltenrand: #eceef5;
    --block-link-farbe: #c7cbd6;

    /*
     * Konturen an Farbflächen. Sie machen einen sehr hellen Typenton auf Weiß
     * als Fläche erkennbar – und müssen sich im Dunkeln umdrehen, sonst
     * verschwände ein dunkler Ton auf dunklem Grund spurlos.
     */
    --kontur-farbklotz: rgba(0,0,0,0.1);
    --kontur-farbfeld: rgba(0, 0, 0, 0.25);

    /*
     * Die Unterlage der Screenshots im Handbuch. Sie bleibt in beiden Modi
     * hell: Die Bilder zeigen die helle Oberfläche, und ein dunkler Rand um
     * ein helles Bild sähe aus wie ein Fehler im Bild. Ausdrücklich wird
     * **nicht** invertiert – ein umgefärbter Screenshot zeigte etwas, das es
     * so nirgends gibt.
     */
    --bild-unterlage: #fff;

    /* Schatten. Im Dunkeln tiefer, sonst wären sie nicht zu sehen. */
    --schatten-zart: 0 1px 2px rgba(0, 0, 0, 0.04);
    --schatten-liste: 0 1px 3px rgba(0, 0, 0, 0.06);
    --schatten-karte: 0 1px 4px rgba(0,0,0,0.07);
    --schatten-block: 0 2px 10px rgba(0,0,0,0.14);
    --schatten-hoch: 0 4px 24px rgba(0,0,0,0.10);
    --schatten-dialog: 0 8px 32px rgba(0,0,0,0.15);
    --schatten-vorschlaege: 0 12px 28px rgba(15, 23, 42, 0.14);
}

/*
 * Der dunkle Modus. Dieselben Namen, andere Werte – und keine einzige Regel,
 * die es nur hier gäbe.
 *
 * Die Stufung ist bewusst flach gehalten: Seite #14161c, Karte #1b1f27,
 * Eingabefeld #1e222b. Reines Schwarz kommt nicht vor, weil dann jede Kante
 * gleich weit entfernt wäre und die Ebenen ununterscheidbar würden.
 *
 * Die Textstufen sind nachgerechnet und liegen alle über dem 4,5:1 der
 * WCAG-Stufe AA auf der Kartenfläche – auch die leiseste (#868f9e, 5,0:1).
 * Das ist der Punkt, an dem ein dunkler Modus üblicherweise scheitert: grauer
 * Text auf fast gleichem grauem Grund.
 *
 * Das Radio-GUDE-Rot bleibt als Fläche unverändert (#e63946, weiße Schrift
 * darauf), wird als Schrift aber aufgehellt (#ff7b83): Auf #1b1f27 käme das
 * Original nur auf 3,3:1 und wäre für kleine Schrift zu schwach.
 */
@media (prefers-color-scheme: dark) {
    :root {
        color-scheme: dark;

        --flaeche-seite: #14161c;
        --flaeche-karte: #1b1f27;
        --flaeche-still: #20242d;
        --flaeche-zart: #232833;
        --flaeche-sanft: #262b35;
        --flaeche-gewaehlt: #2b3145;
        --flaeche-neutral: #333a46;
        --flaeche-neutral-stark: #414957;
        --flaeche-eingabe: #1e222b;
        --flaeche-gesperrt: #23272f;
        --flaeche-bild: #262b35;

        --text-stark: #e9ecf3;
        --text-lesetext: #dfe4ec;
        --text-normal: #d0d7e1;
        --text-mittel: #b9c1cd;
        --text-leise: #9fa8b7;
        /* Nachgerechnet an der gedämpftesten Fläche (`--flaeche-sanft`):
           4,9:1 statt der 4,4:1, auf die ein direkt übersetztes Grau
           gekommen wäre. Das ist die Stufe, an der ein dunkler Modus
           sonst zum grauen Text auf grauem Grund wird. */
        --text-still: #8f98a7;
        --text-platzhalter: #8f98a7;
        --platzhalter-text: #6f7887;

        --rand: #2e333d;
        --rand-stark: #3d4453;
        --rand-sanft: #3a404e;
        --rand-zart: #272b34;
        --rand-still: #4d5563;
        --rand-akzent: #4d5488;

        /* Der Kopf bleibt der Kopf – nur eine Spur tiefer als die Seite. */
        --kopf-flaeche: #101319;

        /* `--fuellung-text` und `--fuellung-text-leise` fehlen hier mit
           Absicht: Weiß auf der Füllung bleibt Weiß. Eine Zuweisung, die
           denselben Wert noch einmal setzt, sähe aus wie eine
           Entscheidung und wäre keine. */
        --fuellung: #3d4762;
        --fuellung-text-still: #b7bfcc;

        --kontur: #9aa5cf;
        --akzent-text: #ff7b83;
        --verweis: #8ab4f8;

        --erfolg-flaeche: #12331f;
        --erfolg-rand: #26663f;
        --erfolg-text: #86efac;
        --erfolg-kraeftig: #2fb35f;
        --erfolg-leise: #7fb99a;
        --erfolg-zart-flaeche: #10302a;
        --erfolg-zart-rand: #2a6b56;
        --erfolg-zart-text: #6fd8b2;
        --erfolg-zart-kante: #2fae83;

        --fehler-flaeche: #3a1a1a;
        --fehler-flaeche-zart: #331a1b;
        --fehler-flaeche-stark: #5e2727;
        --fehler-rand: #7d2c2c;
        --fehler-text: #ffa8a8;
        --fehler-kraeftig: #f05252;
        --gefahr-flaeche-zart: #2e1c1c;
        --gefahr-rand-zart: #4c3030;

        --warnung-flaeche: #3a2f0c;
        --warnung-flaeche-zart: #36300f;
        --warnung-flaeche-blass: #2f2913;
        --warnung-text: #f5c273;
        --warnung-text-tief: #f0c274;
        --warnung-mittel: #f0b45c;
        --warnung-kraeftig: #e79a35;
        /* Deutlich tiefer als ein bloß abgedunkeltes Gelb: Der Treffer erbt
           seine Schriftfarbe vom Text um ihn herum, und die ist hier hell.
           Bei #6d5411 kam er auf 3,9:1 – nachgemessen und korrigiert. */
        --treffer-flaeche: #5c460a;
        --band-ausfall-flaeche: #33290f;
        --band-ausfall-rand: #5a4a22;
        --band-ausfall-text: #e8c98a;

        --info-flaeche: #29315a;
        --info-flaeche-zart: #222a48;
        --info-text: #b6bef7;
        --info-text-tief: #c2d3ff;
        --info-marke: #a3a9f0;
        --info-kante: #7b83e8;
        --initialen-text: #a7ade9;
        --blau-flaeche: #1e3050;
        --blau-text: #a8c6f7;
        --violett-flaeche: #2f2544;
        --violett-text: #d6b7f5;
        --hinweis-kante: #4d86e8;
        --hinweis-flaeche: #182740;
        --hinweis-text: #9dc0ff;
        --voraussetzung-kante: #9a6ef0;
        --voraussetzung-flaeche: #261f3d;
        --voraussetzung-text: #c3aaf7;

        --ausfall-flaeche: #1d2129;
        --ausfall-rand: #3a4150;
        --ausfall-rand-hover: #525b6d;
        --ausfall-text: #7c8494;
        --ausfall-marke-flaeche: #2b303b;
        --ausfall-marke-rand: #363c48;
        --ausfall-marke-text: #99a2b2;
        --frei-streifen-hell: #1e222a;
        --frei-streifen-dunkel: #262b34;
        --frei-text: #7f8898;

        --raster-heute: #202632;
        --raster-linie-stunde: #333a47;
        --raster-linie-halb: #262b34;
        --raster-spaltenrand: #2a2f39;
        --block-link-farbe: #5a6273;

        --kontur-farbklotz: rgba(255, 255, 255, 0.28);
        --kontur-farbfeld: rgba(255, 255, 255, 0.45);

        --schatten-zart: 0 1px 2px rgba(0, 0, 0, 0.45);
        --schatten-liste: 0 1px 3px rgba(0, 0, 0, 0.5);
        --schatten-karte: 0 1px 4px rgba(0, 0, 0, 0.55);
        --schatten-block: 0 2px 10px rgba(0, 0, 0, 0.6);
        --schatten-hoch: 0 4px 24px rgba(0, 0, 0, 0.6);
        --schatten-dialog: 0 8px 32px rgba(0, 0, 0, 0.65);
        --schatten-vorschlaege: 0 12px 28px rgba(0, 0, 0, 0.6);
    }
}

/* ── Grundlayout ─────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/*
 * Der Platz des senkrechten Scrollbalkens bleibt dauerhaft frei.
 *
 * Der Sendeplan ist in der Tagesansicht kürzer als in der Wochenansicht. Ohne
 * diese Zeile erscheint der Balken beim Wechsel und verschwindet wieder; die
 * nutzbare Breite ändert sich um seine Stärke, und der gesamte Inhalt – vor
 * allem die Schalterleiste oben – springt waagerecht mit.
 *
 * `scrollbar-gutter: stable` ist genau dafür gedacht und die standardsaubere
 * Lösung an der richtigen Ebene: Der Streifen wird reserviert, der Balken aber
 * nur gezeigt, wenn er gebraucht wird. Es wird nichts erzwungen und keine
 * zweite, waagerechte Leiste erzeugt. Browser ohne Unterstützung verwerfen die
 * Zeile und verhalten sich wie bisher.
 */
html { scrollbar-gutter: stable; }

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background: var(--flaeche-seite);
    color: var(--text-stark);
    min-height: 100vh;
}

/* ── Hauptmenü ───────────────────────────────────────────── */
.hauptmenue {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: var(--kopf-flaeche);
    color: var(--fuellung-text);
    padding: 0.75rem 1.5rem;
    position: sticky;
    top: 0;
    z-index: 100;
}

.logo-bild {
    height: 38px;
    width: auto;
    display: block;
}

.untertitel {
    margin-left: 0.6rem;
    font-size: 0.9rem;
    color: var(--kopf-text);
}

.menue-rechts {
    display: flex;
    align-items: center;
    gap: 1rem;
    /* Ohne diese Zeile kann die Zone nicht schmaler werden als ihr Inhalt –
       und ein langer Anzeigename schob den ganzen Kopf in eine zweite Zeile.
       Siehe die Begründung bei `.benutzer`. */
    min-width: 0;
}

/*
 * Der Name darf als Letzter nachgeben.
 *
 * Im Kopf stehen drei Zonen: Logo und Produktname links, die Bereiche in der
 * Mitte, Name, Rolle und `Abmelden` rechts. Wird es eng, gibt zuerst die Mitte
 * nach – `menue.js` räumt Bereiche unter „Mehr". Reicht auch das nicht, weil
 * jemand einen sehr langen Anzeigenamen trägt, dann kürzt der Name sich selbst
 * mit Auslassungspunkten, statt den Kopf in eine zweite Zeile zu schieben.
 *
 * Vollständig steht er trotzdem noch da: als `title` am selben Element, und
 * sobald das Fenster wieder breit genug ist, auch wieder sichtbar. Rolle und
 * `Abmelden` bleiben unangetastet – sie sind kurz und werden gebraucht.
 */
.benutzer {
    font-size: 0.9rem;
    color: var(--kopf-text);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.abmelden {
    font-size: 0.85rem;
    color: var(--kopf-akzent);
    text-decoration: none;
    border: 1px solid var(--kopf-akzent);
    padding: 0.25rem 0.6rem;
    border-radius: 4px;
    transition: background 0.15s;
}

.abmelden:hover { background: var(--kopf-akzent); color: var(--fuellung-text); }

/* ── Login ───────────────────────────────────────────────── */
.login-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    padding: 2rem;
}

.login-box {
    background: var(--flaeche-karte);
    border-radius: 10px;
    box-shadow: var(--schatten-hoch);
    padding: 2.5rem 2rem;
    width: 100%;
    max-width: 380px;
}

.login-box h1 {
    font-size: 1.6rem;
    color: var(--akzent-text);
    margin-bottom: 0.2rem;
}

.login-untertitel {
    color: var(--text-leise);
    margin-bottom: 1.8rem;
    font-size: 0.95rem;
}

.fehler-meldung {
    background: var(--fehler-flaeche);
    color: var(--fehler-text);
    border: 1px solid var(--fehler-rand);
    border-radius: 6px;
    padding: 0.7rem 1rem;
    margin-bottom: 1.2rem;
    font-size: 0.9rem;
}

.formfeld {
    margin-bottom: 1.1rem;
}

.formfeld label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-normal);
    margin-bottom: 0.35rem;
}

.formfeld input {
    width: 100%;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    font-size: 0.95rem;
    transition: border-color 0.15s;
}

.formfeld input:focus {
    outline: none;
    border-color: var(--kontur);
}

.anmelde-button {
    width: 100%;
    padding: 0.7rem;
    background: var(--fuellung);
    color: var(--fuellung-text);
    border: none;
    border-radius: 6px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    margin-top: 0.5rem;
    transition: background 0.15s;
}

.anmelde-button:hover { background: var(--akzent); }

/*
 * Der zweite Weg unter der Anmeldeschaltfläche: „Passwort vergessen?" und die
 * Rückwege der Reset-Seiten (Issue #69). Mittig und leiser als der Knopf – wer
 * sein Passwort weiß, soll ihn gar nicht erst lesen müssen.
 */
.login-nebenweg {
    margin-top: 1.1rem;
    text-align: center;
    font-size: 0.88rem;
    color: var(--text-leise);
}

.login-nebenweg a { color: var(--akzent-text); }

/* Der erklärende Satz über einem Formular in der Anmeldekarte. */
.formular-einleitung {
    font-size: 0.88rem;
    color: var(--text-leise);
    margin-bottom: 1.2rem;
    line-height: 1.5;
}

/*
 * Die ruhige Schwester von `.fehler-meldung` in derselben Karte: eine
 * Auskunft, keine Störung. Sie trägt die neutrale Antwort auf eine
 * Reset-Anforderung – die darf nicht nach Fehler aussehen und nicht nach
 * Erfolg, denn sie sagt bewusst nicht, ob es das Konto gibt.
 */
.hinweis-meldung {
    background: var(--flaeche-zart);
    color: var(--text-normal);
    border: 1px solid var(--rand-sanft);
    border-radius: 6px;
    padding: 0.7rem 1rem;
    margin-bottom: 1.2rem;
    font-size: 0.9rem;
    line-height: 1.5;
}

/* ── Passwortfeld mit Augensymbol (Issue #69) ────────────── */
/*
 * Der Knopf liegt im Feld und nicht daneben: Daneben kostete er auf dem
 * Telefon die halbe Zeile, und das Feld selbst ist dort das Knappste, was es
 * gibt. Der zusätzliche rechte Innenabstand hält den Text von ihm fern.
 *
 * Ohne JavaScript gibt es den Knopf nicht – er steht `hidden` im Dokument und
 * wird erst von `static/passwort-auge.js` eingeblendet. Das Feld funktioniert
 * dann unverändert, nur ohne Umschalter.
 */
.passwortfeld {
    position: relative;
    display: block;
}

/*
 * Drei Selektoren für eine Regel, und der Grund ist Gewicht, nicht Geschmack:
 * `.formular-zeile input[type="password"]` weiter unten setzt `padding` als
 * Kurzform und wiegt schwerer als eine Klasse allein – der rechte Abstand für
 * das Auge wäre dort wieder weg, und der eingegebene Text liefe unter das
 * Symbol. Die beiden längeren Selektoren nennen die zwei Umgebungen, in denen
 * ein Passwortfeld vorkommt, und wiegen damit schwerer.
 */
.passwortfeld .passwortfeld-eingabe,
.formfeld .passwortfeld .passwortfeld-eingabe,
.formular-zeile .passwortfeld .passwortfeld-eingabe {
    width: 100%;
    padding-right: 2.9rem;
}

.passwort-auge {
    position: absolute;
    top: 50%;
    right: 0.3rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem;
    height: 2.2rem;
    padding: 0;
    background: none;
    border: 1px solid transparent;
    border-radius: 6px;
    color: var(--text-leise);
    cursor: pointer;
}

.passwort-auge:hover { color: var(--text-stark); }

.passwort-auge:focus-visible {
    outline: 2px solid var(--kontur);
    outline-offset: 1px;
}

/* Steht nach den Maßen und gewinnt trotzdem – ein Attributselektor wiegt
   schwerer als eine Klasse, unabhängig von der Reihenfolge. */
.passwort-auge[hidden] { display: none; }

.auge-symbol {
    width: 1.2rem;
    height: 1.2rem;
}

/*
 * Welches der beiden Symbole zu sehen ist, hängt an genau einem Zustand:
 * `aria-pressed` am Knopf. Solange das Passwort verdeckt ist, steht dort das
 * offene Auge – es sagt, was ein Klick bewirken würde. Ist es sichtbar, steht
 * dort das durchgestrichene.
 *
 * Bewusst über das Stylesheet und nicht über ein `hidden` am `<svg>`: Ein
 * SVG-Element kennt die Eigenschaft `hidden` nicht, `element.hidden = true`
 * legte dort nur ein Feld am Objekt an und ließe das Bild stehen.
 */
.auge-verbergen { display: none; }
.passwort-auge[aria-pressed="true"] .auge-anzeigen { display: none; }
.passwort-auge[aria-pressed="true"] .auge-verbergen { display: block; }

/* ── Mein Konto (Issue #69) ──────────────────────────────── */
.konto-uebersicht { margin-bottom: 1.4rem; }

.konto-angaben {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.4rem 1rem;
    margin: 0.7rem 0 0.9rem;
    font-size: 0.92rem;
}

.konto-angaben dt {
    color: var(--text-leise);
    font-weight: 600;
}

.konto-angaben dd { margin: 0; }

/*
 * Der eigene Name in der Kopfzeile führt nach „Mein Konto". Der Verweis liegt
 * um `.benutzer` herum und erbt dessen Farbe – sichtbar wird er erst beim
 * Überfahren. `min-width: 0` muss mit: Ohne ihn könnte der Name in der
 * Kopfzeile nicht mehr kürzen (Issue #63).
 */
.benutzer-konto {
    display: flex;
    align-items: center;
    min-width: 0;
    color: inherit;
    text-decoration: none;
    border-radius: 4px;
}

.benutzer-konto:hover .benutzer { text-decoration: underline; }

.benutzer-konto:focus-visible {
    outline: 2px solid var(--kopf-akzent);
    outline-offset: 2px;
}

/* Die Auskunft über den Mailversand in der Benutzerverwaltung. */
.mailstand-bereit { margin-bottom: 1.2rem; }

/* ── Dashboard ───────────────────────────────────────────── */
main { padding: 2rem 1.5rem; }

.dashboard-wrapper { max-width: 960px; margin: 0 auto; }

.dashboard-wrapper h2 {
    font-size: 1.4rem;
    margin-bottom: 0.4rem;
}

.rolle-badge {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    margin-bottom: 2rem;
    background: var(--info-flaeche);
    color: var(--info-text);
}

.rolle-badge.rolle-admin { background: var(--fehler-flaeche); color: var(--fehler-text); }
.rolle-badge.rolle-redakteur { background: var(--erfolg-flaeche); color: var(--erfolg-text); }
.rolle-badge.rolle-moderator { background: var(--warnung-flaeche-zart); color: var(--warnung-text-tief); }

.platzhalter-karten {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1.2rem;
    margin-bottom: 2rem;
}

.karte {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    padding: 1.2rem 1.4rem;
}

.karte h3 {
    font-size: 1rem;
    margin-bottom: 0.4rem;
    color: var(--text-stark);
}

.karte p {
    font-size: 0.85rem;
    color: var(--text-still);
}

.karte-aktiv { border-color: var(--kontur); }
.karte-aktiv p { color: var(--text-normal); }
.karte-aktiv a { color: var(--text-stark); text-decoration: underline; font-size: 0.85rem; }

.etappe-hinweis {
    font-size: 0.85rem;
    color: var(--text-leise);
    border-top: 1px solid var(--rand);
    padding-top: 1rem;
}

/* ── Hauptnavigation (Stammdaten-Links) ──────────────────── */
.hauptmenue {
    flex-wrap: wrap;
    gap: 0.5rem;
}

.menue-links {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.menue-nav {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex: 1;
    justify-content: center;
    /* Ohne beides blieb der Streifen 775 px breit und schob auf dem Telefon
       die ganze Seite über den Bildschirm hinaus. `min-width: 0` hebt die
       Vorgabe auf, dass ein Flex-Kind nie schmaler wird als sein Inhalt. */
    flex-wrap: wrap;
    min-width: 0;
}

.menue-link {
    font-size: 0.875rem;
    color: var(--kopf-text);
    text-decoration: none;
    padding: 0.3rem 0.75rem;
    border-radius: 4px;
    transition: background 0.15s, color 0.15s;
}

.menue-link:hover { background: rgba(255,255,255,0.1); color: var(--fuellung-text); }
.menue-link.aktiv { background: rgba(230,57,70,0.2); color: var(--kopf-akzent); font-weight: 600; }

/*
 * Der Menüschalter gehört dem Telefon.
 *
 * Auf dem Schreibtisch ist Platz für alle Bereiche nebeneinander – dort gibt
 * es ihn nicht, weder sichtbar noch als Sprungziel für die Tastatur, und die
 * Navigation steht unverändert offen da. Erst die Medienabfrage für schmale
 * Geräte weiter unten weckt ihn.
 */
.menue-umschalter,
.menue-schalter { display: none; }

/* ── „Mehr": die Navigation bleibt eine Zeile ──────────────────────────────
 *
 * Elf Bereiche brauchen 1113 px; mit Logo, Produktname, Benutzer, Rolle und
 * „Abmelden" sind es rund 1605 px. Unterhalb davon – also auf jedem Laptop –
 * brach die Leiste in eine zweite Zeile um und der Kopf wuchs von 62 auf
 * 79 px, bei 1024 px auf 109 px (Issue #63). Was nicht mehr in die Zeile
 * passt, hängt `menue.js` deshalb unter einen Sammelpunkt „Mehr".
 *
 * Drei Regeln machen das überhaupt möglich:
 *
 *   * **Der Kopf bricht nicht mehr um.** Ein Flex-Kasten verteilt Zeilen
 *     **vor** dem Schrumpfen. Solange `flex-wrap: wrap` gilt, wandert die
 *     Benutzerzone bei einem langen Anzeigenamen in eine zweite Zeile, statt
 *     den Namen zu kürzen – und dann hilft kein Sammelpunkt mehr.
 *   * **Die Leiste bricht nicht um, sondern schneidet ab.** Nur so ist
 *     „passt nicht" ein Zustand, den man rechnen kann, statt eines zweiten
 *     Kopfes, der schon gezeichnet ist. Der Zuschnitt ist dabei nie zu sehen:
 *     Das Skript räumt auf, bevor der Browser zeichnet.
 *   * **Die Bereiche schrumpfen nicht mit.** Eine Beschriftung, die
 *     abgeschnitten wird, ist kein gewonnener Platz, sondern ein neuer Fehler.
 *
 * Alles drei gilt nur mit JavaScript (`html.js`): Ohne Skript gäbe es
 * niemanden, der den Überhang einsammelt, und dann ist Umbrechen das kleinere
 * Übel. Für das Telefon nimmt der Block ganz unten alles wieder zurück – dort
 * trägt weiterhin die Klappnavigation aus Issue #35, und es kommt kein
 * zweiter Breakpoint hinzu.
 */
html.js .hauptmenue { flex-wrap: nowrap; }

html.js .menue-nav {
    flex-wrap: nowrap;
    overflow: hidden;
    /*
     * Der Boden unter der Leiste: Platz für „Mehr" (gemessen 73 px), und
     * keinen Schritt weniger.
     *
     * Die Leiste nimmt sonst genau den Platz, der übrig bleibt – bei einem
     * sehr langen Anzeigenamen und einem schmalen Fenster wäre das null, und
     * die Navigation verschwände ersatzlos. Mit diesem Boden bleibt sie
     * immer erreichbar; was dann fehlt, nimmt sich der Name (siehe dort).
     */
    min-width: 6rem;
}

html.js .menue-nav > * {
    flex: 0 0 auto;
    white-space: nowrap;
}

/*
 * Der Sammelpunkt sieht aus wie ein Bereich, weil er einer ist – er trägt
 * dieselbe Klasse `menue-link` und damit auch deren Zustand `aktiv`. Hier
 * steht nur, was eine Schaltfläche von einem Verweis unterscheidet.
 */
.menue-mehr {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: none;
    border: 0;
    font-family: inherit;
    font-size: 0.875rem;
    line-height: inherit;
    cursor: pointer;
}

/* Ein Dreieck aus Rahmen – kein Zeichen, das je nach Schrift anders aussieht. */
.menue-mehr-pfeil {
    border: 4px solid transparent;
    border-top-color: currentColor;
    border-bottom-width: 0;
    transition: transform 0.15s;
}

.menue-mehr[aria-expanded="true"] .menue-mehr-pfeil { transform: rotate(180deg); }

/*
 * Die Klappliste hängt am Kopf und nicht in der Leiste – die schneidet ihren
 * Überhang ab und würde die Liste mit abschneiden. Ihre waagerechte Lage setzt
 * das Skript, damit sie unter „Mehr" steht und trotzdem im Kopf bleibt.
 */
.menue-mehr-liste {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 110;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 12rem;
    padding: 0.4rem;
    background: var(--kopf-flaeche);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 0 0 8px 8px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35);
}

.menue-mehr-liste .menue-link {
    display: block;
    white-space: nowrap;
}

/* `hidden` muss auch gegen ein `display` aus einer Regel gelten. */
.menue-mehr[hidden],
.menue-mehr-liste[hidden] { display: none; }

/*
 * Der Fokus wird nach innen gezeichnet. Die Leiste schneidet ihren Überhang
 * ab; ein Ring außerhalb des Kastens wäre am Rand der Leiste halb weg – und
 * ein halb sichtbarer Fokus ist für die Tastatur kein Fokus.
 */
.menue-link:focus-visible,
.menue-mehr:focus-visible {
    outline: 2px solid var(--kopf-akzent);
    outline-offset: -2px;
}

/* ── Stammdaten-Seiten – gemeinsames Layout ───────────────── */
/*
 * Die seitliche Polsterung steht als Variable, weil die Auswahlleiste des
 * Sendeplans denselben Wert braucht: Sie steht außerhalb des Flusses und muss
 * ihre linke und rechte Kante selbst setzen – aus dieser einen Angabe statt aus
 * einer zweiten Zahl. Auf dem Telefon wird sie weiter unten kleiner gesetzt,
 * und die Leiste folgt von selbst mit.
 */
.seite-wrapper {
    --seiten-polster: 0.5rem;

    max-width: 1100px;
    margin: 0 auto;
    padding: 0 var(--seiten-polster);
}

/* ── Feststehender Kopf, scrollender Inhalt ───────────────────────────────
 *
 * Eine Arbeitsansicht besteht aus zwei Teilen: oben, was man ständig braucht –
 * Überschrift, Schalter, Filter, Spaltenköpfe –, darunter der Inhalt. Beim
 * Scrollen soll der obere Teil stehen bleiben.
 *
 * Erreicht wird das nicht mit `position: sticky` an vielen Einzelteilen,
 * sondern mit einer Aufteilung: Die Seite ist genau so hoch wie das Fenster,
 * und **nur** der Inhaltsbereich scrollt. Das hat drei Vorteile gegenüber
 * gestapelten Sticky-Elementen:
 *
 *   * Es gibt keine Sticky-Zonen, die einander überlagern könnten, und keine
 *     Kette von `top`-Werten, die zusammen die Höhe der Elemente darüber
 *     ergeben müssten – Werte, die bei jedem responsiven Umbruch neu falsch
 *     wären.
 *   * Der Inhalt kann nicht unter den Kopf geraten, weil er gar nicht dorthin
 *     kann.
 *   * Es ist dieselbe Aufteilung, die die Wochenansicht seit jeher hat: Kopf
 *     außerhalb, Raster mit eigenem Scrollbereich darin. Statt sie ein zweites
 *     Mal nachzubauen, wird sie hier verallgemeinert.
 *
 * Angeschaltet wird das je Seite über `seite-fest` am `<body>`. Ohne die Klasse
 * ändert sich nichts – Personen, Benutzer und alle Formulare scrollen weiter
 * wie gewohnt.
 */
.seite-fest {
    height: 100vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
/* `min-height: 0` an jeder Stufe: Ohne das darf ein Flex-Element nicht unter
   die Höhe seines Inhalts schrumpfen, und der Scrollbereich säße außerhalb des
   Fensters statt darin. */
.seite-fest main,
.seite-fest .seite-wrapper {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
/*
 * `width: 100%` ist hier nicht überflüssig: In einer Flex-Spalte richtet sich
 * ein Element mit `margin: 0 auto` quer nicht mehr nach der verfügbaren
 * Breite, sondern nach seinem Inhalt – die Sendungsliste stand dadurch 190 px
 * weiter rechts als die Elementliste. Mit `width: 100%` bleibt die Breite die
 * gewohnte und `max-width` die Grenze.
 */
.seite-fest .seite-wrapper { width: 100%; }

/*
 * Eine gemeinsame Arbeitsbreite für die Arbeitsansichten.
 *
 * Vorher begann die Kopfzeile in jeder Ansicht woanders: bei 24 px im
 * Sendeplan, bei 32 px in der Planung und bei 170 px in Elementen und
 * Sendungen, die auf 1100 px zentriert waren. Beim Wechsel sprang der
 * Seitenkopf also um bis zu 146 px zur Seite – genau das, was hier ruhig
 * werden soll.
 *
 * Gebunden an `seite-fest` und damit an dieselbe Entscheidung: Personen,
 * Benutzer und alle Formulare behalten ihre zentrierte Lesebreite, weil ein
 * Formular von begrenzter Zeilenlänge profitiert und eine Arbeitsfläche von
 * Platz.
 */
.seite-fest .seite-wrapper {
    max-width: none;
    margin: 0;
}

/*
 * Der scrollende Teil. Er nimmt den Platz, der nach dem Kopf übrig bleibt –
 * ohne dass irgendwo eine Höhe geraten werden müsste.
 */
/*
 * Das Raster der Wochenansicht ist derselbe Fall: ein Scrollbereich, der den
 * Rest der Seite ausfüllen soll. Es hatte dafür `max-height: calc(100vh -
 * 15rem)` – einen Schätzwert für alles, was darüber steht.
 *
 * Gemessen war er um rund 10 px zu großzügig: Das Raster ragte ein Stück über
 * das Fenster hinaus, und die Seite scrollte zusätzlich zum Raster. Zwei
 * Scrollrichtungen für dieselbe Bewegung, und der Kopf rutschte dabei ein
 * wenig mit. Jetzt füllt das Raster genau den Rest – ohne Schätzwert, der bei
 * der nächsten Kopfänderung wieder falsch wäre.
 */
.seite-fest .raster {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
}

.arbeitsflaeche-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    /* Der Platz des Scrollbalkens bleibt reserviert, damit die Spalten beim
       Wachsen der Liste nicht seitlich springen – dieselbe Regel wie am
       Dokument (#4). */
    scrollbar-gutter: stable;
}

.seite-kopf {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.5rem;
    /* Auf schmalen Geräten rutscht die Schaltfläche unter die Überschrift,
       statt rechts aus dem Bildschirm zu laufen. */
    flex-wrap: wrap;
    gap: 0.75rem;
}

.seite-kopf h2 {
    font-size: 1.4rem;
}

/* ── Meldungen (Erfolg / Fehler) ─────────────────────────── */
.meldung {
    padding: 0.75rem 1rem;
    border-radius: 6px;
    margin-bottom: 1.2rem;
    font-size: 0.9rem;
}

.meldung-erfolg {
    background: var(--erfolg-flaeche);
    color: var(--erfolg-text);
    border: 1px solid var(--erfolg-rand);
}

.meldung-fehler {
    background: var(--fehler-flaeche);
    color: var(--fehler-text);
    border: 1px solid var(--fehler-rand);
}

/* ── Datentabelle ─────────────────────────────────────────── */
/*
 * Kein `overflow: hidden` mehr. Es rundete die Ecken, hätte aber die
 * Spaltenköpfe am Feststehen gehindert: Ein Vorfahre mit `overflow: hidden`
 * schneidet ein `position: sticky` ab, noch bevor es wirken kann. Die Rundung
 * übernehmen jetzt die Eckzellen selbst.
 */
.datentabelle {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--flaeche-karte);
    border-radius: 8px;
    box-shadow: var(--schatten-karte);
    font-size: 0.9rem;
}

.datentabelle thead {
    background: var(--fuellung);
    color: var(--fuellung-text);
}

/*
 * Die Spaltenköpfe bleiben beim Scrollen stehen.
 *
 * `top: 0` bezieht sich auf den nächsten scrollenden Vorfahren, und das ist
 * `.arbeitsflaeche-scroll` – nicht das Fenster. Deshalb braucht es hier keinen
 * Versatz um die Höhe der Menüleiste oder des Seitenkopfs: Beide liegen
 * außerhalb des Scrollbereichs und können gar nicht überlagert werden.
 *
 * `background` gehört an die Zelle, nicht nur an `thead`: Ein `sticky`
 * gesetztes Element trägt seinen Hintergrund selbst, sonst scheint der Inhalt
 * darunter durch.
 */
.datentabelle thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--fuellung);
}
.datentabelle thead th:first-child { border-top-left-radius: 8px; }
.datentabelle thead th:last-child { border-top-right-radius: 8px; }
.datentabelle tbody tr:last-child td:first-child { border-bottom-left-radius: 8px; }
.datentabelle tbody tr:last-child td:last-child { border-bottom-right-radius: 8px; }

.datentabelle th {
    padding: 0.7rem 1rem;
    text-align: left;
    font-weight: 600;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.datentabelle td {
    padding: 0.65rem 1rem;
    border-bottom: 1px solid var(--rand-zart);
    vertical-align: middle;
}

.datentabelle tbody tr:last-child td { border-bottom: none; }
.datentabelle tbody tr:hover { background: var(--flaeche-zart); }

/* ── Listenkarten ─────────────────────────────────────────────
 *
 * Dieselben Daten wie die Tabelle darüber, nur als eine Karte je Datensatz.
 * Getragen wird das von Planung, Elementen, Sendungen und Programmpunkt-Typen
 * (Issue #45).
 *
 * Am Schreibtisch ist die Kartenliste nicht da – nicht „klein“, nicht
 * „gestapelt“, sondern `display: none`. Dort bleibt die Tabelle die Ansicht,
 * und sie soll es bleiben: Elf Spalten nebeneinander sind auf 1600 px die
 * bessere Form, und der Mobile-Audit (#35) verlangt für dieses Paket
 * ausdrücklich, dass sich am Schreibtisch nichts ändert.
 *
 * Umgekehrt wird unter 640 px die Tabelle ausgeblendet und die Kartenliste
 * eingeblendet; beide Regeln stehen im Telefon-Block weiter unten, zusammen
 * mit der Gestaltung der Karte selbst.
 *
 * Die Tabelle bleibt dabei **im Dokument**. Sie wird nicht ersetzt, sondern
 * verborgen – so steht es im Audit unter „Seiteneffekte“, und dort stehen auch
 * die Suiten, die ihr Vorhandensein ausdrücklich prüfen.
 */
.listenkarten { display: none; }

/* Elemente-Baum */
.zeile-parent { background: var(--flaeche-karte); }
.zeile-kind { background: var(--flaeche-still); }
.zeile-kind td { font-size: 0.88rem; }

.kind-einzug { padding-left: 2rem !important; }
.baum-linie { color: var(--text-still); margin-right: 0.4rem; }
.baum-marker { color: var(--text-still); margin-right: 0.4rem; font-size: 0.7rem; }
.kinder-anzahl { font-size: 0.8rem; color: var(--text-leise); margin-left: 0.5rem; }

.aktionen { white-space: nowrap; }

/* ── Schaltflächen ────────────────────────────────────────── */
.schaltflaeche {
    display: inline-block;
    padding: 0.45rem 0.9rem;
    border-radius: 5px;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    border: none;
    transition: background 0.15s, opacity 0.15s;
}

.schaltflaeche-primaer  { background: var(--fuellung); color: var(--fuellung-text); }
.schaltflaeche-primaer:hover  { background: var(--akzent); }

.schaltflaeche-neutral  { background: var(--flaeche-neutral); color: var(--text-normal); }
.schaltflaeche-neutral:hover  { background: var(--flaeche-neutral-stark); }

.schaltflaeche-gefahr   { background: var(--fehler-flaeche); color: var(--fehler-text); }
.schaltflaeche-gefahr:hover   { background: var(--fehler-flaeche-stark); }

.schaltflaeche-klein { padding: 0.25rem 0.6rem; font-size: 0.8rem; }
.schaltflaeche:disabled { opacity: 0.4; cursor: not-allowed; }

/* ── Badges & Kästchen ────────────────────────────────────── */
.farbklotz {
    display: inline-block;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: 4px;
    border: 1px solid var(--kontur-farbklotz);
    vertical-align: middle;
}

.kategorie-badge {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.kategorie-wort     { background: var(--blau-flaeche); color: var(--blau-text); }
.kategorie-werbung  { background: var(--warnung-flaeche-zart); color: var(--warnung-text-tief); }
.kategorie-service  { background: var(--erfolg-flaeche); color: var(--erfolg-text); }
.kategorie-musik    { background: var(--violett-flaeche); color: var(--violett-text); }

.badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 999px; font-size: 0.78rem; font-weight: 600; }
.badge-gruen { background: var(--erfolg-flaeche); color: var(--erfolg-text); }
.badge-grau  { background: var(--flaeche-sanft); color: var(--text-leise); }

.typ-badge {
    display: inline-block;
    padding: 0.15rem 0.5rem 0.15rem 0.4rem;
    border-radius: 4px;
    font-size: 0.82rem;
}

/* ── Formular ─────────────────────────────────────────────── */
.formular {
    background: var(--flaeche-karte);
    border-radius: 8px;
    box-shadow: var(--schatten-karte);
    padding: 1.8rem 2rem;
    /*
     * Die Flucht der Seite – dieselbe Zahl, die alles liest, was sich an
     * diesem Kasten ausrichtet (siehe `--flucht` weiter unten). Vorher stand
     * hier 720 px als eigene Zahl; die Kachel darunter kannte sie nicht und
     * war deshalb so breit wie der Wrapper.
     */
    max-width: var(--flucht);
}

/*
 * Folgt eine Sonderaktion unmittelbar auf das Formular, rückt der Kasten unten
 * enger zusammen. Das untere Polster von 1,8 rem ist als Abschluss gedacht –
 * hier schließt aber noch etwas an, und mit ihm stand die Aktion 38 px tiefer
 * und las sich wie ein eigener Abschnitt.
 */
.formular-anschluss { padding-bottom: 0.9rem; }

.formular-abschnitt {
    border: 1px solid var(--rand);
    border-radius: 6px;
    padding: 1.2rem 1.4rem;
    margin-bottom: 1.5rem;
}

.formular-abschnitt legend {
    padding: 0 0.5rem;
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text-stark);
}

.abschnitt-hinweis {
    font-size: 0.84rem;
    color: var(--text-leise);
    margin-bottom: 1rem;
}

.formular-zeile {
    margin-bottom: 1.1rem;
}

.formular-zeile label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-normal);
    margin-bottom: 0.3rem;
}

/*
 * Die vier Feldarten, die in einer Formularzeile vorkommen. `email` und
 * `password` sind seit Issue #69 dabei: Beide gab es schon in der
 * Benutzerverwaltung, standen aber nicht in dieser Liste und wurden deshalb
 * unbestylt gezeichnet – ein kantiges Kästchen neben lauter gerundeten
 * Feldern. Mit „Mein Konto" und den Reset-Seiten stehen jetzt drei
 * Passwortfelder untereinander, und derselbe Unterschied wäre dort nicht mehr
 * zu übersehen.
 */
.formular-zeile input[type="text"],
.formular-zeile input[type="url"],
.formular-zeile input[type="number"],
.formular-zeile input[type="email"],
.formular-zeile input[type="password"],
/* `date` und `time` kommen mit den Fristen der Redaktionsaufgaben dazu
   (Issue #71). Ohne sie zeichnete der Browser genau dort sein eigenes,
   kantiges Feld – neben zwei gerundeten in derselben Zeile. */
.formular-zeile input[type="date"],
.formular-zeile input[type="time"],
.formular-zeile select,
.formular-zeile textarea {
    width: 100%;
    padding: 0.55rem 0.8rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    font-size: 0.92rem;
    font-family: inherit;
    transition: border-color 0.15s;
    background: var(--flaeche-eingabe);
}

.formular-zeile input:focus,
.formular-zeile select:focus,
.formular-zeile textarea:focus {
    outline: none;
    border-color: var(--kontur);
}

.checkbox-label {
    display: flex !important;
    align-items: center;
    gap: 0.5rem;
    font-weight: 500 !important;
    cursor: pointer;
}

.checkbox-label input[type="checkbox"] {
    width: auto;
    margin: 0;
}

.farbe-eingabe {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.farbe-eingabe input[type="color"] {
    width: 3rem;
    height: 2.2rem;
    padding: 0.1rem;
    border-radius: 4px;
    cursor: pointer;
}

.farbe-vorschau {
    font-size: 0.85rem;
    color: var(--text-leise);
    font-family: monospace;
}

.hinweis {
    display: block;
    font-size: 0.8rem;
    color: var(--text-leise);
    margin-top: 0.3rem;
}

.pflicht { color: var(--akzent-text); }

.formular-aktionen {
    display: flex;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

/* ── Sonstige Hilfselemente ───────────────────────────────── */
.dauer-readonly {
    display: inline-block;
    padding: 0.55rem 0.8rem;
    background: var(--flaeche-sanft);
    border: 1px solid var(--rand);
    border-radius: 6px;
    font-size: 0.92rem;
    color: var(--text-leise);
}

.leer-hinweis {
    color: var(--text-leise);
    padding: 2rem;
    text-align: center;
    background: var(--flaeche-karte);
    border-radius: 8px;
    border: 1px dashed var(--rand-stark);
}

.leer-wert { color: var(--text-still); }
.kurztext { color: var(--text-normal); }
.link-extern { color: var(--text-stark); font-size: 0.85rem; }

/* ── Select mit "+ Neu"-Button ───────────────────────────── */
.select-mit-neu {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}
.select-mit-neu select { flex: 1; }

/* ── Schnell-Dialog ──────────────────────────────────────── */
.schnell-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    margin: 0;
    border: 1px solid var(--rand-stark);
    border-radius: 10px;
    padding: 1.5rem;
    width: 100%;
    /* 420 px am Schreibtisch – und auf einem schmalen Gerät ein Rand von je
       1 rem, statt Kante an Kante mit dem Display. Ohne die zweite Grenze war
       der Dialog auf einem 390-px-Telefon genau 390 px breit; die abgerundeten
       Ecken lagen dann außerhalb des sichtbaren Bereichs. */
    max-width: min(420px, calc(100vw - 2rem));
    box-shadow: var(--schatten-dialog);
    /* Ohne diese beiden Zeilen zeichnete der Browser den Dialog in seiner
       eigenen Farbe (`Canvas`) – im Dunkeln richtig, aber eben nicht in der
       Farbe der Karten daneben. Die Fläche gehört zur Oberfläche. */
    background: var(--flaeche-karte);
    color: var(--text-normal);
}
.schnell-dialog h3 {
    font-size: 1.1rem;
    margin-bottom: 1rem;
    color: var(--text-stark);
}
/*
 * Die Angaben, die ein Bestätigungsdialog nennen muss: Bezeichnung links,
 * Wert rechts, zwei Spalten, keine Tabelle. Man soll auf einen Blick sehen,
 * welchen Termin es trifft – „Wirklich?" allein beantwortet niemand richtig.
 */
.dialog-angaben {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.9rem;
    row-gap: 0.2rem;
    margin: 0 0 0.9rem;
    padding: 0.55rem 0.7rem;
    border-radius: 6px;
    background: var(--flaeche-zart);
    font-size: 0.87rem;
}
.dialog-angaben dt { color: var(--text-leise); }
.dialog-angaben dd { margin: 0; color: var(--text-stark); font-weight: 500; overflow-wrap: anywhere; }

.dialog-hinweis { font-size: 0.85rem; line-height: 1.45; color: var(--text-normal); margin: 0; }

/* Abbrechen links, die zerstörende Aktion rechts – und beide am rechten Rand,
   wo die Hand nach dem Lesen ohnehin steht. */
.dialog-aktionen { justify-content: flex-end; flex-wrap: wrap; }

.schnell-dialog::backdrop {
    background: rgba(0,0,0,0.4);
}

/* ── Programm-Verwaltung ──────────────────────────────────── */
.seite-wrapper-breit { max-width: 1400px; }

/*
 * Und die Gegenrichtung, seit Issue #69: „Mein Konto" besteht aus zwei kurzen
 * Formularen und drei Angaben darüber. Über die volle Breite gezogen stünde
 * ein einzeiliges Eingabefeld 900 px weit da – das liest sich schlecht und
 * tippt sich schlechter. Die Klasse steht hier neben ihrer Schwester und nicht
 * bei den Konto-Regeln weiter oben: Beide überschreiben `.seite-wrapper` und
 * müssen dafür nach ihm kommen.
 */
.seite-wrapper-schmal { max-width: 640px; }

/*
 * Die Breite des Programmformulars: eine Zahl, zwei Leser.
 *
 * Der Formularkasten und die Sonderaktion darunter (`.einzelaktion`, weiter
 * unten) sind Geschwister im selben Wrapper und sollen dieselben Außenkanten
 * haben – links wie rechts. Stünde die Zahl zweimal im Stylesheet, liefen die
 * beiden Kanten beim nächsten Eingriff auseinander; genau das war der Befund
 * zu Issue #66. Deshalb steht sie hier einmal und wird zweimal gelesen.
 *
 * Sie ist kein Farbtoken und gehört deshalb nicht in den Farbkopf oben – die
 * dunkle Medienabfrage hat mit einer Breite nichts zu schaffen.
 */
:root { --formular-breite: 860px; }

/* ── Die Flucht einer Seite ───────────────────────────────────────────────
 *
 * Issue #66 hat das Problem für **eine** Seite gelöst; Issue #76 sagt, dass es
 * dasselbe Problem überall ist: Aktions-, Warn- und Löschkacheln standen unter
 * dem Formular, waren aber schmaler oder breiter als es und fluchteten links
 * und rechts nicht mit ihm. Im Rollenformular lag der rote Kasten „Rolle
 * löschen“ 300 px weiter rechts als das Formular darüber, in der
 * Benutzermaske 380 px. Die Ursache war jedes Mal dieselbe: Der Formularkasten
 * hatte eine Höchstbreite, sein Nachbar keine – und übernahm damit die des
 * Wrappers.
 *
 * Statt das je Kachel nachzuziehen, hat die Seite jetzt **eine Flucht**: die
 * linke und rechte Kante, an der alles ausgerichtet ist, was untereinander
 * steht. Sie ist eine Zahl (`--flucht`), sie steht je Seite genau einmal, und
 * gelesen wird sie von zwei Stellen:
 *
 *   * `.formular`      – der Formularkasten selbst (weiter oben)
 *   * `.formularflucht` – alles, was sich an ihm ausrichten soll: der
 *     Fehlerhinweis darüber, der Löschbereich darunter, die Absagekachel,
 *     jede weitere Kachel dieser Art.
 *
 * Der Normalfall sind 720 px – die Breite eines Formulars mit Eingabefeldern
 * untereinander. Zwei Seiten brauchen mehr, und beide sagen es an genau einer
 * Stelle: an ihrem Wrapper, abgeleitet aus der Klasse ihres Formulars. Damit
 * gibt es weiterhin nur einen Ort je Seite, an dem die Breite steht, und die
 * Kachel darunter kann gar nicht mehr eine andere haben.
 *
 * `:has()` steht hier bewusst statt einer zusätzlichen Klasse am Wrapper: Eine
 * zweite Klasse wäre eine zweite Angabe derselben Sache, und genau solche
 * Paare laufen beim nächsten Eingriff auseinander.
 */
:root { --flucht: 720px; }
.seite-wrapper:has(> .formular-breit)  { --flucht: var(--formular-breite); }
/*
 * Das Rollenformular ist breiter als die anderen: `.formular` deckelt bei
 * 720 px – richtig für ein paar Eingabefelder untereinander, zu eng für eine
 * Matrix mit fünf Spalten. Bei 720 px blieben für den Bereichsnamen 200 px,
 * und jede Bereichsbeschreibung stand über fünf Zeilen. 1100 px ist die
 * gewohnte Lesebreite dieser Anwendung (`.seite-wrapper`); die Maske selbst
 * steht im breiten Wrapper von 1400 px, damit ihr Kopf Platz hat.
 */
.seite-wrapper:has(> .formular-rollen) { --flucht: 1100px; }

/*
 * Die gemeinsame Regel. Sie enthält absichtlich nichts als die Breite: Farbe,
 * Rahmen und Innenabstände bleiben Sache der jeweiligen Kachel – es geht um
 * Außenbreite und Flucht, nicht darum, alles gleich aussehen zu lassen.
 *
 * Eine Höchstbreite und keine feste: Unterhalb der Flucht füllt die Kachel die
 * Zeile wie das Formular, auf dem Telefon also die volle Breite.
 */
.formularflucht { max-width: var(--flucht); }

/* Datum- und Zeitfelder wie die übrigen Eingabefelder gestalten */
.formular-zeile input[type="date"],
.formular-zeile input[type="time"] {
    width: 100%;
    padding: 0.55rem 0.8rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    font-size: 0.92rem;
    font-family: inherit;
    background: var(--flaeche-eingabe);
}
.formular-zeile input[type="date"]:focus,
.formular-zeile input[type="time"]:focus { outline: none; border-color: var(--kontur); }
.formular-zeile input[readonly] { background: var(--flaeche-sanft); color: var(--text-leise); }

/* Zwei Felder nebeneinander (gültig ab / gültig bis) */
.formular-zeile-doppelt {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.2rem;
}
@media (max-width: 640px) {
    .formular-zeile-doppelt { grid-template-columns: 1fr; }
}

/* Umschalter "vorhandener Inhalt" / "neuer Inhalt" */
.auswahl-schalter {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    background: var(--flaeche-zart);
    border: 1px solid var(--rand);
    border-radius: 6px;
    padding: 0.7rem 1rem;
}
.auswahl-schalter input[type="radio"] { width: auto; margin: 0; }

/* Wochentags-Auswahl */
.wochentage-auswahl {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.wochentag-feld {
    display: flex !important;
    align-items: center;
    gap: 0.4rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    padding: 0.4rem 0.75rem;
    background: var(--flaeche-karte);
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 500 !important;
    margin-bottom: 0 !important;
    user-select: none;
}
.wochentag-feld input[type="checkbox"] { width: auto; margin: 0; }
.wochentag-feld:has(input:checked) { border-color: var(--kontur); background: var(--flaeche-gewaehlt); }

/* Programm-Tabelle */
/*
 * Bestandsklasse ohne eigene Wirkung mehr. Sie trug den waagerechten
 * Scrollbereich für die breite Planungstabelle; den übernimmt jetzt
 * `.arbeitsflaeche-scroll`, der ohnehin in beide Richtungen scrollt. Zwei
 * ineinanderliegende Scrollbereiche wären nicht nur überflüssig gewesen – der
 * innere hätte die Spaltenköpfe am Feststehen gehindert.
 */
.tabelle-scroll { min-width: 0; }

/*
 * Ein Kasten, der nur auf dem Telefon einer ist.
 *
 * Die Typenliste (`/typen`) hat keinen `.arbeitsflaeche-scroll` – anders als
 * Planung, Elemente und Sendungen. Ihre sieben Spalten brauchen rund 1150 px;
 * bei 390 px wanderte der Überlauf deshalb an das Dokument selbst: 767 px
 * waagerechtes Scrollen der ganzen Seite, Kopfzeile inbegriffen. Gemessen im
 * Mobile-Audit zu Issue #35.
 *
 * Das eigentliche Gegenmittel ist die Kartenliste aus Paket 3 (#45), und sie
 * steht inzwischen: Unter 640 px ist die Tabelle ausgeblendet, der Kasten
 * umschließt dort nichts Sichtbares mehr. Er bleibt trotzdem – er kostet
 * nichts und ist die Rückfallebene, falls die Tabelle auf einem schmalen
 * Gerät je wieder erscheint.
 *
 * Warum die Regel in der Medienabfrage steht und nicht hier: Ein
 * Scrollbereich schneidet `position: sticky` ab. Am Schreibtisch passt die
 * Tabelle ohnehin in die Seitenbreite – dort gäbe es nichts zu scrollen, wohl
 * aber feststehende Spaltenköpfe zu verlieren. Also bleibt der Kasten dort ein
 * gewöhnliches `div`.
 */
.tabelle-quer { min-width: 0; }
.programm-tabelle { min-width: 1150px; font-size: 0.86rem; }
.zelle-zeit strong { font-variant-numeric: tabular-nums; }
.toleranz { display: block; font-size: 0.72rem; color: var(--text-leise); }
.zeittext { font-style: italic; color: var(--text-normal); }
.sendung-hinweis { display: block; font-size: 0.75rem; color: var(--text-leise); }
.programm-tabelle .badge { margin-left: 0.3rem; }

.badge.sidebar-voll         { background: var(--blau-flaeche); color: var(--blau-text); }
.badge.sidebar-nur_vorschau { background: var(--warnung-flaeche-zart); color: var(--warnung-text-tief); }
.badge.sidebar-aus          { background: var(--flaeche-sanft); color: var(--text-leise); }

.tabellen-fussnote { font-size: 0.8rem; color: var(--text-leise); margin-top: 0.9rem; }

/* ── Klärungen ────────────────────────────────────────────── */
.fortschritt { margin-bottom: 2rem; }
.fortschritt-text { font-size: 0.95rem; color: var(--text-normal); margin-bottom: 0.5rem; }
.fortschritt-balken {
    height: 10px;
    background: var(--flaeche-neutral);
    border-radius: 999px;
    overflow: hidden;
}
.fortschritt-balken span {
    display: block;
    height: 100%;
    background: var(--erfolg-kraeftig);
    border-radius: 999px;
    transition: width 0.3s;
}

.klaerung-block { margin-bottom: 2.5rem; }
.block-ueberschrift {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-leise);
    border-bottom: 1px solid var(--rand);
    padding-bottom: 0.5rem;
    margin-bottom: 1.2rem;
}
.block-ueberschrift .anzahl {
    background: var(--flaeche-neutral);
    color: var(--text-normal);
    border-radius: 999px;
    padding: 0.1rem 0.5rem;
    font-size: 0.78rem;
    margin-left: 0.4rem;
}

.klaerung-karte {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-left: 3px solid var(--akzent);
    border-radius: 8px;
    box-shadow: var(--schatten-karte);
    padding: 1.3rem 1.5rem;
    margin-bottom: 1.2rem;
    max-width: 820px;
}
.klaerung-karte.klaerung-geklaert { border-left-color: var(--erfolg-kraeftig); }

.klaerung-kopf {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    flex-wrap: wrap;
    margin-bottom: 0.8rem;
}
.klaerung-kopf h3 { font-size: 1.1rem; color: var(--text-stark); flex: 1; }
.kategorie-klaerung { background: var(--info-flaeche); color: var(--info-text); }
.badge-offen { background: var(--warnung-flaeche); color: var(--warnung-text); }

.klaerung-frage { font-size: 1rem; font-weight: 600; color: var(--text-stark); margin-bottom: 0.6rem; }
.klaerung-kontext { font-size: 0.9rem; color: var(--text-mittel); margin-bottom: 0.6rem; }
.klaerung-quelle { font-size: 0.8rem; color: var(--text-still); margin-bottom: 1rem; }

.klaerung-antwort {
    background: var(--erfolg-flaeche);
    border: 1px solid var(--erfolg-rand);
    border-radius: 6px;
    padding: 0.6rem 0.9rem;
    font-size: 0.92rem;
    color: var(--erfolg-text);
    margin-bottom: 0.6rem;
}
.klaerung-datum { color: var(--erfolg-leise); font-size: 0.82rem; }
.klaerung-notiz-anzeige {
    font-size: 0.9rem;
    color: var(--text-normal);
    background: var(--flaeche-zart);
    border: 1px solid var(--rand);
    border-radius: 6px;
    padding: 0.5rem 0.9rem;
    margin-bottom: 1rem;
}

.klaerung-form { margin-top: 1rem; }
.klaerung-optionen {
    border: 1px solid var(--rand);
    border-radius: 6px;
    padding: 0.9rem 1.1rem;
    margin-bottom: 1rem;
}
.klaerung-optionen legend {
    padding: 0 0.4rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text-leise);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.klaerung-option {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.45rem 0.2rem;
    font-size: 0.93rem;
    color: var(--text-normal);
    cursor: pointer;
    border-radius: 4px;
}
.klaerung-option:hover { background: var(--flaeche-zart); }
.klaerung-option input[type="radio"] { margin-top: 0.25rem; flex-shrink: 0; }
.klaerung-option:has(input:checked) { background: var(--flaeche-gewaehlt); font-weight: 600; color: var(--text-stark); }

.klaerung-notiz { margin-bottom: 0.5rem; }
.klaerung-notiz.notiz-noetig label::after {
    content: " – bitte ausfüllen";
    color: var(--akzent-text);
    font-weight: 600;
}
.klaerung-notiz.notiz-noetig textarea { border-color: var(--akzent); background: var(--gefahr-flaeche-zart); }

.klaerung-karte .formular-aktionen { margin-top: 0.8rem; }

/*
 * Der Aufklapper „Antwort ändern“ einer bereits geklärten Frage – Issue #46.
 *
 * Er gehört dem Telefon. Am Schreibtisch ist Platz genug, dort stehen alle
 * Formulare offen da wie bisher, und beide Teile des Schalters nehmen keinen
 * Platz ein: Das ist der Unterschied zwischen „nicht ausgeliefert“ und „nimmt
 * keinen Raum ein" – das Markup steht auf jeder Breite im Dokument, und die
 * Entscheidung fällt an genau dieser einen Stelle.
 *
 * Was daraus unter 640 px wird, steht im Telefon-Block.
 */
.klaerung-aendern-schalter,
.klaerung-aendern-taste { display: none; }

/* ── Sendeplan: Tages- und Wochenansicht ──────────────────── */
/* ── Kompakter Kopfbereich des Sendeplans ─────────────────────────────────
 *
 * Der Sendeplan ist das Arbeitswerkzeug; das Raster soll den Bildschirm
 * ausfüllen. Vorher standen darüber eine Titelzone (46 px), ein
 * Navigationsband (46 px) und eine Werkzeugleiste mit eingebauter
 * Statistikzeile (60 px), dazwischen dreimal 16–19 px Abstand: gut 203 px auf
 * 1440x900, gemessen am 27.08.2026.
 *
 * Verdichtet, nicht beschnitten: Es fehlt keine Funktion. Titelzone und
 * Navigationsband sagen beide, *welcher Zeitraum* – sie sind jetzt eine Zeile.
 * Die Statistik hat die Werkzeugleiste verlassen, weil ihre Länge dort die
 * Geometrie der Bedienelemente veränderte.
 */

/* Der Sendeplan braucht oben weniger Luft als eine Formularseite. Die Klasse
   sitzt am `main` und gilt nur für ihn – alle anderen Seiten behalten ihr
   Polster. */
/* Waagerecht knapper als die übrigen Seiten: Eine Arbeitsfläche ist kein
   Lesetext. Die 16 px, die das je Seite freigibt, entscheiden bei 1024 px
   darüber, ob die Werkzeugleiste des Sendeplans in eine Zeile passt – sie war
   dort um 0,4 px zu breit.

   Seit #14 tragen alle fünf Arbeitsansichten dieselbe Polsterung, damit der
   Seitenkopf beim Wechsel nicht senkrecht springt: Er stand im Sendeplan bei
   73 px, in den Listen bei 94 px. */
.hauptbereich-arbeit { padding: 0.7rem 1rem 0.8rem; }

/*
 * Zwei Zonen: links das Blättern samt Zeitraum, rechts Datum und
 * Ansichtsumschalter.
 *
 * `margin-left: auto` statt `justify-content: space-between`. Der Unterschied
 * zeigt sich erst beim Umbruch: `space-between` stellt eine allein
 * umgebrochene Zone an den **linken** Rand – die Umschalter sprangen dadurch
 * bei 1245 px um 633 px nach links. Mit `margin-left: auto` bleibt die rechte
 * Zone rechts, ob sie nun neben dem Blätterbereich steht oder unter ihm.
 */
.plan-kopfzeile {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0.8rem;
    margin-bottom: 0.5rem;
}
.plan-blaettern { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }

/*
 * Die rechte Zone. Sie darf umbrechen – aber immer nach demselben Muster:
 * Das Datum rutscht nach oben weg, die Umschalter bleiben unten rechts
 * stehen. Das ergibt sich aus der Reihenfolge im Markup und daraus, dass eine
 * umbrechende Zeile ihre letzte Zeile rechts ausrichtet.
 */
.plan-rechts {
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 0.5rem 0.8rem;
}

/*
 * Die beiden Umschaltergruppen bleiben zusammen. Getrennt umgebrochen stünde
 * „Tag | Woche" allein in einer Zeile und wechselte dabei seine Position –
 * genau der Sprung, den diese Zone verhindern soll. Sie sind zusammen rund
 * 340 px breit und passen damit auch bei 850 px in eine Zeile.
 */
.plan-ansichten {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: nowrap;
}

/* Weiterhin die Überschrift der Seite, nur in Arbeitsgröße statt in
   Plakatgröße. Sie steht zwischen den Blätterschaltflächen und nennt den
   Zeitraum, den man gerade sieht. */
/*
 * `tabular-nums`: Ziffern gleicher Breite. Ohne sie ist „2027" um gut einen
 * Pixel breiter als „2026" – gemessen am 27.08.2026 –, und die
 * Datumsangaben verschöben beim Blättern alles rechts von sich. Mit ihr ist
 * jedes `tt.mm.–tt.mm.jjjj` gleich breit, ganz ohne reservierten Platz.
 */
.plan-zeitraum {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-stark);
    margin: 0 0.3rem;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: baseline;
}

/*
 * Ein Kasten, so breit wie seine breiteste denkbare Beschriftung.
 *
 * Alle Varianten liegen in derselben Gitterzelle übereinander; die Zelle nimmt
 * die Breite der breitesten an. Gemessen wird das vom Browser – eine geratene
 * Breite in `em` wäre bei anderer Schrift oder Zoomstufe wieder falsch.
 *
 * `align-items: baseline` hält die sichtbare Variante auf der Grundlinie der
 * Zeile; ohne das säße sie in der Zelle oben.
 */
.stabil {
    display: inline-grid;
    align-items: baseline;
    justify-items: start;
}
.stabil > * { grid-area: 1 / 1; white-space: nowrap; }
.stabil-platz { visibility: hidden; }
.plan-zusatz { font-weight: 400; color: var(--text-leise); font-size: 0.88rem; }
/* „heute" als Marke statt als eigener Absatz – der kostete eine ganze Zeile. */
/*
 * Sie steht in jeder Woche im Markup und ist außerhalb der aktuellen nur
 * unsichtbar. Weggelassen gab sie ihre Breite frei und schob die
 * Blätterschaltflächen um 58,9 px – bei jedem Sprung in die aktuelle Woche
 * hinein und wieder heraus.
 *
 * Reservierter Platz kostet etwas, also ist die Marke so knapp gehalten, wie
 * sie lesbar bleibt: ohne Sperrung, mit engem Innenabstand.
 */
.plan-heute {
    flex: 0 0 auto;
    margin-left: 0.4rem;
    padding: 0.05rem 0.3rem;
    border-radius: 3px;
    background: var(--info-flaeche-zart);
    color: var(--info-marke);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
}
.plan-heute-still { visibility: hidden; }

/* ── Was es nur auf dem Telefon gibt ──────────────────────────────────────
 *
 * Fünf Bausteine aus Issue #44 stehen unverändert im Markup der
 * Sendeplan-Ansichten und sind am Schreibtisch schlicht nicht da: der
 * Tagesstreifen und die beiden Schalter „Ansicht" und „Details" mit ihren
 * Kästchen.
 *
 * `display: none` und nicht `visibility: hidden`: Sie reservieren keinen
 * Platz, sie sollen am Schreibtisch gar nicht vorkommen. Gemessen bedeutet das
 * null Abweichung – ein Element ohne Kasten verschiebt nichts.
 *
 * Sie stehen hier zusammen und nicht bei ihren jeweiligen Nachbarn, weil sie
 * eine gemeinsame Aussage haben: Der Schreibtisch bleibt, wie er war. Was aus
 * ihnen auf dem Telefon wird, steht im Block `@media (max-width: 640px)`.
 *
 * `.termin-nebensache` fehlt in dieser Liste mit Absicht: Die Angaben, die sie
 * auszeichnet, sind am Schreibtisch sichtbar wie zuvor. Die Klasse trägt dort
 * keine einzige Regel.
 */
.tagesstreifen,
.plan-werkzeug-schalter,
.plan-werkzeug-taste,
.plan-nebensachen-schalter,
.plan-nebensache-taste { display: none; }

/* Die Werkzeugleiste: eine Zeile, wo sie hinpasst, sonst kontrollierter
   Umbruch. Sie trägt nur noch Bedienelemente. */
/* 0,6 rem statt 0,8: Die Leiste war bei 1024 px um sieben Pixel zu breit für
   eine Zeile – gemessen am 27.08.2026. Zusammen mit dem etwas knapperen
   Innenabstand der Schalter passt sie dort jetzt hinein. Die Höhe der Schalter
   und damit die Trefferfläche bleibt unverändert. */
.plan-werkzeuge {
    display: flex;
    align-items: center;
    gap: 0.5rem 0.6rem;
    flex-wrap: wrap;
    margin-bottom: 0.35rem;
    /* Eine feste Zeilenhöhe, weil die Tagesansicht keine Zeitskala hat: Ihr
       höchstes Bedienelement ist einen Pixel niedriger als das der
       Wochenansicht, und der Rasterbeginn wanderte beim Umschalten genau um
       diesen Pixel. Reserviert ist er ohnehin. */
    min-height: 2rem;
}
.plan-werkzeuge:empty { display: none; }

/* Beschriftung vor einer Schaltergruppe. Sie trägt das Wort, das sonst in
   jedem einzelnen Schalter stünde – einmal statt zweimal, und die Gruppe
   bleibt trotzdem als Ganzes benannt (`aria-labelledby`). */
.werkzeug-feld { display: inline-flex; align-items: center; gap: 0.4rem; }
.werkzeug-titel { font-size: 0.8rem; color: var(--text-leise); white-space: nowrap; }
/* Unsichtbar, aber der Platz bleibt – und aus Tabreihenfolge und Vorlesefluss
   ist der Inhalt damit ebenfalls heraus. */
.werkzeug-feld-still { visibility: hidden; }

/*
 * Die Fußnotenzeile: links die Einordnung, rechts die Zahlen.
 *
 * Immer genau eine Zeile hoch. Das ist der Preis dafür, dass kein Umschalter
 * etwas verschiebt – Vorschau-Erklärung, Dauer-Hinweis und Statistik sind
 * unterschiedlich lang und bräuchten sonst je nach Zustand eine Zeile mehr
 * oder weniger. Was nicht hineinpasst, endet mit Auslassungspunkten; der
 * vollständige Text steht im `title`.
 */
.plan-fussnote {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin: 0 0 0.45rem;
    font-size: 0.82rem;
    line-height: 1.35;
    color: var(--text-normal);
    min-height: 1.35em;
}
.plan-notiz {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--warnung-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.plan-statistik { flex: 0 0 auto; white-space: nowrap; }
.plan-statistik .still { color: var(--text-still); }

/* Nur für Vorlesesoftware – die Beschriftung des Datumsfeldes braucht keinen
   Platz mehr, das Feld erklärt sich selbst. */
.nur-vorlesen {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.sendeplan-steuerung { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.schalter-gruppe {
    display: inline-flex;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    overflow: hidden;
    background: var(--flaeche-karte);
}
.schalter {
    /* Waagerecht knapper, senkrecht unverändert: Die Trefferfläche für Finger
       hängt an der Höhe, die Breite einer Werkzeugleiste an der Breite. */
    padding: 0.4rem 0.75rem;
    font-size: 0.85rem;
    color: var(--text-normal);
    text-decoration: none;
    border-right: 1px solid var(--rand);
    /*
     * Ein fester Schriftschnitt für alle Zustände.
     *
     * Zuvor trug allein der aktive Schalter 600 und alle übrigen 400. Fetter
     * Text ist breiter: „Öffentliche Vorschau" maß aktiv 162,91 px und inaktiv
     * 152,39 px, „Intern" 65,95 gegen 62,95. Beim Umschalten wuchs die Gruppe
     * dadurch um 7,5 px, und weil sie rechtsbündig steht, schob sie die
     * Gruppe „Tag/Woche" daneben um genau diese 7,51 px nach links – im
     * Browser gemessen.
     *
     * Ein konstantes Gewicht löst das an der Ursache, ohne mit Margins oder
     * Transformationen nachzuhelfen. Erkennbar bleibt der aktive Zustand
     * ohnehin: dunkle Fläche, weiße Schrift.
     */
    font-weight: 500;
}
.schalter:last-child { border-right: none; }
.schalter:hover { background: var(--flaeche-zart); }
/* Farbe und Fläche tragen den Zustand – nie die Maße. */
.schalter-aktiv { background: var(--fuellung); color: var(--fuellung-text); }
.schalter-aktiv:hover { background: var(--fuellung); }
.schalter:focus-visible { outline: 2px solid var(--kontur); outline-offset: -2px; }

/* Eine eigene Zone: Sie darf als Ganzes umbrechen, aber nicht in sich. */
.datumswahl { display: flex; align-items: center; gap: 0.4rem; flex-wrap: nowrap; }

/*
 * Wege, die es nur ohne JavaScript braucht. Ausgeblendet wird über die Klasse
 * am `<html>` und damit im Stylesheet – vor dem ersten Zeichnen. Ein Skript am
 * Seitenende zeigte sie erst und nahm sie dann weg; in diesem Moment konnte
 * die Zeile umbrechen.
 */
.js .datum-los,
.js .skala-los { display: none; }
.datumswahl label { font-size: 0.82rem; color: var(--text-leise); }
.datumswahl input[type="date"] {
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--rand-stark);
    border-radius: 5px;
    font-size: 0.85rem;
    font-family: inherit;
}

/* Tagesansicht */
.terminliste { list-style: none; display: flex; flex-direction: column; gap: 0.4rem; }
.termin {
    display: flex;
    align-items: stretch;
    gap: 0.9rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
}
.termin:hover { border-color: var(--rand-akzent); }
.termin-intern { background: var(--flaeche-still); }

.termin-zeit { min-width: 6.5rem; display: flex; flex-direction: column; }
.zeit-haupt { font-size: 1.05rem; font-weight: 700; color: var(--text-stark); font-variant-numeric: tabular-nums; }
.zeit-toleranz, .zeit-ende { font-size: 0.72rem; color: var(--text-still); }

.termin-farbe { width: 4px; border-radius: 2px; flex-shrink: 0; }

.termin-inhalt { flex: 1; min-width: 0; }
.termin-titel { font-size: 0.98rem; font-weight: 600; color: var(--text-stark); }
.termin-moderator { font-size: 0.85rem; color: var(--text-leise); margin-top: 0.1rem; }
.termin-merkmale { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.4rem; }
.merkmal {
    font-size: 0.74rem;
    background: var(--flaeche-sanft);
    color: var(--text-mittel);
    border-radius: 999px;
    padding: 0.1rem 0.5rem;
}
.merkmal-still { background: transparent; color: var(--text-still); padding-left: 0; }
.merkmal-zeittext { background: var(--warnung-flaeche-zart); color: var(--warnung-text-tief); }
.merkmal-verborgen { background: var(--flaeche-sanft); color: var(--text-leise); }   /* kein Fehler – nur intern */
.termin-aktion { display: flex; align-items: center; }

.badge-wdh { background: var(--info-flaeche); color: var(--info-text); margin-left: 0.4rem; }

/*
 * Im Wochenraster ist das Kennzeichen kleiner und enger – es soll im knappen
 * Block neben den Titel passen, nicht ihn verdrängen. Die runde Form und die
 * Farbe bleiben, damit es dasselbe Zeichen ist wie überall sonst.
 */
.block .badge-wdh {
    /* Rechts stabil: Das Kennzeichen schrumpft nie und sitzt am Rand. */
    flex: 0 0 auto;
    padding: 0 0.3rem;
    font-size: 0.85em;
    /*
     * Die Zeilenhöhe wird geerbt und nicht eigens gesetzt. Mit einem eigenen
     * Wert war der Zeilenkasten des Kennzeichens höher als der des Titels: Im
     * knappen Block – 24 px, in denen Uhrzeit und Titel schon fast aufgehen –
     * wuchs die Titelzeile dadurch über den Kasten hinaus, und das Kennzeichen
     * wurde unten angeschnitten. Geerbt bleibt es innerhalb der Zeile, ohne
     * einen Millimeter Höhe zu kosten.
     */
    line-height: inherit;
    margin-left: auto;
}
.block-knapp .badge-wdh,
.block-spuren-viele .badge-wdh { padding: 0 0.22rem; font-size: 0.9em; }
.badge-hinweis { background: var(--warnung-flaeche); color: var(--warnung-text); margin-left: 0.4rem; }

.musikmix-hinweis {
    margin-top: 1.4rem;
    padding: 0.8rem 1rem;
    background: var(--flaeche-sanft);
    border-radius: 8px;
    font-size: 0.88rem;
    color: var(--text-mittel);
}

/* ── Bestätigung der internen Zielzeit ─────────────────────── */

.zeit-eingabe {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.zeit-eingabe input[type="time"] { width: auto; }
.zeit-bestaetigt {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--erfolg-kraeftig);
}
/* Ohne gewählte Uhrzeit ist es keine Bestätigung, sondern ein Hinweis. */
.zeit-bestaetigt-leer { color: var(--warnung-mittel); font-weight: 500; }

/* ── Gleiche Inhalte hervorheben ───────────────────────────── */

/*
 * Ein Klick auf einen Programmpunkt zeigt, wo derselbe Inhalt in der gerade
 * sichtbaren Ansicht noch vorkommt. Zusammengehörig sind die Vorkommen über
 * die Inhaltskennung, nie über den Titel.
 *
 * Die Auswahl arbeitet mit dem Gegensatz zum Umfeld statt mit einer eigenen
 * Farbe: Die Gruppe bleibt voll da und bekommt eine deutliche, aber neutrale
 * Kontur, alles andere tritt zurück. Bewusst kein Rot – das trägt hier bereits
 * den Konflikt.
 *
 * Zurückgenommen, nicht ausgeblendet: Bei dieser Deckkraft bleibt jede Zeile
 * lesbar und der Plan überblickbar. Die Regeln hängen ausschließlich am
 * Planbehälter – Zeitachse, Tagesköpfe, Werkzeugleiste und Navigation liegen
 * außerhalb und bleiben unberührt.
 */
[data-rgs-plan] { --rgs-abblendung: 0.35; }

[data-rgs-plan].hat-inhalt .block:not(.ist-inhalt),
[data-rgs-plan].hat-inhalt .termin:not(.ist-inhalt) {
    opacity: var(--rgs-abblendung, 0.35);
    transition: opacity 0.18s ease;
}

/* Die Kontur liegt als innerer Schein im Kasten und verschiebt deshalb nichts. */
[data-rgs-plan].hat-inhalt .block.ist-inhalt,
[data-rgs-plan].hat-inhalt .termin.ist-inhalt {
    opacity: 1;
    box-shadow: inset 0 0 0 2px var(--kontur);
    /* Über den abgeblendeten Nachbarn, damit die Kontur nirgends angeschnitten wird. */
    z-index: 5;
}
/* Der Hoverschatten des Wochenblocks darf die Kontur nicht ersetzen. */
[data-rgs-plan].hat-inhalt .block.ist-inhalt:hover {
    box-shadow: inset 0 0 0 2px var(--kontur), var(--schatten-block);
}

/* Bedienbar heißt auch: sichtbar, sobald man mit der Tastatur dort ist. */
[data-rgs-inhalt] { cursor: pointer; }
[data-rgs-inhalt]:focus-visible {
    outline: 2px solid var(--kontur);
    outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
    [data-rgs-plan].hat-inhalt .block:not(.ist-inhalt),
    [data-rgs-plan].hat-inhalt .termin:not(.ist-inhalt) { transition: none; }
}

/* Eine Einordnung, keine Warnung und kein Erfolg: Sie sagt, was gerade gilt. */
.meldung-hinweis {
    background: var(--flaeche-zart);
    border: 1px solid var(--rand-sanft);
    color: var(--text-normal);
}

/* ── Ausgefallene Termine ──────────────────────────────────── */

/*
 * Ein gestrichener Termin ist Planungsinformation, kein Programm. Er muss
 * deshalb erkennbar sein, ohne wie ein Programmpunkt auszusehen: gestrichelte
 * Kante statt voller, gedämpfte Farbe, durchgestrichener Titel.
 *
 * Er liegt über den freien Streifen (z-index 0) und unter den echten Blöcken
 * (z-index 2): Wo zur selben Zeit etwas läuft, gehört dem Laufenden die
 * Aufmerksamkeit. Dass die Zeit trotzdem als frei gilt, entscheidet nicht das
 * CSS, sondern die Rechnung – ein Ausfall belegt keine Sendezeit.
 */
.block-ausfall {
    z-index: 1;
    background: var(--ausfall-flaeche);
    border: 1px dashed var(--ausfall-rand);
    border-left: 3px dashed var(--ausfall-rand);
    color: var(--ausfall-text);
    box-shadow: none;
}
.block-ausfall .block-titel { text-decoration: line-through; }
.block-ausfall:hover { z-index: 6; border-color: var(--ausfall-rand-hover); }

.badge-ausfall {
    flex: 0 0 auto;
    line-height: inherit;
    margin-left: auto;
    background: var(--flaeche-sanft);
    color: var(--text-leise);
    border: 1px solid var(--ausfall-marke-rand);
}

/*
 * Im Wochenraster ist die Marke kleiner und enger – dieselbe Behandlung, die
 * das Wiederholungskennzeichen in #11 bekommen hat, und aus demselben Grund.
 *
 * `.badge` setzt eine **absolute** Schriftgröße von 0,78 rem. Ein knapper Block
 * steht aber bei 0,6 rem: Die Marke war damit größer als der Text um sie herum,
 * 19,88 px hoch und höher als eine Textzeile. Sie schob den Titel 5,4 px tiefer
 * als im normalen Block derselben Höhe – gemessen am 28.08.2026 –, und dort
 * wurde er unten angeschnitten.
 *
 * `0.85em` statt `0.78rem` ist der ganze Unterschied: Die Marke wächst und
 * schrumpft jetzt mit ihrem Block. Dazu die geerbte Zeilenhöhe und kein
 * Rahmen, der zwei weitere Pixel kostet. Die Farbe bleibt und trägt allein –
 * sie hebt sich auch ohne Kante vom hellen Untergrund des Platzhalters ab.
 */
.block .badge-ausfall {
    padding: 0 0.3rem;
    font-size: 0.85em;
    border: 0;
    background: var(--ausfall-marke-flaeche);
    color: var(--ausfall-marke-text);
}

/*
 * Die Wiederherstellen-Schaltfläche sitzt wie der Stift in der Ecke – und
 * bleibt es auch im knappsten Block.
 *
 * Ich hatte sie dort zunächst ausgeblendet, weil sie im engen Slot zu drängen
 * schien. Nachgesehen: `.block-link` ist absolut positioniert und bis zum
 * Überfahren unsichtbar. Sie nimmt also gar keinen Platz in der Zeile und
 * drängt nichts. Das Ausblenden hätte eine funktionierende Aktion aus einer
 * Vermutung heraus entfernt.
 */
.block-ausfall-aktion { display: contents; }
.block-ausfall-aktion .block-link {
    background: none;
    border: 0;
    cursor: pointer;
    font: inherit;
}

/* In der Tagesliste ist es eine eigene Zeile, kein Untergrund. */
.termin-ausfall {
    background: var(--ausfall-flaeche);
    border-style: dashed;
    color: var(--ausfall-text);
}
.termin-ausfall .ausfall-titel { text-decoration: line-through; }
.termin-ausfall .termin-zeit { color: var(--ausfall-text); }
.ausfall-aktion { display: flex; align-items: center; padding-right: 0.8rem; }

/*
 * Die Rückmeldung einer Aktion, mit ihrer Umkehrung daneben. Sichtbar, aber
 * nicht aufdringlich: Es ist eine Bestätigung, keine Warnung.
 */
.plan-band {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 0.5rem;
    padding: 0.5rem 0.8rem;
    border-radius: 6px;
    font-size: 0.86rem;
    background: var(--flaeche-zart);
    border: 1px solid var(--rand-sanft);
    color: var(--text-normal);
}
/*
 * `display: flex` schlägt das eingebaute `[hidden] { display: none }` des
 * Browsers – ein verstecktes Band stünde sonst weiter da. Deshalb hier
 * ausdrücklich; das Auswahlband unten wird genau so ein- und ausgeblendet.
 */
.plan-band[hidden] { display: none; }
.plan-band-ausgefallen { background: var(--band-ausfall-flaeche); border-color: var(--band-ausfall-rand); color: var(--band-ausfall-text); }
.plan-band-text { flex: 1 1 auto; min-width: 0; }
.plan-band-aktion { flex: 0 0 auto; }

/*
 * Welche Sendung gerade hervorgehoben ist – Issue #73.
 *
 * Dieselbe Zeile wie die Rückmeldung darüber, nur mit der Kontur der Auswahl
 * als linker Kante. Damit sagt die Farbe dasselbe wie der innere Schein an den
 * markierten Blöcken: *das* ist die Auswahl. Beide holen sie aus `--kontur` und
 * folgen damit von selbst dem hellen wie dem dunklen Modus.
 *
 * Es ist eine Einordnung und keine Meldung: kein Erfolgsgrün, kein Warngelb.
 */
.plan-band-auswahl { border-left: 3px solid var(--kontur); }

/*
 * Sein Platz ist die Unterkante der Arbeitsfläche – an jeder Breite.
 *
 * Bis zur Nacharbeit zu Issue #91 war das eine Frage des Geräts: Auf dem
 * Telefon stand das Band seit #85 außerhalb des Flusses, am Schreibtisch bekam
 * es mit `flex: 1 0 100%` die ganze Zeilenbreite der Kopfzeile und brach damit
 * in eine eigene Zeile um. Gemessen kostete das dort 49 px – die Kopfzeile
 * wuchs beim Auswählen von 62 auf 111 px, der ganze Plan rutschte um genau
 * diesen Betrag nach unten und beim Aufheben wieder zurück. Es ist derselbe
 * Sprung, den #85 auf dem Telefon abgeschafft hat, nur eine Bildschirmgröße
 * weiter; also gilt jetzt überall dieselbe Antwort.
 *
 * Zwei Regeln tragen sie. Die Leiste steht `position: absolute` an der
 * Unterkante der Arbeitsfläche, deren Unterkante zugleich die der Ansicht ist –
 * die Seite ist genau fensterhoch (`.seite-fest`). Und ihr Platz wird unten
 * frei gemacht statt oben (siehe die `:has()`-Regeln unten): Der Scrollbereich
 * wird kürzer, sein Inhalt beginnt aber weiter an derselben Stelle. Kein Kasten
 * wandert, weder beim Setzen noch beim Wechseln noch beim Aufheben.
 *
 * Die linke und rechte Kante kommen aus derselben Polsterung, die
 * `.seite-wrapper` setzt: Die Leiste steht damit auf den Kanten der Karten
 * darüber und nicht ein paar Pixel daneben.
 *
 * Sichtbar unterscheiden sich Schreibtisch und Telefon weiterhin – dort die
 * beschriftete Schaltfläche „Auswahl aufheben“ und das Wort „Auswahl:“, hier
 * das „×“ mit 44-px-Tippziel. Das steht in `@media (max-width: 640px)`; die
 * Lage der Leiste steht hier und nur hier.
 */
.plan-kopfzeile > .plan-band-auswahl {
    position: absolute;
    left: var(--seiten-polster);
    right: var(--seiten-polster);
    bottom: 0;
    /* Über dem Plan – die markierten Blöcke liegen auf 5. */
    z-index: 6;
    margin: 0;
    min-height: var(--auswahlleiste);
    min-width: 0;
    flex-wrap: nowrap;
    gap: 0.4rem;
    /* Die Höhe trägt das Tippziel; ein eigenes Polster käme oben und unten
       dazu. Seitlich bleibt es, damit der Name nicht an der Auswahlkontur und
       der Ausstieg nicht an der rechten Kante klebt. */
    padding: 0 0.6rem;
    /* Sie liegt über dem Programm: Der Schatten trennt sie von dem, was
       darunter durchscrollt. `.plan-band` deckt mit `--flaeche-zart` bereits
       vollflächig – durchscheinen soll hier nichts. */
    box-shadow: 0 -2px 10px -6px rgba(0, 0, 0, 0.45);
}

/*
 * Name und Zusatz nebeneinander, und der Name ist der, der nachgibt.
 * `min-width: 0` hebt die Vorgabe auf, dass ein Flex-Element nicht unter seinen
 * Inhalt schrumpft – ohne sie schöbe ein langer Titel die Leiste über den Rand
 * hinaus, statt sich kürzen zu lassen.
 */
.plan-band-auswahl .plan-band-text {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.3rem;
    min-width: 0;
}
.plan-band-auswahl [data-rgs-auswahl-titel] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* „– in diesem Zeitraum nicht im Plan" ist der Satz, für den es das Band
   überhaupt gibt. Er wird nicht gekürzt, sondern rutscht neben einem langen
   Namen unter ihn – daher `flex-wrap` oben. Zwei kurze Zeilen sind in einer
   44 px hohen Leiste kostenlos; ein in vier Stücke gebrochener Halbsatz wäre es
   nicht. Der Name darüber bleibt dabei immer **eine** Zeile – er wird gekürzt,
   nicht umgebrochen. */
.plan-band-auswahl .plan-auswahl-leer { flex: 0 0 auto; max-width: 100%; }

/*
 * Der Platz für die Leiste – und zwar nur, solange es eine Auswahl gibt.
 *
 * Dauerhaft reserviert wäre es dieselbe verschenkte Zeile, die hier gerade
 * abgeschafft wird. `:has()` fragt den einen Zustand ab, der darüber
 * entscheidet, und zwar denselben, den Server und Skript ohnehin über das
 * `hidden` am Band führen – kein zweiter Schalter, der auseinanderlaufen
 * könnte.
 */
.sendeplan-arbeitsflaeche:has(.plan-band-auswahl:not([hidden])) {
    padding-bottom: calc(var(--auswahlleiste) + 0.5rem);
}

/* Der Zusatz für eine Woche, in der die Auswahl nicht vorkommt. Er tritt
   zurück – die Auswahl gilt weiter, hier läuft sie nur nicht. */
.plan-auswahl-leer { color: var(--text-leise); }

/* Das „×" ist die Telefonfassung von „Auswahl aufheben". Am Schreibtisch ist
   Platz für Worte; dort nimmt es keinen. */
.plan-aktion-kurz { display: none; }

/* Die Aktion im Programmeditor – abgesetzt vom Formular, weil sie keine
   Variante des Speicherns ist. */
/*
 * Die Sonderaktion zum Ausfallenlassen.
 *
 * Sie gehört zum Speicherbereich darüber, nicht in eine eigene Zone: knapper
 * Abstand, knappe Polsterung – und dieselben Außenkanten wie der Formularkasten
 * über ihr. Sie steht zwar außerhalb des `<form>` (Absagen ist keine Variante
 * des Speicherns), aber im selben Raster: gleiche linke, gleiche rechte Kante.
 *
 * Text links, die Schaltfläche rechts auf der Grundlinie der letzten Zeile.
 * Sie bleibt in Warnfarbe, aber ohne Nachdruck: Wer hier landet, hat den Modus
 * „Nur diesen Termin" schon bewusst gewählt.
 */
.einzelaktion {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: end;
    column-gap: 1rem;
    row-gap: 0.15rem;
    /*
     * Die Breite steht hier nicht mehr.
     *
     * Sie kam schon immer aus dem Formular daneben (Issue #66, Nacharbeit nach
     * Martins Sichtprüfung) – dazwischen stand hier eine eigene, engere
     * Höchstbreite von 660 px: so breit, wie der Inhalt der Kachel es
     * verlangt. Gemessen war das stimmig, gesehen nicht – die Kachel endete
     * auf dem Laptop 200 px vor dem Formularkasten und stand als losgelöste
     * Karte daneben statt im Raster. Beurteilt wird das Bild, nicht die
     * Messung.
     *
     * Seit Issue #76 ist das keine Sonderregel dieser einen Kachel mehr: Die
     * Kachel trägt im Markup `formularflucht` und bekommt ihre Außenkanten aus
     * derselben gemeinsamen Regel wie jeder andere Aktions-, Warn- und
     * Löschbereich der Anwendung. Hier steht nur noch, wie sie innen aussieht.
     */
    margin-top: 0.35rem;
    padding: 0.55rem 0.8rem;
    border: 1px solid var(--gefahr-rand-zart);
    border-radius: 6px;
    background: var(--gefahr-flaeche-zart);
}
.einzelaktion-titel {
    grid-column: 1;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text-stark);
    margin: 0;
}
.einzelaktion-hinweis {
    grid-column: 1;
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--text-leise);
    margin: 0;
}
/* Über beide Textzeilen hinweg, unten bündig mit der letzten. */
.einzelaktion form {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: end;
}
.einzelaktion .schaltflaeche {
    padding: 0.35rem 0.75rem;
    font-size: 0.83rem;
    white-space: nowrap;
}

/* Schmal: Der Text steht oben, die Schaltfläche darunter rechts. Gestapelt,
   aber weiterhin knapp. */
@media (max-width: 620px) {
    .einzelaktion {
        grid-template-columns: 1fr;
        row-gap: 0.5rem;
    }
    .einzelaktion form {
        grid-column: 1;
        grid-row: auto;
        justify-self: end;
    }
}

/* ── Freie Zeiten ──────────────────────────────────────────── */

/*
 * Eine zugeschaltete Zusatzebene, kein zweiter Plan. Sie muss deshalb leiser
 * sein als alles, was Programm ist: keine Fläche, die mit einem Block
 * verwechselt werden kann, keine Farbe, die neben den Typenfarben um
 * Aufmerksamkeit wirbt. Ein schraffierter, heller Untergrund – man sieht ihn,
 * wenn man ihn sucht, und übersieht ihn, wenn man das Programm liest.
 */
.frei-fenster {
    position: absolute;
    left: 0;
    right: 2px;
    z-index: 0;                     /* unter den Blöcken (z-index: 2) */
    border-radius: 3px;
    border: 1px dashed var(--rand-sanft);
    /* Schraffur statt Füllung: eine gefüllte Fläche läse sich als Eintrag. */
    background: repeating-linear-gradient(
        135deg, var(--frei-streifen-hell), var(--frei-streifen-hell) 6px,
        var(--frei-streifen-dunkel) 6px, var(--frei-streifen-dunkel) 12px);
    overflow: hidden;
    pointer-events: none;           /* nichts daran ist bedienbar */
}

/*
 * Beschriftet wird nur, wo der Text hinpasst – ohne Platz bleibt der Streifen
 * mit seinem Tooltip; ein abgeschnittenes „1:4…" hülfe niemandem.
 *
 * `--frei-text-oben` schiebt den Text unter dem Überstand des Blocks darüber
 * hervor. Ein Block wird mindestens 24 px hoch gezeichnet, auch wenn seine
 * Sendezeit nur eine Minute dauert – ohne dieses Ausweichen lag die
 * Beschriftung darunter und war unsichtbar, selbst bei einem 2:44 Stunden
 * langen Fenster. Der Server rechnet den Wert, der Regler führt ihn beim
 * Ziehen nach.
 */
.frei-text {
    display: block;
    margin-top: var(--frei-text-oben, 0px);
    padding: 2px 6px;
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--frei-text);
    white-space: nowrap;
}

/* In der Tagesansicht ist es kein Untergrund, sondern eine eigene Zeile. */
.frei-zeile {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.45rem 0.9rem;
    margin-bottom: 0.35rem;
    border: 1px dashed var(--rand-sanft);
    border-radius: 4px;
    background: repeating-linear-gradient(
        135deg, var(--frei-streifen-hell), var(--frei-streifen-hell) 6px,
        var(--frei-streifen-dunkel) 6px, var(--frei-streifen-dunkel) 12px);
    color: var(--frei-text);
}
.frei-zeile .termin-zeit { color: var(--frei-text); }
.frei-zeile-text { font-weight: 500; }

.frei-schalter { margin-bottom: 0.9rem; }

.frei-hinweis {
    margin: 0.4rem 0 0;
    font-size: 0.8rem;
    color: var(--warnung-text);
}

/*
 * Ausgeschaltet verschwindet die Ebene, ihr Platz aber nicht.
 *
 * `visibility: hidden` und ausdrücklich nicht `display: none`: Nur so behält
 * die Bilanzzeile ihre Breite und der Hinweis seine Höhe. Sonst wuchs die Zeile
 * beim Einschalten um 185 px und wanderte – sie liegt mit `margin-left: auto`
 * rechts – um dieselbe Strecke nach links; in der umbrechenden Werkzeugleiste
 * verschob das bei 900 bis 1100 px die ganze Zeile.
 *
 * Vorgelesen wird ein `visibility: hidden`-Bereich ohnehin nicht; das
 * zusätzliche `aria-hidden` im Markup sagt es nur noch einmal ausdrücklich.
 */
.frei-statistik-still,
.frei-hinweis-still { visibility: hidden; }

/* ── Abgrenzung von Inhalt, Darstellung und Planung ────────── */

/*
 * Ein Hinweis, der einer Verwechslung vorbeugt, statt ein Feld zu erklären.
 * Er tritt deshalb nicht zurück wie die übrigen Hilfetexte, sondern bekommt
 * eine Kante – man soll ihn lesen, bevor man das Datum falsch versteht.
 */
.hinweis-abgrenzung {
    display: block;
    margin-top: 0.4rem;
    padding: 0.45rem 0.6rem;
    border-left: 3px solid var(--rand-akzent);
    background: var(--flaeche-zart);
    border-radius: 3px;
    color: var(--text-mittel);
}

/*
 * Der Planungsabschnitt trägt keine Felder – er sagt nur, wo die dritte Ebene
 * wohnt. Deshalb ohne weiße Fläche: Er ist ein Wegweiser, kein Formularteil.
 */
.abschnitt-verweis {
    background: var(--flaeche-zart);
    border-style: dashed;
}
.abschnitt-verweis legend { color: var(--text-leise); }

/* ── Personenkarten ────────────────────────────────────────── */

.personenkarten {
    display: grid;
    /* Wächst mit dem Fenster; auf schmalen rücken die Karten von selbst
       untereinander. Die Mindestbreite ist an der tatsächlich vorhandenen
       gedeckelt, sonst liefe die Seite bei großer Schrift über. */
    grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
    gap: 1rem;
}

.personenkarte {
    display: flex;
    flex-direction: column;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    overflow: hidden;
    box-shadow: var(--schatten-zart);
}
.personenkarte:hover { border-color: var(--rand-akzent); }

/*
 * Feste Bildfläche mit gleichbleibendem Seitenverhältnis. Ohne sie ruckelten
 * die Karten beim Laden, weil jedes Foto eine andere Höhe mitbrächte.
 *
 * Der Platzhalter liegt darunter: Fehlt das Bild oder lädt es nicht, tritt er
 * hervor, ohne dass sich an der Höhe etwas ändert.
 */
.personenkarte-bild {
    position: relative;
    aspect-ratio: 4 / 3;
    background: var(--flaeche-bild);
    display: flex;
    align-items: center;
    justify-content: center;
}
.personenkarte-bild img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* Füllt die Fläche, ohne zu verzerren – beschnitten statt gequetscht. */
    object-fit: cover;
}
.personenkarte-platzhalter {
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: var(--platzhalter-text);
    user-select: none;
}

.personenkarte-inhalt {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding: 0.85rem 1rem 0.6rem;
    /* Schiebt die Aktionen nach unten, auch bei ungleich langen Texten. */
    flex: 1 1 auto;
}
.personenkarte-name { font-size: 1rem; color: var(--text-stark); }
.personenkarte-oeffentlich { font-size: 0.82rem; color: var(--text-leise); }
.marke-ki { align-self: flex-start; background: var(--warnung-flaeche); color: var(--warnung-text); }

/*
 * Drei Zeilen Vorschau, dann Schluss. Ein langer Text machte sonst eine Karte
 * doppelt so hoch wie ihre Nachbarn – gelesen wird er im Formular.
 */
.personenkarte-vorstellung {
    font-size: 0.85rem;
    line-height: 1.4;
    color: var(--text-leise);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/*
 * Wo die Person noch zugeordnet ist (Issue #80). Ein kleiner Abstand nach oben
 * setzt die Angabe von der Kurzvorstellung ab: Das eine ist Text über den
 * Menschen, das andere eine Auskunft über den Bestand.
 */
.personenkarte-verwendung { margin-top: 0.25rem; }

.personenkarte-aktionen {
    display: flex;
    gap: 0.4rem;
    padding: 0.7rem 1rem;
    border-top: 1px solid var(--rand-zart);
}
.personenkarte-aktionen form { display: inline; }
/* Gesperrt und erkennbar gesperrt – der Grund steht im Titel des Knopfes. */
.personenkarte-aktionen button[disabled] {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ── Bildfeld: URL oder Hochladen, mit Zuschnitt (Issue #67) ─
 *
 * Ein Baustein für vier Masken. Alles darin richtet sich nach der Breite des
 * Behälters und nie nach der des Fensters: Das Feld steht am Schreibtisch in
 * einer breiten Spalte, auf dem Telefon in einer schmalen, und beide Male soll
 * es sich selbst ausmessen. Deshalb `flex-wrap` statt einer Bildschirmabfrage
 * und `aspect-ratio` statt fester Höhen.
 *
 * Das Seitenverhältnis von Bühne und Vorschau steht als `style` am Element und
 * kommt aus `app/bildtypen.py` – es ist je Bildtyp ein anderes und hat in
 * einem Stylesheet nichts verloren.
 */

.bildfeld { display: block; }

.bildfeld-quelle {
    border: 0;
    padding: 0;
    margin: 0 0 0.5rem;
}
.bildfeld-quelle legend {
    padding: 0;
    margin-bottom: 0.35rem;
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--text-normal);
}
/* Die Umschalter nebeneinander – aber in einem eigenen Behälter. Eine
   `legend` in einem Flex-Container wird von Browsern unterschiedlich
   behandelt; das Feld muss überall gleich aussehen. */
.bildfeld-umschalter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 1.2rem;
}
.bildfeld-umschalter .checkbox-label { margin: 0; }

/*
 * Eingabe und Vorschau nebeneinander – solange beide nebeneinander passen.
 * Unter rund 20 rem Feldbreite rückt die Vorschau von selbst darunter; das
 * geht ohne Bildschirmabfrage und richtet sich damit nach dem Platz, den das
 * Feld wirklich hat, und nicht nach der Breite des Geräts.
 */
.bildfeld-koerper {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.8rem;
}
.bildfeld-eingabe { flex: 1 1 12rem; min-width: 0; }
.bildfeld-eingabe input[type="url"],
.bildfeld-eingabe input[type="file"] { width: 100%; }

.bildfeld-unterschrift {
    display: block;
    font-size: 0.82rem;
    color: var(--text-mittel);
    margin-bottom: 0.2rem;
}

.bildfeld-vorschau {
    position: relative;
    flex: 0 0 auto;
    width: 7rem;
    background: var(--flaeche-bild);
    border: 1px solid var(--rand);
    border-radius: 6px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.bildfeld-vorschau img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.bildfeld-vorschau-hinweis {
    font-size: 0.68rem;
    color: var(--text-still);
    text-align: center;
    padding: 0 0.3rem;
}

/* Die Fläche, auf die eine Datei fallen gelassen werden darf. */
.bildfeld-ziel {
    outline: 2px dashed var(--akzent);
    outline-offset: 3px;
    border-radius: 6px;
}

.bildfeld-zuschnitt {
    margin-top: 0.8rem;
    padding: 0.8rem;
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--flaeche-zart);
}
.bildfeld-anleitung {
    margin: 0 0 0.6rem;
    font-size: 0.82rem;
    color: var(--text-mittel);
}

/*
 * Die Bühne. Sie ist so breit wie der Platz hergibt und so hoch, wie ihr
 * Seitenverhältnis es verlangt – auf dem Telefon wird sie damit schmaler und
 * flacher, aber nie unbedienbar und nie breiter als die Seite. Die Obergrenze
 * hält sie am Schreibtisch in einer Größe, die neben das Formular passt.
 */
.bildfeld-buehne {
    position: relative;
    width: 100%;
    max-width: 28rem;
    background: var(--bild-unterlage);
    border-radius: 6px;
    overflow: hidden;
}
.bildfeld-buehne canvas {
    display: block;
    width: 100%;
    height: 100%;
    /* Ohne das rollt das Telefon beim Schieben die Seite statt das Bild. */
    touch-action: none;
    cursor: move;
}

.bildfeld-regler {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 0.6rem;
    max-width: 28rem;
}
.bildfeld-regler label { font-size: 0.82rem; color: var(--text-mittel); }
.bildfeld-regler input[type="range"] { flex: 1 1 auto; min-width: 0; }

.bildfeld-messung {
    margin: 0.5rem 0 0;
    font-size: 0.82rem;
    color: var(--text-mittel);
}
.bildfeld-messung-warnung {
    color: var(--warnung-text);
    background: var(--warnung-flaeche-zart);
    border-left: 3px solid var(--warnung-kraeftig);
    padding: 0.4rem 0.6rem;
    border-radius: 0 4px 4px 0;
}

.bildfeld-aktionen {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.7rem;
}

.bildfeld-meldung {
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.7rem;
    border-radius: 4px;
    font-size: 0.85rem;
    background: var(--fehler-flaeche-zart);
    border: 1px solid var(--fehler-rand);
    color: var(--fehler-text);
}

/* ── Bildvorschau im Personenformular ─────────────────────── */

.foto-eingabe {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
}
.foto-eingabe input { flex: 1 1 auto; min-width: 0; }
.foto-vorschau {
    position: relative;
    flex: 0 0 auto;
    width: 5.5rem;
    aspect-ratio: 4 / 3;
    background: var(--flaeche-bild);
    border: 1px solid var(--rand);
    border-radius: 6px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.foto-vorschau img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.foto-vorschau-hinweis {
    font-size: 0.68rem;
    color: var(--text-still);
    text-align: center;
    padding: 0 0.3rem;
}

/* ── Verwendung: wo ein Stammdatensatz noch hängt ───────────
 *
 * Erst für die Typen gebaut, seit Issue #80 auch auf den Personenkarten. Ein
 * zweiter Satz Klassen daneben hieße, denselben Gedanken zweimal zu pflegen –
 * die Auskunft ist an beiden Stellen dieselbe.
 */

.spalte-zusatz { font-weight: 400; font-size: 0.78rem; color: var(--fuellung-text-still); }

.verwendung { font-size: 0.86rem; }
.verwendung-zahl { display: block; font-weight: 600; color: var(--text-normal); }
.verwendung-namen { display: block; color: var(--text-leise); }
/* Ein unbenutzter Typ ist kein Fehler – nur eine Feststellung. */
.verwendung-frei { color: var(--text-still); font-style: italic; }

.verwendung-liste summary {
    cursor: pointer;
    color: var(--text-leise);
    font-size: 0.82rem;
}
.verwendung-liste ul {
    margin: 0.3rem 0 0 1rem;
    padding: 0;
    color: var(--text-leise);
}

/* Gesperrt und erkennbar gesperrt – der Grund steht im Titel des Knopfes. */
.aktionen button[disabled] {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ── Rollen und Benutzerverwaltung ─────────────────────────── */

.benutzer-rolle {
    margin-left: 0.5rem;
    padding: 0.1rem 0.45rem;
    border: 1px solid rgba(255, 255, 255, 0.35);
    border-radius: 999px;
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.85);
}

/*
 * Marken für Rolle und Status.
 *
 * Ruhige Flächen statt kräftiger Signalfarben: Eine Rolle ist eine Zuordnung
 * und keine Warnung. Nur der Admin bekommt einen wärmeren Ton, weil er der
 * einzige ist, bei dem die Zuordnung eine Folge hat.
 */
.marke {
    display: inline-block;
    padding: 0.12rem 0.55rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}
.marke-rolle { background: var(--flaeche-gewaehlt); color: var(--info-text); }
.marke-rolle-admin { background: var(--fehler-flaeche-zart); color: var(--fehler-text); }
.marke-rolle-moderator { background: var(--flaeche-sanft); color: var(--text-mittel); }
/* Ein technischer Zugang, kein Mensch – deshalb sichtbar anders als die drei
   Rollen darüber und bewusst ohne Alarmfarbe: Er darf ja nichts. */
.marke-rolle-qm { background: var(--erfolg-zart-flaeche); color: var(--erfolg-zart-text); border: 1px dashed var(--erfolg-zart-rand); }
/* Sachlich, nicht alarmistisch – ein deaktivierter Zugang ist kein Fehler. */
.marke-status { background: var(--flaeche-sanft); color: var(--text-leise); border: 1px solid var(--rand); }

/* Die Aktionsspalte einer Zeile, in der nur gelesen werden darf. */
.nur-lesen { font-size: 0.8rem; color: var(--text-still); font-style: italic; }

/* ── Benutzerkarten ────────────────────────────────────────── */

.seite-unterzeile { margin-top: 0.15rem; font-size: 0.88rem; color: var(--text-leise); }

.benutzerkarten {
    display: grid;
    /* Wächst mit dem Fenster und rückt auf schmalen von selbst untereinander –
       ohne eigenen Haltepunkt. `min(...)` deckelt die Mindestbreite an der
       tatsächlich vorhandenen, sonst liefe die Seite bei großer Schrift über. */
    grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr));
    gap: 0.9rem;
    margin-bottom: 1.4rem;
}

.benutzerkarte {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    padding: 1rem 1.1rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    box-shadow: var(--schatten-zart);
}
.benutzerkarte:hover { border-color: var(--rand-akzent); }
/* Zurückgenommen, nicht ausgegraut: Die Angaben bleiben vollständig lesbar. */
.benutzerkarte-inaktiv { background: var(--flaeche-still); }
.benutzerkarte-inaktiv .benutzerkarte-name { color: var(--text-leise); }

.benutzerkarte-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
}
/*
 * Das Profilbild in der Karte. Feste Fläche mit festem Seitenverhältnis, damit
 * die Karten nicht beim Nachladen der Bilder zucken und Karten mit und ohne
 * Bild gleich hoch bleiben.
 *
 * Die Initialen liegen darunter, nicht daneben: Fehlt das Bild oder lädt es
 * nicht, blendet `onerror` das `<img>` aus und der Platzhalter tritt hervor –
 * ohne zweite Fallunterscheidung im Markup.
 *
 * `flex: 0 0 auto`, damit ein langer Name die Bildfläche nicht zusammendrückt.
 */
.benutzerkarte-bild {
    position: relative;
    flex: 0 0 auto;
    width: 2.6rem;
    aspect-ratio: 1;
    border-radius: 50%;
    overflow: hidden;
    background: var(--info-flaeche-zart);
    align-self: center;
}
.benutzerkarte-bild img {
    position: relative;
    width: 100%;
    height: 100%;
    /* Füllt die Fläche, ohne zu verzerren – ein Hochformat wird beschnitten,
       nicht gestaucht. */
    object-fit: cover;
    display: block;
}
.benutzerkarte-platzhalter {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--initialen-text);
    letter-spacing: 0.02em;
}
/* Der Name soll die Marken rechts halten, auch wenn links das Bild steht. */
.benutzerkarte-kopf .benutzerkarte-name { flex: 1 1 auto; min-width: 0; }
.benutzerkarte-inaktiv .benutzerkarte-bild { filter: grayscale(1); opacity: 0.7; }

.benutzerkarte-name { font-size: 1.02rem; color: var(--text-stark); }
.benutzerkarte-marken { display: flex; gap: 0.35rem; flex-wrap: wrap; }

/* Bezeichnung links, Wert rechts – zwei Zeilen, kein Fließtext. */
.benutzerkarte-angaben {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.9rem;
    row-gap: 0.2rem;
    margin: 0;
    font-size: 0.86rem;
}
.benutzerkarte-angaben dt { color: var(--text-still); }
.benutzerkarte-angaben dd { margin: 0; color: var(--text-normal); }
/* Eine lange Adresse bricht um, statt die Karte zu verbreitern. */
.benutzerkarte-mail { overflow-wrap: anywhere; }

.benutzerkarte-aktionen {
    display: flex;
    /* Drei Aktionen passen auf einer schmalen Karte nicht immer nebeneinander –
       bei großer Schrift rutscht die letzte dann in die nächste Zeile, statt
       die Karte zu sprengen. */
    flex-wrap: wrap;
    gap: 0.4rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--rand-zart);
    /* Die Aktionen sitzen unten, auch wenn eine Karte weniger Inhalt hat. */
    margin-top: auto;
}
.benutzerkarte-aktionen form { display: inline; }
.benutzerkarte-aktionen button[disabled] { opacity: 0.45; cursor: not-allowed; }
/* Löschen sitzt abgesetzt am rechten Rand – dieselbe Zeile, aber sichtbar nicht
   dieselbe Art von Aktion wie Bearbeiten und Deaktivieren. Bricht die Zeile auf
   einer schmalen Karte um, bleibt es auch dort rechts. */
.benutzerkarte-loeschen { margin-left: auto; }

.benutzer-fusshinweis { max-width: 46rem; }

/*
 * Der Löschbereich unter dem Benutzerformular.
 *
 * Klar abgesetzt und in gedämpftem Rot, aber ohne Warndreiecke und ohne Kasten
 * in Signalfarbe: Es ist eine seltene, endgültige Handlung – kein Alarm.
 */
.loeschbereich {
    margin-top: 1.6rem;
    padding: 1rem 1.1rem;
    background: var(--gefahr-flaeche-zart);
    border: 1px solid var(--gefahr-rand-zart);
    border-radius: 10px;
}
.loeschbereich h3 {
    margin: 0 0 0.4rem;
    font-size: 1rem;
    color: var(--fehler-text);
}
.loeschbereich p {
    margin: 0 0 0.8rem;
    font-size: 0.88rem;
    color: var(--text-leise);
    max-width: 44rem;
}
/* Steht ein Hindernis da, folgt keine Schaltfläche – dann trägt der Absatz
   allein und braucht keinen Abstand nach unten. */
.loeschbereich p:last-child { margin-bottom: 0; }

/* Die Rollen im Formular – untereinander statt als Textwand. */
.rollen-erklaerung {
    list-style: none;
    display: grid;
    gap: 0.3rem;
    margin: 0.4rem 0 0;
    padding: 0;
    font-size: 0.85rem;
    color: var(--text-leise);
}
.rollen-erklaerung li {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* ── Umfang einer Bearbeitung: Serie oder einzelner Termin ─── */

/*
 * Die Frage steht ganz oben im Formular, weil sie alles darunter betrifft. Zwei
 * gleichwertige Karten nebeneinander, auf schmalen Fenstern untereinander – die
 * Auswahl soll gelesen und nicht überflogen werden.
 */
.umfang-wahl {
    border-color: var(--rand-akzent);
    background: var(--flaeche-zart);
}
.umfang-optionen {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    gap: 0.6rem;
}
.umfang-option {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas: "radio titel" ".     satz";
    column-gap: 0.55rem;
    row-gap: 0.15rem;
    align-items: baseline;
    padding: 0.7rem 0.85rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    background: var(--flaeche-karte);
    cursor: pointer;
}
.umfang-option:hover { border-color: var(--rand-akzent); }
/* Die gewählte Karte hebt sich ab, ohne die andere zu verstecken. */
.umfang-option:has(input:checked) {
    border-color: var(--kontur);
    box-shadow: inset 0 0 0 1px var(--kontur);
}
.umfang-option input { grid-area: radio; margin: 0; }
.umfang-titel {
    grid-area: titel;
    font-weight: 600;
    color: var(--text-stark);
}
.umfang-satz {
    grid-area: satz;
    font-size: 0.85rem;
    line-height: 1.4;
    color: var(--text-leise);
}
.umfang-hinweis {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0.7rem 0 0;
    padding: 0.55rem 0.7rem;
    border-left: 3px solid var(--akzent);
    background: var(--flaeche-karte);
    border-radius: 3px;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--text-normal);
}

/*
 * Serienfelder im Einzelterminmodus: sichtbar, aber erkennbar außer Betrieb.
 * Ausgeblendet wären sie schlechter – man soll sehen, was zur Serie gehört und
 * warum es hier nicht zur Wahl steht.
 */
.serienbereich-gesperrt { opacity: 0.55; }
.serienbereich-gesperrt legend { color: var(--text-leise); }
.serienbereich-sperre {
    margin: 0 0 0.8rem;
    padding: 0.55rem 0.7rem;
    border-left: 3px solid var(--rand-still);
    background: var(--flaeche-sanft);
    border-radius: 3px;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--text-normal);
    /* Der Hinweis bleibt lesbar, auch wenn der Abschnitt zurücktritt. */
    opacity: 1;
}

/* ── Wochenansicht: Stundenraster ─────────────────────────── */
/*
 * Der Arbeitsbereich des Sendeplans – für Tages- und Wochenansicht derselbe.
 *
 * Zuvor lag die Wochenansicht auf `seite-wrapper-voll` und die Tagesansicht auf
 * `seite-wrapper-breit` (1400 px, mittig). Auf einem 2560 px breiten Monitor
 * begann die eine bei 8 px und die andere bei 580 px: Beim Umschalten sprang
 * die gesamte Oberfläche einschließlich Kopfzeile und Schaltern um über einen
 * halben Bildschirm.
 *
 * Beide nutzen jetzt dieselbe äußere Geometrie. Kopfzeile, Navigation und
 * Schalter stehen dadurch in beiden Ansichten an derselben Stelle – das ist die
 * Bedingung dafür, dass der Wechsel ruhig wirkt.
 *
 * Der Klassenname sagt, worum es geht, statt eine Breite zu beschreiben: Dies
 * ist die Fläche, auf der geplant wird. Was darin wie breit sein darf,
 * entscheidet die jeweilige Ansicht für sich.
 */
.sendeplan-arbeitsflaeche {
    /* Die Lesebreite einer Inhaltsspalte in diesem Bereich. Sie steht hier,
       weil die Tagesansicht sie braucht und der Wert zur Fläche gehört. */
    --arbeitsflaeche-spalte: 1400px;
    /* Die Höhe der Auswahlleiste steht an genau einer Stelle: Sie ist zugleich
       das Tippziel nach der 44-px-Regel aus #43 und das Maß des Platzes, der
       unten frei gehalten wird. */
    --auswahlleiste: 44px;

    /* Der Bezugspunkt der Auswahlleiste: Sie liegt außerhalb des Flusses an der
       Unterkante dieser Fläche – siehe `.plan-kopfzeile > .plan-band-auswahl`. */
    position: relative;
    max-width: none;
    margin: 0;
    padding: 0 var(--seiten-polster);
}

/*
 * Die Terminliste behält genau ihre bisherige Breite – die Karten sehen aus wie
 * zuvor. Sie steht nur nicht mehr mittig, sondern beginnt am linken Rand des
 * Arbeitsbereichs, dort, wo auch die Wochenansicht beginnt.
 *
 * Der Platz rechts daneben bleibt bewusst frei. Er ist die Stelle, an der
 * später Planungsangaben stehen können; heute erfindet hier nichts eine zweite
 * Spalte, die es fachlich noch nicht gibt.
 */
.sendeplan-arbeitsflaeche .terminliste,
.sendeplan-arbeitsflaeche .leer-hinweis,
.sendeplan-arbeitsflaeche .musikmix-hinweis {
    max-width: min(var(--arbeitsflaeche-spalte, 1400px), 100%);
}

/* Bestandsklasse: außerhalb des Sendeplans unverändert in Gebrauch. */
.seite-wrapper-voll { max-width: none; padding: 0 0.5rem; }

/* ── Regler für die vertikale Zeitskala ───────────────────────────────────
 *
 * Gestreckt wird ausschließlich die Zeitachse des Wochenrasters. Der Regler
 * ändert nichts an Schriftgrößen, Innenabständen oder Breiten – weder an
 * seinen eigenen noch an denen der Programmblöcke.
 *
 * Er sitzt in derselben Zeile wie die übrigen Schalter und übernimmt deren
 * Rahmen, Radius und Schriftgröße: eine Bedienung, kein zweites Formular­gefühl.
 */
.skala-regler {
    display: inline-flex;
    align-items: center;
    /*
     * Auf schmalen Fenstern bricht die Gruppe um, statt über den Rand zu
     * laufen. Bei 390 px maß sie zuvor 417 px und war der einzige Grund, warum
     * die Wochenansicht dort waagerecht überlief – der Rasterkasten selbst
     * scrollt in sich und trägt nichts nach außen.
     */
    flex-wrap: wrap;
    max-width: 100%;
    gap: 0.45rem;
    padding: 0.15rem 0.5rem 0.15rem 0.65rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    background: var(--flaeche-karte);
}
.skala-titel {
    font-size: 0.85rem;
    color: var(--text-normal);
    white-space: nowrap;
}
.skala-taste {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border: 1px solid var(--rand);
    border-radius: 4px;
    background: var(--flaeche-zart);
    color: var(--text-normal);
    font-size: 0.95rem;
    line-height: 1;
    text-decoration: none;
}
.skala-taste:hover { background: var(--flaeche-gewaehlt); border-color: var(--rand-akzent); }
/* Am Anschlag bleibt die Taste sichtbar, aber erkennbar wirkungslos. */
.skala-taste[aria-disabled="true"] { opacity: 0.4; pointer-events: none; }

.skala-schieber {
    /* Wachsen bis 7,5 rem, darunter nachgeben statt hinauszuragen. */
    flex: 0 1 7.5rem;
    width: 7.5rem;
    min-width: 4rem;
    margin: 0;
    accent-color: var(--kontur);
    vertical-align: middle;
}
.skala-wert {
    /*
     * Reservierter Platz für den Zahlenwert.
     *
     * `50 %` braucht weniger Raum als `200 %`. Ohne Reservierung änderte die
     * Anzeige mit jedem Schritt ihre Breite und schöbe die Gruppe daneben. Die
     * 3,2 rem decken den längsten Wert des Bereichs ab – nachgemessen belegt
     * jeder Wert von 50 bis 200 % dieselben 51,19 px. `tabular-nums` sorgt
     * zusätzlich dafür, dass gleich viele Ziffern immer gleich breit sind.
     */
    min-width: 3.2rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-stark);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/*
 * Die Vorschaumarke – und ihr ebenso reservierter Platz.
 *
 * Sie stand zuvor als `::after` im Zahlenfeld selbst. Damit hing ihre Breite am
 * Zahlenwert: Beim Ziehen maß das Feld 99,75 px bei „90 %" und 107,31 px bei
 * „100 %", die Gruppe wuchs entsprechend, und die Nachrichten-Schalter daneben
 * sprangen um 7,57 px – im Browser gemessen.
 *
 * Jetzt ist sie ein eigenes Element mit fester Breite. Der Platz ist in jedem
 * Zustand belegt; sichtbar wird die Marke nur während des Ziehens. Die Gruppe
 * hat dadurch bei jedem Wert und in jedem Zustand dieselben Außenmaße.
 *
 * `visibility` statt `display`: Nur so bleibt der Platz erhalten. Ausgeblendet
 * wäre er weg, und das Springen begänne von vorn.
 */
.skala-vorschau-marke {
    width: 4.2rem;
    flex: 0 0 auto;
    font-size: 0.78rem;
    line-height: 1;
    color: var(--text-leise);
    white-space: nowrap;
    visibility: hidden;
}
.skala-regler-vorschau .skala-vorschau-marke { visibility: visible; }
/*
 * Rückweg auf die Voreinstellung. Etwas breiter als die beiden Pfeiltasten,
 * weil eine Zahl darin steht, sonst dieselbe Formensprache.
 *
 * Auf der Voreinstellung ist die Schaltfläche gefüllt statt hell – dieselbe
 * Auszeichnung, die im Werkzeug auch sonst den aktuellen Zustand anzeigt
 * (`schalter-aktiv`). Sie ist dann nicht bedienbar, denn es gäbe nichts zu tun.
 */
.skala-standard {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 3rem;
    height: 1.5rem;
    padding: 0 0.45rem;
    margin-left: 0.15rem;
    border: 1px solid var(--rand);
    border-radius: 4px;
    background: var(--flaeche-zart);
    color: var(--text-normal);
    font-size: 0.8rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-decoration: none;
    white-space: nowrap;
}
.skala-standard:hover { background: var(--flaeche-gewaehlt); border-color: var(--rand-akzent); }
.skala-standard-aktiv {
    background: var(--fuellung);
    border-color: var(--fuellung);
    color: var(--fuellung-text);
    font-weight: 600;
    pointer-events: none;
}

/*
 * Während gezogen wird, ist zu sehen, dass der Plan eine Vorschau zeigt: Der
 * Regler hebt sich ab, und der Prozentwert wird als vorläufig gekennzeichnet.
 * Beim Loslassen lädt die Ansicht neu, und die Kennzeichnung verschwindet mit
 * ihr – sie braucht kein eigenes Zurücksetzen.
 */
.skala-regler-vorschau {
    border-color: var(--kontur);
    box-shadow: inset 0 0 0 1px var(--kontur);
}

/* Ohne JavaScript die Auslöse-Schaltfläche, mit JavaScript ausgeblendet. */
.skala-los { border-right: none; border-radius: 4px; border: 1px solid var(--rand); }
.skala-los[hidden] { display: none; }

.raster {
    /* Luft über der ersten und unter der letzten Stundenlinie. Ohne sie ragt die
       auf ihre Linie zentrierte 06:00-Marke in die Kopfzeile und wird von der
       sticky Ecke verdeckt. */
    --rand-oben: 0.85rem;
    --rand-unten: 0.85rem;
    overflow: auto;                     /* trägt beide Scrollrichtungen */
    max-height: calc(100vh - 15rem);
    min-height: 22rem;
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--flaeche-karte);
}

.raster-gitter {
    display: grid;
    grid-template-columns: 4.5rem repeat(7, minmax(9.5rem, 1fr));
    grid-template-rows: auto 1fr;
    min-width: 72rem;                   /* darunter wird horizontal gescrollt */
}

/* Kopfzeile: bleibt beim vertikalen Scrollen stehen */
.raster-ecke, .tageskopf { position: sticky; top: 0; z-index: 3; }
.raster-ecke {
    left: 0;
    z-index: 5;                         /* Ecke über beiden Achsen */
    background: var(--flaeche-sanft);
    border-right: 1px solid var(--rand);
    border-bottom: 1px solid var(--rand-stark);
    font-size: 0.7rem;
    color: var(--text-still);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 0.4rem;
}
.tageskopf {
    background: var(--flaeche-zart);
    border-bottom: 1px solid var(--rand-stark);
    border-left: 1px solid var(--raster-spaltenrand);
    padding: 0.5rem 0.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
}
.tageskopf-heute { background: var(--flaeche-gewaehlt); box-shadow: inset 0 -2px 0 var(--kontur); }
.tageskopf-name { font-weight: 600; font-size: 0.92rem; color: var(--text-stark); text-decoration: none; }
.tageskopf-name:hover { color: var(--akzent-text); }
.tageskopf-datum { font-size: 0.78rem; color: var(--text-leise); }
.tageskopf-bilanz { font-size: 0.7rem; color: var(--text-still); }

/* Zeitachse: bleibt beim horizontalen Scrollen stehen */
.zeitachse {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--flaeche-sanft);
    border-right: 1px solid var(--rand);
    /* Der Rand verschiebt die Achse als Ganzes, nicht ihre Beschriftungen:
       06:00 bleibt exakt auf der ersten Stundenlinie der Tagesspalten. */
    margin: var(--rand-oben) 0 var(--rand-unten);
    height: calc(var(--stunden-gesamt) * var(--stunde));
}
.stunde-marke {
    position: absolute;
    right: 0.5rem;
    transform: translateY(-0.5em);
    font-size: 0.72rem;
    color: var(--text-leise);
    font-variant-numeric: tabular-nums;
}

/* Tagesspalten mit Stunden- und Halbstundenlinien */
.tagesspalte {
    position: relative;
    z-index: 1;             /* eigener Stapelkontext: kein Block über die Kopfzeile */
    margin: var(--rand-oben) 0 var(--rand-unten);
    height: calc(var(--stunden-gesamt) * var(--stunde));
    border-left: 1px solid var(--raster-spaltenrand);
    background-image:
        linear-gradient(to bottom, var(--raster-linie-stunde) 1px, transparent 1px),
        linear-gradient(to bottom, var(--raster-linie-halb) 1px, transparent 1px);
    background-size: 100% var(--stunde), 100% calc(var(--stunde) / 2);
}
.tagesspalte-heute { background-color: var(--raster-heute); }

.nachrichten-sammel {
    position: absolute;                 /* top/left/width kommen aus der Spurverteilung */
    z-index: 1;
    box-sizing: border-box;
    overflow: hidden;
    background: var(--info-flaeche-zart);
    border: 1px dashed var(--rand-akzent);
    border-radius: 5px;
    padding: 0.25rem 0.4rem;
    font-size: 0.7rem;
    line-height: 1.25;
    color: var(--text-mittel);
    margin: 0;
}
.nachrichten-titel, .nachrichten-zeit {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.nachrichten-titel { font-weight: 600; color: var(--info-text); }
.nachrichten-zeit { color: var(--text-leise); font-variant-numeric: tabular-nums; }
.nachrichten-sammel-schmal { font-size: 0.62rem; padding: 0.2rem 0.25rem; }

/* Programmblöcke – absolut über dem Raster, verschieben nichts.
   Überschneiden sich zwei gerenderte Rechtecke, liegen sie nebeneinander
   (siehe _visuelle_spuren_verteilen); verdeckt wird nie etwas. */
.block {
    position: absolute;
    z-index: 2;
    overflow: hidden;
    box-sizing: border-box;
    padding: 0.15rem 0.35rem 0.15rem 0.4rem;
    border: 1px solid var(--rand);
    border-left: 3px solid var(--rand-still);
    border-radius: 4px;
    background: var(--flaeche-karte);
    font-size: 0.76rem;
    line-height: 1.25;
    color: var(--text-stark);
}
.block:hover { z-index: 6; box-shadow: var(--schatten-block); }

/*
 * Reihenfolge im Block: Uhrzeit, Titel mit Wiederholungskennzeichen, dann
 * erst die Zusatzangaben.
 *
 * Der Block ist ein umbrechender Flexkasten. Das klingt aufwendiger als es ist
 * und löst genau eine Sache: Die Uhrzeit belegt eine ganze Zeile, Titel und
 * Wiederholungskennzeichen teilen sich die nächste. Das Kennzeichen kostet
 * dadurch keine eigene Zeile und keinen Millimeter Höhe – im knappsten Block
 * gibt es beides nicht.
 *
 * Die Reihenfolge im Markup bleibt dabei unverändert (Uhrzeit, Titel,
 * Kennzeichen). Es kommt kein Umschließer hinzu; die Zeile entsteht allein aus
 * dem Umbruchverhalten.
 */
.block {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    align-content: flex-start;
    column-gap: 0.25rem;
}
.block-zeit, .block-titel {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Eigene Zeile: Die Uhrzeit ist die erste Angabe und teilt sie mit nichts. */
.block-zeit {
    flex: 0 0 100%;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
/*
 * Der Titel gibt nach, das Kennzeichen nicht. `min-width: 0` hebt die Vorgabe
 * auf, dass ein Flexkind nie schmaler wird als sein Inhalt – ohne sie liefe
 * die Kürzung mit Auslassungspunkten ins Leere und der Titel schöbe das
 * Kennzeichen aus dem Kasten.
 */
/*
 * `flex-basis: 0` und nicht `auto` – das ist hier der entscheidende Wert.
 *
 * Mit `auto` ist die Ausgangsbreite die Inhaltsbreite. Ein sehr langer Titel
 * überschreitet damit die Zeile, und ein umbrechender Flexkasten bricht dann
 * um, statt zu schrumpfen: Das Kennzeichen landete auf einer dritten Zeile und
 * damit außerhalb des knappen Kastens. Mit `0` beansprucht der Titel zunächst
 * gar keine Breite, bekommt den Rest nach dem Kennzeichen und kürzt darin mit
 * Auslassungspunkten – genau die gewünschte Rangfolge.
 */
.block-titel { flex: 1 1 0; min-width: 0; color: var(--text-normal); }
.block-voll .block-titel { white-space: normal; }
/* Alles Weitere bekommt wieder eine eigene Zeile. */
.block-zusatz { flex: 0 0 100%; }
.block-moderator, .block-typ, .block-intern-marke {
    /* Sekundäre Angaben – je eine eigene Zeile, sichtbar nur, wo Platz ist. */
    flex: 0 0 100%;
    font-size: 0.68rem;
    color: var(--text-still);
}
.block-intern { background: var(--flaeche-still); }
.block-intern-marke { color: var(--text-still); }

/* Knappe Blöcke: kleinere Schrift, damit Uhrzeit UND Titelanfang in die
   Mindesthöhe von 24 px passen. */
.block-knapp {
    font-size: 0.6rem;
    line-height: 1.05;
    padding: 0.1rem 0.2rem 0.1rem 0.3rem;
}
.block-mittel { font-size: 0.72rem; line-height: 1.2; }

/* Geteilte Spuren sind KEIN Konflikt – nur weniger Platz. Deshalb neutral grau. */
.block-geteilt { border-color: var(--rand-stark); }
.block-spuren-viele { font-size: 0.56rem; line-height: 1.05; padding: 0.08rem 0.12rem 0.08rem 0.25rem; }
.block-spuren-viele .block-link { display: none; }

/* Rot bleibt ausschließlich fachlichen Konflikten vorbehalten. */
.block-konflikt { border-color: var(--akzent); background: var(--gefahr-flaeche-zart); }
.block-konflikt .block-titel { color: var(--fehler-text); }
.badge-konflikt { background: var(--fehler-flaeche); color: var(--fehler-text); margin-left: 0.3rem; font-size: 0.65rem; }

.block-link {
    position: absolute;
    top: 0.1rem;
    right: 0.2rem;
    font-size: 0.75rem;
    color: var(--block-link-farbe);
    text-decoration: none;
    opacity: 0;
    transition: opacity 0.15s;
}
.block:hover .block-link { opacity: 1; }
.block-link:hover { color: var(--akzent-text); }

@media (max-width: 900px) {
    .raster { max-height: calc(100vh - 12rem); }
    .raster-gitter { grid-template-columns: 3.6rem repeat(7, minmax(8.5rem, 1fr)); min-width: 64rem; }
}

/* Farbwahl im Elementformular: Farbwähler, Hex-Feld und Zurücksetzen in einer
   Zeile. Das Textfeld bleibt schmal – es trägt genau sieben Zeichen. */
.farbwahl {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: wrap;
}

.farbwahl input[type="color"] {
	width: 3rem;
	height: 2.2rem;
	padding: 0.1rem;
	cursor: pointer;
}

.farbwahl input[type="text"] {
	width: 9rem;
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}


/* ── Öffentliche Elementfarbe ─────────────────────────────────
 *
 * Der schmale Streifen links am Programmpunkt und die linke Kante des
 * Rasterblocks zeigen die öffentliche Elementfarbe, sofern eine gepflegt ist –
 * sonst weiterhin die Typenfarbe. Welche der beiden gilt, entscheidet das
 * Template; hier steht nur, dass eine gepflegte Farbe sichtbar abgesetzt wird.
 *
 * Es ist ausschließlich eine Darstellungsrangfolge. Die Typenfarbe bleibt
 * unverändert am Typ, die öffentliche Farbe am Element; keine schreibt die
 * andere fort, und keine wird aus der anderen hergeleitet.
 *
 * Eine Eckfahne gibt es in dieser Ansicht bewusst nicht: Der Streifen ist
 * ohnehin da und sagt dasselbe. Die Ecke bleibt der öffentlichen Webseite
 * vorbehalten, wo sie Beiträge von Sendungen unterscheidet.
 */
.termin-farbe-oeffentlich {
    /* Etwas breiter als der Typenstreifen – die redaktionelle Farbe ist die
       Aussage, die man auch öffentlich wiedererkennt. */
    width: 6px;
}

/* ── Schmale Geräte ───────────────────────────────────────────
 *
 * Zwei Dinge waren auf dem Telefon kaputt, beide im Browser nachgemessen.
 *
 * Erstens die Programmpunkte: `.termin-zeit` hatte eine feste Mindestbreite
 * von 6,5 rem und `.termin-aktion` konnte wegen `min-width: auto` nicht unter
 * die Breite der Schaltfläche schrumpfen. Bei 360 px Fensterbreite blieben
 * dem Titel dadurch 24,5 px – der Text lief aus seinem Kasten heraus, und das
 * Wdh.-Kennzeichen dahinter war praktisch nicht mehr zu sehen. Es war nie
 * ausgeblendet; es hatte nur keinen Platz mehr.
 *
 * Zweitens der Fokus-Zoom: Safari auf iOS vergrößert die ganze Seite, sobald
 * ein Formularfeld mit weniger als 16 px Schrift den Fokus bekommt. Sämtliche
 * Felder lagen darunter – das Datumsfeld der Sendeplan-Navigation bei 13,6 px.
 * Der saubere Weg ist die Schriftgröße selbst; `user-scalable=no` oder
 * `maximum-scale=1` kämen nicht in Frage, sie nähmen dem Benutzer das eigene
 * Zoomen.
 */
@media (max-width: 640px) {
    /*
     * Der Kopfbereich auf dem Telefon: eine Zeile.
     *
     * Nachgemessen im Browser, vorher: 203 px hoch bei 390 px Fensterbreite,
     * 256 px bei 375 px – die zehn Bereiche brauchten dort sechs bzw. acht
     * Zeilen. Der Seiteninhalt begann erst bei 235 bzw. 288 px. Wer auf dem
     * Handy nur nachsehen wollte, was der Worker gerade tut, musste vorher
     * scrollen. Jetzt sind es 58 px, der Inhalt beginnt bei 90 px.
     *
     * In der Zeile steht, was man ohne Umweg braucht: Logo, der Schalter für
     * die Bereiche und Abmelden. Die Bereiche selbst sind nicht weg, sie
     * klappen auf Antippen darunter auf – ohne Skript, ohne Hover, ohne eine
     * zweite Navigation. Am Schreibtisch ändert sich nichts: dort war der Kopf
     * mit 62 px immer eine Zeile, und er bleibt es.
     *
     * Klebend bliebe der Streifen auch schmal im Weg, deshalb scrollt er auf
     * schmalen Geräten weiterhin mit.
     */
    .hauptmenue {
        position: static;
        padding: 0.45rem 0.7rem;
        gap: 0.4rem;
    }
    .logo-bild { height: 30px; }
    .untertitel { margin-left: 0.4rem; }
    .menue-rechts { gap: 0.5rem; }

    /*
     * Sichtbar ausgeblendet, für die Tastatur erreichbar: Das Kästchen selbst
     * hat keine Fläche, lässt sich aber anspringen und mit der Leertaste
     * schalten. Es aus der Darstellung zu nehmen nähme es der Tastatur ganz.
     *
     * Genau das war bis hierher der Fall, und es ist im Zuge von #63
     * aufgefallen: Für den Schreibtisch steht weiter oben eine Regel, die
     * Kästchen und Beschriftung aus der Darstellung nimmt – und dieser Block
     * hat sie nie zurückgenommen. Für die Maus fiel das nicht auf, weil die
     * Beschriftung das Kästchen schaltet; für die Tastatur war der Schalter
     * unerreichbar, und die Fokusregel darunter lief ins Leere. Die erste
     * Zeile stellt das richtig.
     */
    .menue-umschalter {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .menue-schalter {
        display: inline-flex;
        align-items: center;
        gap: 0.45rem;
        /* Ein Tippziel, kein Textlink: 44 px sind das Maß, das Apple nennt. */
        min-height: 44px;
        padding: 0 0.7rem;
        border: 1px solid rgba(255, 255, 255, 0.35);
        border-radius: 6px;
        font-size: 0.85rem;
        color: var(--kopf-text-hell);
        cursor: pointer;
        /* Sonst markiert ein zweites Antippen die Beschriftung. */
        -webkit-user-select: none;
        user-select: none;
    }
    .menue-umschalter:focus-visible + .menue-schalter {
        outline: 2px solid var(--kopf-akzent);
        outline-offset: 2px;
    }
    /* Drei Striche aus einem einzigen Kasten. */
    .menue-schalter-strich,
    .menue-schalter-strich::before,
    .menue-schalter-strich::after {
        display: block;
        width: 16px;
        height: 2px;
        background: currentColor;
        border-radius: 2px;
    }
    .menue-schalter-strich { position: relative; }
    .menue-schalter-strich::before,
    .menue-schalter-strich::after {
        content: "";
        position: absolute;
        left: 0;
    }
    .menue-schalter-strich::before { top: -5px; }
    .menue-schalter-strich::after { top: 5px; }

    /* Zugeklappt ist der Ausgangszustand. */
    .menue-nav { display: none; }
    .menue-umschalter:checked ~ .menue-nav {
        display: flex;
        /* Eine eigene Zeile unter dem Kopf, linksbündig statt mittig. */
        flex-basis: 100%;
        justify-content: flex-start;
        gap: 0.2rem;
        padding-top: 0.2rem;
    }
    /*
     * „Mehr" gehört dem Schreibtisch.
     *
     * Auf dem Telefon steht schon der Hamburger; zwei Klappmenüs übereinander
     * wären eine Bedienfalle. Das Skript räumt die Bereiche dort ohnehin
     * zurück in die Leiste – diese Regel ist der Riegel davor, dass beim
     * Drehen des Geräts für einen Wimpernschlag doch etwas stehen bleibt.
     */
    .hauptmenue .menue-mehr,
    .hauptmenue .menue-mehr-liste { display: none; }

    /*
     * Und die Leiste bekommt ihre Zeilen zurück.
     *
     * Für den Schreibtisch schneidet sie ihren Überhang ab, damit `menue.js`
     * ihn einsammeln kann. Hier gibt es niemanden, der einsammelt – hier klappt
     * das Kästchen auf, und dann sollen alle Bereiche untereinander stehen.
     * Dieselbe Klasse, dieselbe Spezifität, nur später im Stylesheet: Es
     * braucht dafür keinen zweiten Breakpoint.
     *
     * Der Boden von 6 rem darf stehen bleiben: Aufgeklappt nimmt die Leiste
     * hier ohnehin die volle Breite (`flex-basis: 100%`), und zugeklappt hat
     * sie gar keinen Kasten. 96 px sind auf keinem Telefon eine Grenze.
     */
    html.js .hauptmenue { flex-wrap: wrap; }
    html.js .menue-nav {
        flex-wrap: wrap;
        overflow: visible;
    }
    html.js .menue-nav > * {
        flex: 0 1 auto;
        white-space: normal;
    }

    /* Aufgeklappt wird getippt, nicht gezeigt: jede Fläche mindestens 44 px. */
    .menue-link {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding: 0 0.7rem;
    }

    /*
     * Abmelden bleibt immer sichtbar – es ist die einzige Bedienung im Kopf,
     * die man auch ohne den Umweg über das Menü braucht. Name und Rolle
     * dagegen kosten auf 390 px mehr Platz, als sie sagen; sie erscheinen mit
     * den Bereichen.
     */
    .abmelden {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding: 0 0.7rem;
    }
    .benutzer,
    .benutzer-rolle { display: none; }
    .menue-umschalter:checked ~ .menue-rechts .benutzer,
    .menue-umschalter:checked ~ .menue-rechts .benutzer-rolle { display: inline; }
    /*
     * Der Verweis nach „Mein Konto" liegt um den Namen herum (Issue #69) und
     * verschwindet mit ihm. Bliebe er stehen, wäre er ein leeres, unsichtbares
     * Tabulatorziel in der Kopfzeile.
     */
    .benutzer-konto { display: none; }
    .menue-umschalter:checked ~ .menue-rechts .benutzer-konto { display: inline; }

    /*
     * Die Maße dieser Regel stammen aus #44: weniger Polster, engere Zeilen.
     * Warum sie hier stehen und nicht im Abschnitt weiter unten – es gibt für
     * einen Selektor eine Regel, nicht zwei, von denen die zweite die erste
     * überschreibt. Die Begründung steht bei „Kompaktere Programmkarten".
     */
    .termin {
        flex-wrap: wrap;
        gap: 0.6rem;
        row-gap: 0.4rem;
        padding: 0.5rem 0.6rem;
    }
    /* Die Uhrzeit braucht keine 6,5 rem – „06:15“ passt in 4,5 rem. */
    .termin-zeit { min-width: 4.5rem; }
    .termin-inhalt { flex: 1 1 8rem; }
    /* Deutsche Zusammensetzungen wie „Landesgartenschau-Wissen“ sind breiter
       als die Spalte. Sie dürfen umbrechen, statt in das Polster zu laufen. */
    .termin-titel,
    .termin-moderator { overflow-wrap: break-word; }
    /* Die Schaltfläche bekommt eine eigene Zeile, statt dem Titel den Platz
       wegzunehmen. Sie verschwindet nicht – sie steht nur darunter. */
    .termin-aktion { flex: 1 1 100%; }

    /* Mindestens 16 px, sonst zoomt iOS beim Antippen die ganze Seite. */
    .formular-zeile input[type="text"],
    .formular-zeile input[type="url"],
    .formular-zeile input[type="number"],
    .formular-zeile input[type="date"],
    .formular-zeile input[type="time"],
    .formular-zeile select,
    .formular-zeile textarea,
    .datumswahl input[type="date"],
    .farbwahl input[type="text"],
    input,
    select,
    textarea {
        font-size: 16px;
    }

    /* ── Mobile Basis, Teil 1: Tippflächen ────────────────────────────────
     *
     * Der Mobile-Audit zu Issue #35 nennt das den Befund mit der größten
     * Reichweite, und er ist keine Sammlung von Einzelfällen, sondern die
     * Grundregel des Stylesheets: `.schaltflaeche` misst 30 px,
     * `.schaltflaeche-klein` 23 px, `.schalter` 29 px, ein Kontrollkästchen
     * 13 × 13 px. „Deaktivieren“ und „Löschen“ stehen in der
     * Benutzerverwaltung mit je 23 px Höhe direkt nebeneinander.
     *
     * 44 px ist das Maß, das Apple nennt, und dasselbe, das die Kopfzeile seit
     * Issue #26 einhält – deshalb steht es hier noch einmal und nicht in einer
     * neuen Zahl.
     *
     * Erreicht wird es über `min-height` und nicht über `padding`: Die
     * Beschriftung bleibt dadurch, wo sie ist, und eine Schaltfläche mit
     * umbrechendem Text wird höher statt gequetscht. `inline-flex` mit
     * `align-items: center` hält den Text dabei in der Mitte der neuen Höhe;
     * ohne das säße er oben.
     *
     * Die Breite bleibt unberührt. Sie ist auf dem Telefon der knappe Wert,
     * und ein Knopf, der über den Rand wächst, wäre kein besseres Tippziel.
     *
     * Warum an der Fensterbreite und nicht an `pointer: coarse`, wie es der
     * Audit vorschlägt: Issue #43 begrenzt dieses Paket ausdrücklich auf
     * schmale Smartphone-Ansichten und verlangt, dass Tablet und Querformat
     * unverändert bleiben. Ein Tablet ist genauso fingerbedient, aber breiter
     * als 640 px – es bleibt damit außen vor. Das ist eine bewusste
     * Entscheidung dieses Pakets, keine vergessene Zeile.
     */
    .schaltflaeche,
    .schalter {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-height: 44px;
    }
    /* Die Anmeldeschaltfläche ist bereits zeilenbreit – sie bleibt ein
       Blockelement, sonst entstünde unter ihr die Grundlinienlücke einer
       Textzeile. */
    .anmelde-button {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 44px;
    }
    /* `.schaltflaeche-klein` ändert nur Polster und Schriftgröße – die
       Mindesthöhe kommt von `.schaltflaeche` und gilt damit auch hier. */

    /*
     * Die Zeitskala des Wochenrasters. Ihre drei Bedienelemente sind mit
     * 24 px die kleinsten Ziele der ganzen Anwendung; `height` ist dort fest
     * gesetzt und muss deshalb ausdrücklich zurückgenommen werden, bevor
     * `min-height` etwas bewirken kann.
     */
    .skala-taste,
    .skala-standard {
        height: auto;
        min-height: 44px;
    }
    .skala-taste { width: 44px; }
    .skala-schieber { min-height: 44px; }

    /*
     * Kontrollkästchen, Auswahlknöpfe und ihre Beschriftung als **eine**
     * Fläche.
     *
     * Das Kästchen allein bleibt ein 13-px-Ziel, egal wie groß die Zeile
     * daneben ist – erst die gemeinsame Fläche macht daraus ein Tippziel. Die
     * Beschriftungen sind bereits `<label>`-Elemente mit dem Feld darin, also
     * genügt hier die Höhe.
     *
     * Die Selektoren nennen dieselben Kombinationen wie die Regeln weiter
     * oben (`.checkbox-label input[type="checkbox"]` und Geschwister). Das ist
     * kein Zufall: Mit geringerer Spezifität bliebe das dortige `width: auto`
     * stehen und das Kästchen 13 px klein.
     */
    .checkbox-label,
    .klaerung-option,
    .wochentag-feld,
    .umfang-option {
        min-height: 44px;
    }
    .checkbox-label input[type="checkbox"],
    .wochentag-feld input[type="checkbox"],
    .auswahl-schalter input[type="radio"],
    .klaerung-option input[type="radio"],
    .umfang-option input,
    input[type="checkbox"],
    input[type="radio"] {
        width: 22px;
        height: 22px;
        /* In einer Flex-Beschriftung gäbe das Kästchen sonst Breite ab, sobald
           der Text daneben eng wird – nachgemessen 13 von 22 px. */
        flex-shrink: 0;
    }
    /* Der Versatz stammt aus einem 13-px-Knopf, der zur ersten Textzeile
       ausgerichtet werden musste. Ein 22-px-Knopf säße damit zu tief. */
    .klaerung-option input[type="radio"] { margin-top: 0.1rem; }

    /*
     * Auswahl- und Eingabefelder. Die Schriftgröße steht weiter oben schon auf
     * 16 px (Fokus-Zoom); was fehlt, ist die Höhe. Kontrollkästchen und
     * Auswahlknöpfe sind ausdrücklich ausgenommen – sie sind quadratisch und
     * würden sonst zu 44-px-Klötzen.
     */
    .formular-zeile input:not([type="checkbox"]):not([type="radio"]),
    .formular-zeile select,
    .formular-zeile textarea,
    .datumswahl input[type="date"],
    .farbwahl input[type="text"],
    .formfeld input,
    select {
        min-height: 44px;
    }

    /*
     * Das Augensymbol im Passwortfeld (Issue #69). Es liegt im Feld und ist
     * damit kein Geschwister, sondern ein Überzug – trotzdem gilt für es
     * dieselbe Zusage wie für jedes andere Bedienelement auf dem Telefon:
     * 44 px in beide Richtungen. Der rechte Innenabstand des Feldes wächst
     * mit, sonst liefe der eingegebene Text darunter.
     */
    .passwort-auge {
        width: 44px;
        height: 44px;
    }

    .passwortfeld .passwortfeld-eingabe,
    .formfeld .passwortfeld .passwortfeld-eingabe,
    .formular-zeile .passwortfeld .passwortfeld-eingabe { padding-right: 3.3rem; }

    /*
     * Kleine Bedienelemente, die keine Schaltfläche sind: der Aufklapper
     * „Namen anzeigen“ in der Typenliste.
     */
    summary {
        display: flex;
        align-items: center;
        min-height: 44px;
    }

    /*
     * Die Verweise neben einem Feld. Sie stehen inmitten eines Satzes – in der
     * Programmliste und im Programmformular jeweils als „… in der
     * Elemente-Verwaltung gepflegt.“. Als Blockelement zerrisse der Verweis
     * genau diesen Satz auf drei Zeilen; `inline-flex` bleibt im Textfluss und
     * trägt die Mindesthöhe trotzdem, wie schon bei `.karte-aktiv p a`.
     */
    .link-extern {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    /*
     * Die Bereichsverweise auf dem Dashboard. Sie sind reiner Text mit 16 px
     * Höhe; in der Karte „Stammdaten“ stehen vier davon durch „·“ getrennt in
     * einer Zeile, und der senkrechte Abstand zwischen „Elemente“ und
     * „Programmpunkt-Typen“ war gemessene 0 px. Mit einer Mindesthöhe je
     * Verweis stehen sie auch umgebrochen weit genug auseinander, um sie
     * einzeln zu treffen – inhaltlich ändert sich nichts.
     */
    .karte-aktiv p a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    /* ── Mobile Basis, Teil 2: Ränder und Innenabstände ───────────────────
     *
     * Auf 390 px waren 24 px Rand je Seite aus `main` plus 8 px aus
     * `.seite-wrapper` zu vergeben – 16 % der Bildschirmbreite für nichts. Am
     * deutlichsten auf der Anmeldeseite: Dort kamen noch einmal 32 px dazu,
     * und die Karte war 276 px breit in einem 390-px-Fenster.
     *
     * Die Werte sind nicht auf null gesetzt: Ein Kasten, der die Bildschirm-
     * kante berührt, sieht nach Fehler aus, und auf gebogenen Displays liegt
     * er teilweise darunter.
     */
    main { padding: 1rem 0.75rem; }
    .hauptbereich-arbeit { padding: 0.6rem 0.5rem 0.7rem; }
    /* Als Variable, weil die Auswahlleiste weiter unten denselben Wert braucht:
       Sie steht außerhalb des Flusses und muss ihre linke und rechte Kante
       selbst setzen – aus dieser einen Angabe statt aus einer zweiten Zahl. */
    .seite-wrapper { --seiten-polster: 0.25rem; padding: 0 var(--seiten-polster); }
    .login-wrapper { padding: 1rem 0.75rem; }
    .login-box { padding: 1.6rem 1.2rem; }
    .karte,
    .formular-abschnitt { padding: 1rem 0.9rem; }

    /* ── Mobile Basis, Teil 3: der Kopf der Sendeplan-Ansichten ───────────
     *
     * Fünf der sechs gemessenen Überstände der Tagesansicht kommen aus dem
     * Kopf, keiner aus der Liste. Die Ursache ist in beiden Fällen dieselbe:
     * `white-space: nowrap`.
     *
     * `.plan-statistik` („32 Programmpunkte · davon 18 nicht im öffentlichen
     * Tagesplan“) wurde dadurch 607 px breit in einem 342 px breiten Kasten
     * und schob das ganze Dokument um 257 px zur Seite – Kopfzeile
     * inbegriffen. `.plan-zeitraum` machte `.plan-blaettern` 374 px breit, und
     * die „heute“-Marke stand rechts außerhalb des Bildschirms.
     *
     * Am Schreibtisch hat `nowrap` seinen Grund und bleibt: Dort passt die
     * Zeile, und ein Umbruch beim Blättern verschöbe alles darunter. Auf dem
     * Telefon passt sie nicht, und eine zweite Zeile ist das kleinere Übel
     * gegenüber einer Seite, die sich zur Seite schieben lässt.
     */
    .plan-zeitraum {
        white-space: normal;
        flex-wrap: wrap;
        min-width: 0;
        /*
         * Die Überschrift bekommt eine eigene Zeile – und zwar die erste.
         *
         * Umgebrochen stünde sie sonst zwischen „Vortag“ und „Heute“ und
         * zerrisse die drei Blätterschaltflächen auf zwei Zeilen; gemessen
         * 120 px für eine Zone, die 80 braucht. Oben stehend sagt sie
         * außerdem zuerst, welchen Tag man sieht, und die Bedienung steht
         * darunter beieinander.
         *
         * `order` verschiebt nur die Darstellung. Die Reihenfolge im Dokument
         * bleibt, was sie ist – für Vorlesesoftware und für die Tabtaste; die
         * Überschrift selbst ist ohnehin kein Sprungziel.
         */
        order: -1;
        flex-basis: 100%;
    }
    .plan-statistik {
        flex: 0 1 auto;
        min-width: 0;
        white-space: normal;
    }
    .plan-fussnote {
        flex-wrap: wrap;
        gap: 0 0.6rem;
    }
    .plan-notiz { flex-basis: 100%; }
    /*
     * Die Breitenplatzhalter der Kopfzeile dürfen auf dem Telefon nicht mehr
     * Platz reservieren.
     *
     * Am Schreibtisch halten sie die Zeile ruhig: „KW 2“ wird „KW 32“, 2026
     * wird 2027, „gerade“ wird „ungerade“ – jede dieser Änderungen verschöbe
     * sonst alles rechts davon. Auf 390 px bricht die Zeile ohnehin um; dort
     * reservieren sie nur noch die Breite der längsten Variante, die niemand
     * sieht. `visibility: hidden` hält den Platz, `display: none` gibt ihn
     * frei – mehr ist der Unterschied nicht.
     */
    .stabil-platz { display: none; }
    .stabil > * { white-space: normal; }

    /*
     * Die Werkzeugleiste darf wachsen.
     *
     * Der einzige echte Layoutfehler des Audits: Auf 390 px bricht die
     * Zeitskala um und wird 62 px hoch, aber `.plan-werkzeuge` ist ein
     * Flex-Element in der festen Spalte von `.seite-fest` und darf unter seine
     * Inhaltshöhe schrumpfen. Es blieb bei seiner `min-height: 2rem`, und die
     * zweite Zeile lief unten heraus – der dunkle „100 %“-Knopf stand mitten
     * im Text der Bilanzzeile darunter, gemessene 18 px Überdeckung.
     *
     * `flex-shrink: 0` an den drei Kopfzonen behebt das an der Ursache. Die
     * reservierte Mindesthöhe hat auf dem Telefon ohnehin nichts mehr zu tun:
     * Sie hielt den Rasterbeginn beim Wechsel zwischen Tag und Woche um einen
     * Pixel ruhig – ein Wert aus der Schreibtischansicht.
     */
    .plan-kopfzeile,
    .plan-werkzeuge,
    .plan-fussnote {
        flex-shrink: 0;
    }
    .plan-werkzeuge { min-height: 0; }
    /* Die beiden Umschaltergruppen zusammen sind rund 340 px breit und passen
       damit auf 390 px gerade eben nicht mehr neben den Rand. Sie dürfen
       umbrechen statt hinauszuragen. */
    .plan-ansichten { flex-wrap: wrap; }
    /*
     * Gestapelt gibt es kein „rechts“ mehr.
     *
     * `margin-left: auto` und die rechtsbündige Ausrichtung halten die Zone am
     * Schreibtisch beim Umbruch an ihrem Platz – der Grund steht oben bei
     * `.plan-kopfzeile`. Auf 390 px steht sie ohnehin allein in ihrer Zeile,
     * und das Datumsfeld hing dort ohne Not am rechten Rand, während links
     * daneben nichts stand. Untereinander an derselben Kante gelesen zu
     * werden, ist die Form, die eine gestapelte Ansicht braucht.
     */
    .plan-rechts {
        margin-left: 0;
        justify-content: flex-start;
    }

    /* ── Die aktive Auswahl als Leiste am unteren Rand (Issue #85) ────────
     *
     * Gemessen bei 390 px: Das Band kostete als eigener Block über der Liste
     * 94 px plus Abstand, und die Programmliste begann dadurch 102 px weiter
     * unten. Der Grund war nicht der Text, sondern die beschriftete
     * Schaltfläche „Auswahl aufheben": 137 px breit, neben dem Namen nicht
     * unterzubringen und deshalb in einer zweiten, 44 px hohen Zeile.
     *
     * Der erste Anlauf machte daraus eine Pille im freien Platz der
     * Steuerzeile. Nachgemessen blieb davon nichts: In der Zeile mit
     * Datumsfeld und „Ansicht" sind bei 390 px 92 px frei und bei 360 px
     * 62 px – zu wenig für einen erkennbaren Namen neben einem 44-px-Tippziel.
     * Die Pille brach deshalb doch in eine eigene Zeile um, und die kostete
     * 54 px. Genau die waren der gemeldete Sprung: Beim Auswählen wuchs die
     * Kopfzeile, und der ganze Plan darunter rutschte 54 px nach unten; beim
     * Aufheben sprang er zurück. (Die Kontur am gewählten Programmpunkt hat
     * daran keinen Anteil – sie liegt seit jeher als innerer Schein im Kasten
     * und verschiebt nichts, siehe `[data-rgs-plan].hat-inhalt .block.ist-inhalt`.)
     *
     * Waagerecht ist der Platz also nicht da. Also senkrecht – aber von
     * **unten**. Wo die Leiste steht und wie ihr Platz frei gemacht wird,
     * steht seit der Nacharbeit zu #91 nicht mehr hier, sondern außerhalb
     * jeder Medienabfrage bei `.plan-kopfzeile > .plan-band-auswahl`: Der
     * Schreibtisch hatte denselben Sprung, also gilt dort dieselbe Antwort.
     *
     * Was hier bleibt, ist der Unterschied des Telefons – die kompakte
     * Beschriftung und das Tippziel. Nebenbei bekommt der Name damit die volle
     * Breite statt einer Restbreite, und das „×" liegt in der Daumenzone statt
     * am oberen Rand.
     */
    /*
     * Mit dem Zusatz „nicht im Plan" hat die Leiste zwei Zeilen zu tragen, und
     * auf 320 px bricht der Halbsatz selbst noch einmal um: gemessen 54,8 px
     * statt 46. Ohne diese Ausnahme deckte sie dort die letzten drei Pixel des
     * Scrollbereichs zu – überlagern statt umbrechen, und genau das soll es
     * nicht geben. Der Rest ist Luft für eine dritte Zeile. Am Schreibtisch
     * passt derselbe Halbsatz neben den Namen; dort reicht die Grundhöhe.
     */
    .sendeplan-arbeitsflaeche:has(.plan-band-auswahl:not([hidden]) .plan-auswahl-leer:not([hidden])) {
        padding-bottom: calc(var(--auswahlleiste) + 1.25rem);
    }
    /* Rechts läuft die Leiste bis an die Kante: Das Tippziel ist dort ihr
       Ende und kein Kasten mit Abstand darin. */
    .plan-kopfzeile > .plan-band-auswahl { padding-right: 0; }
    /* Das Wort steht weiter im Vorlesefluss – siehe `.nur-vorlesen`, dieselbe
       Technik. Sichtbar sagt die Kontur links dasselbe kürzer. */
    .plan-band-auswahl .plan-auswahl-wort {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
    /* Das Tippziel: 44 × 44 px nach der Regel aus #43, quadratisch statt
       breit, und ohne den Rahmen einer Schaltfläche – in einer Pille ist es
       ihr rechtes Ende und kein zweiter Kasten darin. */
    .plan-band-auswahl .plan-band-aktion {
        min-width: 44px;
        min-height: 44px;
        padding: 0;
        border: 0;
        background: none;
        font-size: 1.4rem;
        line-height: 1;
    }
    /* Die Rückmeldung beim Antippen bleibt: Sie ist nur dann eine Fläche,
       wenn sie etwas zu sagen hat. */
    .plan-band-auswahl .plan-band-aktion:hover,
    .plan-band-auswahl .plan-band-aktion:active {
        background: var(--flaeche-neutral);
    }
    .plan-aktion-lang { display: none; }
    .plan-aktion-kurz { display: inline; }

    /*
     * Der Kasten für die Typenliste – der einzige Ort, an dem er einer ist.
     * Warum nur hier und nicht am Schreibtisch: siehe `.tabelle-quer` oben.
     */
    .tabelle-quer { overflow-x: auto; }

    /* ══ Sendeplan im Hochformat (Issue #44) ══════════════════════════════
     *
     * Das zweite Paket aus dem Mobile-Audit #35. Die Tagesansicht ist auf dem
     * Telefon die Ansicht – dorthin schickt `sendeplan/woche.html` schmale
     * Geräte, wenn keine Ansicht ausdrücklich verlangt war. Hier steht, was
     * sie braucht, um dort allein zu tragen: ein Tageswähler statt des
     * Wochenrasters, kürzere Karten und eine Kopfzeile, die nicht die halbe
     * Anzeige belegt.
     *
     * Alles davon liegt in diesem Block und wirkt ausschließlich unter 640 px.
     */

    /* ── 1) Der Tagesstreifen ─────────────────────────────────────────────
     *
     * Sieben gleich breite Knöpfe. `1fr` statt einer Breitenangabe: Bei 390 px
     * bleiben je Tag rund 50 px, bei 360 px rund 46 – in beiden Fällen über
     * dem 44-px-Maß aus #43, und ohne dass hier eine Zahl stünde, die bei der
     * nächsten Randänderung wieder falsch wäre.
     *
     * `flex-shrink: 0` aus demselben Grund wie bei den drei Kopfzonen: Er
     * steht in der festen Spalte von `seite-fest` und dürfte sonst unter seine
     * Inhaltshöhe gedrückt werden.
     */
    .tagesstreifen {
        display: grid;
        grid-template-columns: repeat(7, 1fr);
        gap: 0.25rem;
        margin-bottom: 0.5rem;
        flex-shrink: 0;
    }
    .tagesstreifen-tag {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        min-height: 44px;
        padding: 0.15rem 0;
        border: 1px solid var(--rand-stark);
        border-radius: 6px;
        background: var(--flaeche-karte);
        color: var(--text-normal);
        text-decoration: none;
        line-height: 1.15;
    }
    .tagesstreifen-kuerzel { font-size: 0.82rem; font-weight: 600; }
    .tagesstreifen-zahl {
        font-size: 0.68rem;
        color: var(--text-still);
        font-variant-numeric: tabular-nums;
    }
    /*
     * „Heute" und „gerade gewählt" sind zwei verschiedene Aussagen und
     * bekommen deshalb zwei verschiedene Mittel: Farbe für heute, Fläche für
     * die Auswahl. Beides zugleich ist der Normalfall und muss lesbar bleiben
     * – deshalb steht der aktive Zustand hinter dem heutigen und gewinnt.
     */
    .tagesstreifen-tag-heute {
        border-color: var(--info-marke);
        color: var(--info-marke);
    }
    .tagesstreifen-tag-heute .tagesstreifen-zahl { color: var(--info-marke); }
    .tagesstreifen-tag-aktiv {
        background: var(--fuellung);
        border-color: var(--fuellung);
        color: var(--fuellung-text);
    }
    .tagesstreifen-tag-aktiv .tagesstreifen-zahl { color: var(--fuellung-text-leise); }
    .tagesstreifen-tag:focus-visible {
        outline: 2px solid var(--kontur);
        outline-offset: 2px;
    }

    /* ── 2) Die Werkzeuge hinter „Ansicht" ────────────────────────────────
     *
     * Zugeklappt ist der Ausgangszustand. Die Zeitskala, „Nachrichten" und
     * „Freie Zeiten" sind Werkzeuge des Wochenrasters am Schreibtisch; auf dem
     * Telefon kosteten sie in der Tagesansicht eine Zeile, die man beim
     * Nachsehen nie braucht. Die Umschalter „Tag | Woche" und „Intern |
     * Öffentliche Vorschau" gehören zur selben Frage und klappen mit auf.
     *
     * Verloren geht dabei nichts: Jedes dieser Bedienelemente steht
     * unverändert im Dokument und ist einen Fingertipp entfernt.
     *
     * Dasselbe Mittel wie beim Hauptmenü – ein Kontrollkästchen und seine
     * Beschriftung, kein Skript. Das Kästchen ist sichtbar ausgeblendet, aber
     * für die Tastatur erreichbar; `display: none` nähme es ihr ganz.
     */
    .plan-werkzeug-schalter,
    .plan-nebensachen-schalter {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .plan-werkzeug-taste {
        display: inline-flex;
        align-items: center;
        gap: 0.35rem;
        cursor: pointer;
        /* Sonst markiert ein zweites Antippen die Beschriftung. */
        -webkit-user-select: none;
        user-select: none;
    }
    /*
     * Das Dreieck als Ränder eines leeren Kastens statt als Schriftzeichen:
     * „▸" fehlt in manchen Systemschriften und wäre dann ein Ersatzkästchen.
     */
    .plan-werkzeug-pfeil {
        width: 0;
        height: 0;
        border: 4px solid transparent;
        border-bottom: 0;
        border-top-color: currentColor;
    }
    .plan-werkzeug-schalter:checked ~ .plan-kopfzeile .plan-werkzeug-pfeil {
        border-top: 0;
        border-bottom: 4px solid currentColor;
    }
    .plan-werkzeug-schalter:focus-visible ~ .plan-kopfzeile .plan-werkzeug-taste,
    .plan-nebensachen-schalter:focus-visible ~ .plan-kopfzeile .plan-nebensache-taste {
        outline: 2px solid var(--kontur);
        outline-offset: 2px;
    }

    /*
     * Zugeklappt. Ausdrücklich auch für „Details": Es trägt die Klasse
     * `.schaltflaeche`, und die steht in diesem Block auf `inline-flex` –
     * ohne diese Zeile wäre es sichtbar, obwohl nichts aufgeklappt ist.
     */
    .plan-ansichten,
    .plan-werkzeuge,
    .plan-nebensache-taste { display: none; }
    .plan-werkzeug-schalter:checked ~ .plan-werkzeuge { display: flex; }
    .plan-werkzeug-schalter:checked ~ .plan-kopfzeile .plan-ansichten { display: flex; }
    /* „Details" ist eine Option von „Ansicht" und erscheint mit ihr. */
    .plan-werkzeug-schalter:checked ~ .plan-kopfzeile .plan-nebensache-taste {
        display: inline-flex;
        align-items: center;
        cursor: pointer;
        -webkit-user-select: none;
        user-select: none;
    }
    /* Eingeschaltet sieht er aus wie ein aktiver Schalter – dieselbe Fläche,
       dieselbe Farbe, dieselbe Aussage. */
    .plan-nebensachen-schalter:checked ~ .plan-kopfzeile .plan-nebensache-taste {
        background: var(--fuellung);
        border-color: var(--fuellung);
        color: var(--fuellung-text);
    }

    /* ── 3) Die Nebenangaben in den Karten ────────────────────────────────
     *
     * Toleranz, öffentlicher Zeittext und Sidebar-Modus. Der Audit führt sie
     * als das, was auf 390 px in fast jeder Karte steht, dort eine ganze Zeile
     * kostet und beim Nachsehen nie gebraucht wird.
     *
     * Ein Aufklapper je Karte wäre nach der 44-px-Regel selbst höher als die
     * Zeile, die er spart. Deshalb einer für die ganze Liste – er steht bei
     * den übrigen Ansichtsoptionen hinter „Ansicht".
     */
    .termin-nebensache { display: none; }
    .plan-nebensachen-schalter:checked ~ .arbeitsflaeche-scroll .termin-nebensache {
        display: inline;
    }

    /* ── 4) Kompaktere Programmkarten ─────────────────────────────────────
     *
     * Weniger Polster, engere Zeilen, aber **mehr** Abstand zwischen zwei
     * Karten: Der Audit misst dort heute 6 px, und eine kürzere Karte braucht
     * eine deutlichere Kante, sonst verschmilzt die Liste zu einer Fläche.
     *
     * Die Schriftgrößen bleiben, wie sie sind. Kompakter heißt hier weniger
     * Leerraum, nicht kleinere Schrift – lesbar muss die Karte bleiben.
     */
    .terminliste { gap: 0.55rem; }
    /* Polster und Zeilenabstände der Karte selbst stehen weiter oben bei den
       übrigen `.termin`-Regeln aus #43 – ein Selektor, eine Regel. */
    .termin-titel { line-height: 1.3; }
    .termin-merkmale { margin-top: 0.3rem; gap: 0.3rem; }
    /*
     * „Bearbeiten" behält seine eigene Zeile aus #43 – nachgemessen und
     * verworfen: Neben den Inhalt gestellt spart die Schaltfläche bei 390 px
     * rund 30 px Kartenhöhe, drückt den Titel dabei aber von 220 auf 151 px.
     * Ein langer Titel braucht dann drei Zeilen statt zwei, und die Karte ist
     * am Ende höher als vorher. Der Platz gehört dem Titel.
     */

    /* ══ Mobile Listen: Karten statt Tabellen (Issue #45) ═════════════════
     *
     * Das dritte Paket aus dem Mobile-Audit #35. Vier Listen, ein Muster.
     *
     * Der Befund war überall derselbe: eine Tabelle, viel breiter als das
     * Gerät. Planung 1345 px auf elf Spalten, Programmpunkt-Typen 1125 px,
     * Elemente 988 px, Sendungen 685 px – sichtbar davon jeweils 342 px. Wer
     * in der Planung „Bearbeiten“ suchte, wischte über einen Meter
     * Bildschirmbreite, und die feststehende Kopfzeile half dabei nicht: Sie
     * sagte, in welcher Spalte man ist, aber nicht mehr, zu welcher Zeile.
     *
     * Eine schmalere Tabelle ist keine Lösung. Elf Spalten in 342 px sind
     * 31 px je Spalte – das ist keine Tabelle mehr, sondern ein Rest davon.
     * Deshalb steht hier je Datensatz eine Karte: oben, was die Zeile
     * bezeichnet, darunter die Merkmale als Marken, dann die übrigen Spalten
     * als Paare aus Bezeichnung und Wert, unten die Aktionen.
     *
     * Weggelassen wird dabei nichts. Jede Spalte der Tabelle hat in der Karte
     * ihren Platz – auch die, die dort nur ein `title` war.
     */

    /*
     * Die Tabelle geht, die Karten kommen. Beides an einer Stelle, damit
     * niemals beide zugleich dastehen.
     *
     * `.datentabelle` trägt genau diese vier Tabellen und keine weitere.
     * Ausgeblendet statt entfernt: Der Schreibtisch braucht sie, und mehrere
     * Suiten prüfen, dass sie im Dokument steht.
     */
    .datentabelle { display: none; }
    .listenkarten {
        display: flex;
        flex-direction: column;
        /* Derselbe Abstand wie zwischen zwei Programmkarten aus #44 – eine
           kurze Karte braucht eine deutliche Kante, sonst verschmilzt die
           Liste zu einer Fläche. */
        gap: 0.55rem;
    }
    .listenkarte {
        background: var(--flaeche-karte);
        border: 1px solid var(--rand);
        border-radius: 8px;
        box-shadow: var(--schatten-liste);
        padding: 0.6rem 0.7rem;
    }

    /*
     * Der Kopf: das, woran man den Datensatz erkennt.
     *
     * In der Planung sind das zwei Angaben – die interne Zielzeit und der
     * Titel –, überall sonst nur der Titel. Die Zeit gibt keine Breite ab
     * (`flex-shrink: 0`), der Titel nimmt den Rest und darf umbrechen;
     * deutsche Zusammensetzungen wie „Landesgartenschau-Wissen“ sind länger
     * als 342 px.
     */
    .listenkarte-kopf {
        display: flex;
        align-items: baseline;
        gap: 0.5rem;
        flex-wrap: wrap;
    }
    .listenkarte-zeit {
        flex-shrink: 0;
        font-weight: 700;
        font-size: 1.05rem;
        color: var(--text-stark);
        font-variant-numeric: tabular-nums;
    }
    .listenkarte-titel {
        flex: 1 1 8rem;
        margin: 0;
        font-size: 1rem;
        font-weight: 600;
        color: var(--text-stark);
        line-height: 1.3;
        overflow-wrap: anywhere;
    }
    /* Die Anzahl der Unter-Elemente steht am Titel, nicht in einer eigenen
       Zeile – sie beschreibt ihn. */
    .listenkarte-zusatz { font-size: 0.8rem; font-weight: 400; color: var(--text-leise); }

    /* Die Marken direkt unter dem Titel: Typ, „Wdh.“, Kategorie. Sie sind das,
       was man beim Überfliegen sucht, und brauchen deshalb keine
       Bezeichnung. */
    .listenkarte-marken {
        display: flex;
        flex-wrap: wrap;
        gap: 0.3rem;
        margin-top: 0.4rem;
    }

    /*
     * Die übrigen Spalten als Paare aus Bezeichnung und Wert – dieselbe Form
     * wie in den Angaben einer Benutzerkarte und im Bestätigungsdialog.
     *
     * Zwei Spalten und nicht untereinander: Die Bezeichnungen sind kurz, und
     * nebeneinander gelesen bleibt die Karte halb so hoch.
     */
    .listenkarte-angaben {
        display: grid;
        grid-template-columns: auto 1fr;
        column-gap: 0.7rem;
        row-gap: 0.2rem;
        margin: 0.45rem 0 0;
        font-size: 0.85rem;
    }
    .listenkarte-angaben dt { color: var(--text-leise); }
    .listenkarte-angaben dd { margin: 0; color: var(--text-normal); overflow-wrap: anywhere; }

    /*
     * Die Aktionen als Fußzeile: abgesetzt, damit ein „Löschen“ nicht wie eine
     * weitere Angabe aussieht, und umbrechend, weil in der Elementliste bis zu
     * fünf davon nebeneinanderstehen.
     *
     * Die Höhe von 44 px bringen die Schaltflächen aus #43 selbst mit.
     */
    .listenkarte-aktionen {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.4rem;
        margin-top: 0.5rem;
        padding-top: 0.45rem;
        border-top: 1px solid var(--rand-zart);
    }
    .listenkarte-aktionen form { display: inline; }

    /*
     * Die Reihenfolge-Tasten der Elementliste. Sie sind die einzigen
     * Schaltflächen der Anwendung, die nacheinander mehrfach gedrückt werden,
     * und mit „↑“ als ganzem Inhalt die schmalsten – der Audit misst 30 × 23
     * px. Die Höhe kommt von `.schaltflaeche`, die Breite hier.
     */
    .listenkarte-rang { min-width: 44px; }

    /*
     * Unter-Elemente. In der Tabelle sind sie eine eingerückte Zeile mit „↳“;
     * hier eine eingerückte Karte mit derselben Kante. Eigene Karte und nicht
     * ein Abschnitt der Elternkarte: Sie haben eigene Angaben und eigene
     * Aktionen, und eine Karte, die zwei Datensätze bedient, ist keine mehr.
     */
    .listenkarte-kind {
        margin-left: 0.9rem;
        border-left: 3px solid var(--rand-akzent);
        background: var(--flaeche-still);
    }

    /* ══ Feinschliff: Personen, Klärungen, Benutzer, Formulare, Login ═════
     *
     * Das vierte und letzte Paket aus dem Mobile-Audit #35 (Issue #46). Diese
     * fünf Bereiche bewertet der Audit als „strukturell brauchbar“ – hier wird
     * deshalb nichts umgebaut, sondern verdichtet: weniger Leerraum, breitere
     * Felder, eine Karte, die nicht den ganzen Bildschirm belegt, und ein
     * Archiv, das nicht zwölf Formulare offen stehen lässt.
     *
     * Alles davon steht in diesem Block und wirkt ausschließlich unter 640 px.
     * Der Entwicklungsstatus bleibt unberührt: Der Audit nennt ihn das gute
     * Vorbild, und es gibt hier keine Regel, die ihn träfe.
     */

    /* ── 1) Die Anmeldeseite ──────────────────────────────────────────────
     *
     * Zwei Ränder übereinander. `main` gibt seit #43 auf dem Telefon 0,75 rem
     * je Seite, `.login-wrapper` noch einmal 0,75 rem – zusammen 48 px auf
     * 390 px Bildschirm für einen Kasten, der ohnehin allein auf der Seite
     * steht. Die Karte maß dadurch 342 px.
     *
     * Der Rand verschwindet nicht, er wird nur einmal statt zweimal vergeben:
     * `.login-wrapper` trägt ihn, `main` gibt ihn ab. Die Karte hat damit
     * 366 px und denselben Abstand zur Bildschirmkante wie der Inhalt jeder
     * anderen Seite.
     *
     * Der senkrechte Rand geht aus einem zweiten Grund mit: `.login-wrapper`
     * ist 100 vh hoch. In einem `main` mit 1 rem Polster oben und unten war
     * das Dokument dadurch 876 px hoch in einem 844-px-Fenster – 32 px
     * Scrollweg auf einer Seite, die nichts zu scrollen hat.
     *
     * Die Klasse steht am `main` der Anmeldeseite und sonst nirgends; die
     * allgemeine Regel für `main` bleibt, wie sie ist.
     */
    main.hauptbereich-anmeldung { padding: 0; }

    /* ── 2) Personen: Miniatur statt Kopfbild ─────────────────────────────
     *
     * Der Audit misst 16 Personen mit einem 6023 px hohen Dokument – gut
     * sieben Bildschirmlängen für eine Liste, in der man einen Namen sucht.
     * Der Grund ist das Bild: Es steht in voller Kartenbreite über dem Namen
     * und ist bei 390 px 356 × 267 px groß, also zwei Drittel einer 402 px
     * hohen Karte.
     *
     * Auf dem Telefon steht es deshalb links neben dem Namen statt darüber.
     * Weggelassen wird nichts: dieselbe Bildfläche, dasselbe Seitenverhältnis,
     * dieselben Angaben, dieselben Aktionen – nur anders angeordnet. Aus
     * „ein Porträt je Bildschirm“ werden vier Personen je Bildschirm.
     *
     * Ein Raster und keine Flex-Zeile: Die Aktionen sollen unter **beiden**
     * Spalten stehen und nicht neben dem Bild eingerückt beginnen.
     */
    .personenkarten { gap: 0.55rem; }
    .personenkarte {
        display: grid;
        grid-template-columns: auto 1fr;
        column-gap: 0.7rem;
        padding: 0.6rem 0.7rem;
    }
    /*
     * Die Miniatur. 3,6 rem Breite ergeben bei 4:3 rund 58 × 43 px – groß
     * genug, um ein Gesicht zu erkennen, klein genug, um die Karte nicht mehr
     * zu beherrschen. `align-self: start` hält sie an der Oberkante, damit sie
     * neben dem Namen steht und nicht neben der Mitte des Textes.
     */
    .personenkarte-bild {
        width: 3.6rem;
        align-self: start;
        border-radius: 6px;
    }
    /* Die Initialen sind der Ersatz für das Bild und folgen seiner Größe. */
    .personenkarte-platzhalter { font-size: 1.05rem; }
    .personenkarte-inhalt { padding: 0; gap: 0.2rem; }
    /*
     * Zwei Zeilen Vorschau statt drei. Am Schreibtisch stehen die Karten
     * nebeneinander und eine dritte Zeile kostet nichts; untereinander
     * gestapelt ist sie die dritte Zeile jeder einzelnen Karte.
     */
    .personenkarte-vorstellung { -webkit-line-clamp: 2; }
    .personenkarte-aktionen {
        grid-column: 1 / -1;
        margin-top: 0.5rem;
        padding: 0.45rem 0 0;
    }

    /* ── 3) Klärungen: das Archiv klappt zu ───────────────────────────────
     *
     * Die Seite ist bei 390 px 10 824 px hoch – dreizehn Bildschirmlängen.
     * Davon entfallen 5007 px auf die zwölf Änderungsformulare der bereits
     * geklärten Fragen; jede dieser Karten trägt eines, vollständig
     * aufgeklappt, mit allen Auswahlknöpfen und einem Notizfeld. Der
     * eigentliche Zweck der Seite – die offenen Fragen – steht darüber und
     * ist meistens leer.
     *
     * Sichtbar bleibt, was eine geklärte Frage ausmacht: die Frage, die
     * gespeicherte Antwort und ihr Datum, dazu Kontext und Quelle. Das
     * Formular kommt auf Antippen. Offene Klärungen behalten ihres offen.
     *
     * Der Schalter ist ein Kontrollkästchen mit Beschriftung, kein Skript –
     * dasselbe Mittel wie beim Hauptmenü (#26) und bei „Ansicht“ (#44).
     */
    .klaerung-karte {
        padding: 0.9rem 0.9rem;
        margin-bottom: 0.7rem;
    }
    /*
     * Sichtbar ausgeblendet, für die Tastatur erreichbar. `display: block`
     * steht hier ausdrücklich: Außerhalb der Medienabfrage ist das Kästchen
     * `display: none`, und das nähme es der Tastatur ganz.
     */
    .klaerung-aendern-schalter {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .klaerung-aendern-taste {
        display: inline-flex;
        align-items: center;
        gap: 0.4rem;
        /* Ein Tippziel, kein Textlink – dasselbe Maß wie überall seit #43. */
        min-height: 44px;
        padding: 0 0.8rem;
        border: 1px solid var(--rand-stark);
        border-radius: 6px;
        background: var(--flaeche-zart);
        font-size: 0.88rem;
        font-weight: 600;
        color: var(--text-normal);
        cursor: pointer;
        /* Sonst markiert ein zweites Antippen die Beschriftung. */
        -webkit-user-select: none;
        user-select: none;
    }
    .klaerung-aendern-schalter:focus-visible ~ .klaerung-aendern-taste {
        outline: 2px solid var(--kontur);
        outline-offset: 2px;
    }
    /*
     * Das Dreieck als Ränder eines leeren Kastens statt als Schriftzeichen –
     * derselbe Grund wie bei „Ansicht“: „▸“ fehlt in manchen Systemschriften
     * und wäre dort ein Ersatzkästchen.
     */
    .klaerung-aendern-pfeil {
        width: 0;
        height: 0;
        border: 4px solid transparent;
        border-bottom: 0;
        border-top-color: currentColor;
    }
    .klaerung-aendern-schalter:checked ~ .klaerung-aendern-taste .klaerung-aendern-pfeil {
        border-top: 0;
        border-bottom: 4px solid currentColor;
    }
    /* Zugeklappt ist der Ausgangszustand – aber nur für geklärte Fragen. */
    .klaerung-geklaert .klaerung-form { display: none; }
    .klaerung-aendern-schalter:checked ~ .klaerung-form { display: block; }

    /* ── 4) Benutzerverwaltung: eine feste Anordnung ──────────────────────
     *
     * Die Tippflächen sind seit #43 in Ordnung; der Audit nennt hier sonst
     * nur die Struktur, und die ist es im Grundsatz auch. Was auf dem Telefon
     * fehlte, war Verlässlichkeit: Der Kopf ist eine Flex-Zeile mit
     * `space-between`, und dadurch stand die Rolle bei einem kurzen Namen
     * rechts neben ihm, bei einem langen dagegen umgebrochen an der linken
     * Kartenkante unter dem Bild. Zwei Karten untereinander sahen aus wie zwei
     * verschiedene Kartenarten.
     *
     * Als Raster steht sie immer an derselben Stelle: Bild links über beide
     * Zeilen, Name oben rechts, Marken darunter. Gemessen wird der Unterschied
     * an der zweiten Karte – sie war 237 px hoch und ist es nicht mehr, weil
     * der Name nicht mehr in eine eigene Zeile gedrängt wird.
     *
     * Dazu dieselbe Kartendichte wie in den Listen aus #45: weniger Polster,
     * engerer Abstand, deutliche Kante.
     */
    .benutzerkarten { gap: 0.55rem; }
    .benutzerkarte {
        padding: 0.7rem 0.8rem;
        gap: 0.55rem;
    }
    .benutzerkarte-kopf {
        display: grid;
        grid-template-columns: auto 1fr;
        align-items: center;
        column-gap: 0.6rem;
        row-gap: 0.25rem;
    }
    /* Das Bild steht neben beiden Zeilen, nicht neben einer von ihnen. */
    .benutzerkarte-bild { grid-row: span 2; }
    .benutzerkarte-name,
    .benutzerkarte-marken { grid-column: 2; }
    .benutzerkarte-aktionen { padding-top: 0.5rem; }

    /* ── 5) Formulare: ein Feld, eine Zeile ───────────────────────────────
     *
     * Die Masken sind einspaltig und bleiben es – das ist die Form, die auf
     * ein Telefon gehört, und der Audit bestätigt sie. Was nicht stimmte,
     * waren die Feldbreiten **innerhalb** einer Zeile: Überall dort, wo neben
     * einem Feld noch etwas steht – ein Verweis, eine Schaltfläche, eine
     * Bildvorschau –, teilten sich beide eine Zeile, die dafür zu schmal ist.
     *
     * Gemessen bei 390 px: die Typ-Auswahl der Elementmaske 116 px, das
     * Bild-Feld der Benutzermaske 162 px, die Foto-Adresse der Personenmaske
     * 193 px, die Moderatorenauswahl der Sendungsmaske 170 px, das Farbfeld
     * der Elementmaske 144 px. In eine 116 px breite Auswahl passt kein
     * Typname.
     *
     * Die Regel ist überall dieselbe: Das Feld nimmt die ganze Zeile, sein
     * Begleiter rückt darunter. Keines der Paare verliert dabei seinen
     * Zusammenhang – sie stehen weiterhin in derselben Zeile des Formulars,
     * nur untereinander statt nebeneinander.
     */
    .select-mit-neu,
    .foto-eingabe { flex-wrap: wrap; }
    .select-mit-neu select,
    .foto-eingabe input { flex-basis: 100%; }
    /* `.zeit-eingabe` bricht schon um; dem Zeitfeld fehlte nur die Breite. */
    .zeit-eingabe input[type="time"] { width: 100%; }
    /*
     * Das Farbfeld. Der Farbwähler daneben ist mit 48 × 44 px ein gültiges
     * Tippziel und behält seine Breite – ein Farbfleck wird nicht besser,
     * wenn er breiter ist. Das Hex-Feld bekommt den Rest der Zeile;
     * „Farbe entfernen“ rückt darunter.
     */
    .farbwahl input[type="text"] {
        flex: 1 1 8rem;
        width: auto;
    }
    /*
     * E-Mail und Passwort sind die einzigen beiden Felder der Anwendung, die
     * nie in die Breiten- und Rahmenregel der Formularzeile aufgenommen
     * wurden – sie standen deshalb als browsereigene Felder da, 204 px breit
     * neben 263 px breiten Nachbarn. Auf dem Telefon zählt jeder Millimeter
     * Zeilenbreite, und ein Formular, in dem zwei von sechs Feldern anders
     * aussehen als der Rest, ist keines.
     *
     * Am Schreibtisch bleiben sie unverändert: Issue #46 lässt ihn
     * ausdrücklich in Ruhe. Dass sie auch dort dazugehören sollten, ist ein
     * eigener Befund und gehört in ein eigenes Issue.
     */
    .formular-zeile input[type="email"],
    .formular-zeile input[type="password"] {
        width: 100%;
        padding: 0.55rem 0.8rem;
        border: 1px solid var(--rand-stark);
        border-radius: 6px;
        font-family: inherit;
        background: var(--flaeche-eingabe);
    }
    /*
     * Die Aktionsleiste darf umbrechen.
     *
     * Nachgemessen bei 360 px: „Programmeintrag anlegen“ und „Abbrechen“
     * ergeben zusammen 271 px in einer 264 px breiten Leiste – „Abbrechen“
     * stand 7 px außerhalb. Umbrechend steht es darunter, und beide behalten
     * ihre volle Beschriftung, statt sie auf zwei Zeilen zu quetschen.
     *
     * Eine am unteren Rand feststehende Aktionsleiste, die der Audit zur
     * Prüfung stellt, ist bewusst nicht daraus geworden: Sie nähme auf jeder
     * Maske dauerhaft 60 px vom ohnehin knappen Bildschirm und verdeckte beim
     * Tippen das Feld darunter. Die Masken sind lang, aber sie sind
     * einspaltig und laufen auf ihr Ende zu – das Ende ist der richtige Ort
     * für den Knopf, der sie abschließt.
     */
    .formular-aktionen { flex-wrap: wrap; }
}

/*
 * Der Fokus-Zoom hängt nicht an der Fensterbreite, sondern am Gerät: Er tritt
 * dort auf, wo mit dem Finger bedient wird. Ein Tablet mit 900 px fällt nicht
 * unter die Regel oben, ist aber genauso betroffen. Diese Abfrage trifft genau
 * die Geräte, um die es geht, und lässt maus-bediente Fenster in Ruhe.
 */
@media (pointer: coarse) {
    .formular-zeile input[type="text"],
    .formular-zeile input[type="url"],
    .formular-zeile input[type="number"],
    .formular-zeile input[type="date"],
    .formular-zeile input[type="time"],
    .formular-zeile select,
    .formular-zeile textarea,
    .datumswahl input[type="date"],
    .farbwahl input[type="text"],
    input,
    select,
    textarea {
        font-size: 16px;
    }
}

/* ── Bedienelemente: dieselbe Fläche wie ihr Formular (Issue #65) ─────────
 *
 * Die Mischzustände, die einen dunklen Modus kaputt aussehen lassen, entstehen
 * alle an derselben Stelle: bei den Feldern, die ihre Farbe bisher vom Browser
 * bekamen und nicht vom Stylesheet. Ein weißes Eingabefeld auf dunkler Karte,
 * ein heller Vorschlagstext, ein von der Autovervollständigung gelb gefärbtes
 * Feld, ein deaktiviertes Feld, das man nicht mehr lesen kann.
 *
 * Der Block steht bewusst **hinter** den Formularregeln: Er soll ergänzen, was
 * dort fehlt, und nicht überschreiben, was dort ausdrücklich steht. Deshalb
 * auch die niedrige Spezifität – `.formular-zeile input[readonly]` und
 * `.klaerung-notiz.notiz-noetig textarea` behalten ihre eigene Fläche.
 *
 * Alles hier gilt in **beiden** Modi. Es gibt keine Regel, die nur im Dunkeln
 * existiert; nur Werte, die sich mit dem Modus ändern.
 */
input[type="text"],
input[type="url"],
input[type="number"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="date"],
input[type="time"],
select,
textarea {
    background: var(--flaeche-eingabe);
    color: var(--text-normal);
}

/*
 * Die Vorbelegung eines leeren Feldes. `opacity: 1` gehört dazu: Browser
 * dämpfen den Platzhalter zusätzlich, und aus einem ohnehin leisen Grau würde
 * im Dunkeln ein kaum sichtbares.
 */
::placeholder {
    color: var(--text-platzhalter);
    opacity: 1;
}

/*
 * Die Autovervollständigung des Browsers.
 *
 * Chrome und Safari übermalen ein ausgefülltes Feld mit einem eigenen hellen
 * Gelb – über jede `background`-Angabe hinweg; das ist eine Benutzeragenten-
 * Regel, die sich nicht schlicht überschreiben lässt. Der eingebürgerte Weg
 * ist ein innerer Schatten über die volle Feldfläche: Er liegt darüber, folgt
 * dem Eckenradius und nimmt die Farbe, die das Feld ohnehin haben soll. Die
 * Schriftfarbe braucht denselben Sonderweg (`-webkit-text-fill-color`).
 */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill {
    -webkit-box-shadow: 0 0 0 40rem var(--flaeche-eingabe) inset;
    -webkit-text-fill-color: var(--text-normal);
    caret-color: var(--text-normal);
}

/*
 * Gesperrte Felder. Erkennbar gesperrt, aber lesbar: `opacity` würde den Text
 * gegen die Fläche ausbleichen – im Dunkeln bis zur Unlesbarkeit. Stattdessen
 * eine eigene, ruhigere Fläche und eine leisere, aber kontrastreiche Schrift.
 */
.formular-zeile input:disabled,
.formular-zeile select:disabled,
.formular-zeile textarea:disabled,
input:disabled,
select:disabled,
textarea:disabled {
    background: var(--flaeche-gesperrt);
    color: var(--text-leise);
    -webkit-text-fill-color: var(--text-leise);
    opacity: 1;
}

/*
 * Verweise im Fließtext.
 *
 * Sie hatten bisher gar keine Farbe und trugen damit das Browserblau
 * (#0000EE). Auf Weiß fiel das nicht auf; auf einer dunklen Fläche ist es
 * praktisch nicht mehr zu lesen. Betroffen sind die Verweise, die aus dem
 * Handbuchtext selbst kommen (`app/handbuch_html.py` setzt dort ein blankes
 * `<a>`) und der Hinweis auf die öffentliche Seite im Dashboard.
 */
.hb-inhalt a,
.hb-kasten a,
.hb-vorspann a,
.etappe-hinweis a,
.leer-hinweis a {
    color: var(--verweis);
}

/* ── Farbwert in Listen ───────────────────────────────────────
 *
 * Ein echtes Farbfeld neben dem Hex-Wert. Nur Anzeige – gepflegt wird die
 * Farbe ausschließlich im Elementformular.
 */
.farbwert {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

.farbfeld {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    border-radius: 3px;
    /* Die Kontur macht auch sehr helle Töne als Fläche erkennbar. */
    border: 1px solid var(--kontur-farbfeld);
    flex-shrink: 0;
}

.farbcode {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8rem;
    color: var(--text-mittel);
}

.zelle-farbe { white-space: nowrap; }

/* ── Entwicklungsstatus ───────────────────────────────────────
 *
 * Die Seite `/entwicklungsstatus` – ausdrücklich von unten nach oben gebaut:
 * Was hier ohne Medienabfrage steht, gilt auf dem Handy. Erst weiter unten
 * kommt der Schreibtisch dazu.
 *
 * Drei Regeln, die das Layout auf schmalen Geräten zusammenhalten:
 *
 *   * keine feste Breite, nirgends – jedes Raster benutzt `minmax(0, 1fr)`,
 *     damit ein langer Issue-Titel die Spalte nicht aufblähen kann;
 *   * lange Zeichenketten (Titel, Commit-SHA) brechen `anywhere` um statt
 *     die Seite waagerecht scrollen zu lassen;
 *   * jedes antippbare Ziel ist mindestens 44 px hoch.
 */

.entw-seite {
    max-width: 1400px;
    margin: 0 auto;
    /* Nichts in dieser Seite darf breiter werden als ihr Kasten. */
    min-width: 0;
    /*
     * Die reservierte Höhe der oberen Kartenzeile – Statuskarte links,
     * Fortschritt rechts. Auf dem Handy gilt sie nicht: Dort stehen die
     * Karten untereinander, und abgeschnittener Text wäre schlimmer als eine
     * längere Seite. Am Schreibtisch dagegen entscheidet sie darüber, ob die
     * Seite bei den Zehn-Sekunden-Takten ruhig stehen bleibt: Ohne feste
     * Höhe schöbe jede längere Meldung alles darunter nach unten.
     *
     * Bemessen ist sie nach der vollsten regulären Statuskarte – Zustand über
     * zwei Zeilen, Meldung, Issue mit Titel, Laufzeit, Browser-QM,
     * Qualitätsprüfung und Handlungssatz. Was darüber hinausgeht, bekommt
     * innerhalb der Karte seinen Platz und schiebt die Zeile nicht auf.
     */
    --entw-kopfhoehe: 26rem;
}

/*
 * Ausgeblendet heißt ausgeblendet. Mehrere Bausteine dieser Seite bekommen
 * hier ein eigenes `display` – und das schlägt die eingebaute Regel des
 * Browsers für `hidden`. Ohne diese Zeile bliebe ein leerer Wert sichtbar,
 * den die Seite gerade nicht zeigen will.
 */
.entw-seite [hidden] { display: none !important; }

.entw-kopf h2 {
    margin: 0 0 0.25rem;
    font-size: 1.35rem;
    color: var(--text-stark);
}

.entw-kopf-hinweis {
    margin: 0 0 1rem;
    font-size: 0.88rem;
    color: var(--text-leise);
    line-height: 1.5;
}

.entw-takt { display: block; font-size: 0.8rem; }

/* ── Kacheln anordnen (Issue #89) ─────────────────────────────
 *
 * Ein eigener Modus und keine dauernd sichtbare Bedienung: Wer die Seite
 * liest, soll sie lesen. Erst `Kacheln anordnen` schaltet den Griff an jeder
 * Kachel ein – und weil er bis dahin in einem `display: none` steckt, ist er
 * auch für Tastatur und Vorlesehilfe nicht da.
 *
 * Nichts hier hat eine feste Farbe: Die Leiste benutzt dieselben
 * `.schaltflaeche`-Klassen wie der Rest der Anwendung, der Rest die
 * Farbtoken. Der dunkle Modus entsteht daraus von selbst.
 */
.entw-ordnen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1rem;
}

.entw-ordnen-form {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/*
 * Diese Seite hält jedes antippbare Ziel bei 44 px – auch am Schreibtisch, wo
 * `.schaltflaeche` sonst 30 px misst. Das ist keine Sonderregel für die
 * Leiste, sondern die dritte Regel aus dem Kopf dieses Abschnitts; jeder
 * andere Verweis dieser Seite hält sie schon. Nachgemessen wird sie in einem
 * echten Browser von `tests/bildbeleg_entwicklungsstatus.py`.
 */
.entw-ordnen .schaltflaeche {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}

.entw-ordnen-hinweis {
    /* Der Satz gehört unter die Knöpfe und nicht neben den letzten. */
    flex-basis: 100%;
    margin: 0;
    font-size: 0.85rem;
    color: var(--text-leise);
}

/*
 * Welche der beiden Ordnungen gerade bearbeitet wird – Schreibtisch oder
 * Telefon. Der Satz steht unter dem Bedienhinweis und trägt dessen Aussehen:
 * Beide beantworten dieselbe Frage „was tue ich hier gerade", und zwei
 * verschiedene Schriftgrößen dafür wären eine Behauptung über eine
 * Rangfolge, die es nicht gibt.
 */
.entw-ordnen-ansicht {
    flex-basis: 100%;
    margin: -0.25rem 0 0;
    font-size: 0.85rem;
    color: var(--text-leise);
}

.entw-ordnen-meldung {
    margin: -0.4rem 0 1rem;
    font-size: 0.85rem;
    color: var(--erfolg-text);
}

/* Der Griff über der Kachel – im Ruhezustand gibt es ihn nicht. */
.entw-kachel-ordnen { display: none; }

.entw-ordnen-aktiv .entw-kachel-ordnen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: -0.25rem 0 0.6rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px dashed var(--rand-stark);
}

.entw-kachel-name {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-stark);
    margin-right: auto;
}

.entw-kachel-breite,
.entw-kachel-grund {
    font-size: 0.75rem;
    color: var(--text-still);
}

.entw-kachel-pfeil {
    /*
     * 44 px im Quadrat, damit die Taste auch auf dem Telefon zu treffen ist –
     * dort ist sie die einzige Bedienung, weil Ziehen auf Touchgeräten nicht
     * geht. Die Breite kommt aus dem Seitenverhältnis und nicht aus einer
     * `min-width` in Pixeln: Diese Seite darf nirgends eine feste
     * Mindestbreite bekommen, sonst entstünde auf einem 375 px breiten
     * Bildschirm eine waagerechte Scrollleiste.
     */
    min-height: 44px;
    aspect-ratio: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    background: var(--flaeche-sanft);
    color: var(--text-normal);
    font-size: 1rem;
    cursor: pointer;
}

.entw-kachel-pfeil:hover { background: var(--flaeche-neutral); }

/*
 * Im Bearbeitungsmodus sieht man, was verschiebbar ist – und was nicht.
 * Eine Kachel, die sich stumm weigert, wäre eine Panne; eine, die ihren
 * Grund danebenschreibt, ist eine Grenze.
 */
.entw-ordnen-aktiv .entw-karte {
    outline: 2px dashed var(--rand-akzent);
    outline-offset: 2px;
    cursor: grab;
}

.entw-ordnen-aktiv .entw-karte[data-entw-fest="1"] {
    outline-style: dotted;
    cursor: default;
}

/*
 * Solange angeordnet wird, führt kein Verweis in einer Kachel mehr weg. Ein
 * Klick auf „#88" mitten im Verschieben verließe die Seite – und mit ihr die
 * noch nicht gespeicherte Reihenfolge. Zugleich bekommt damit die Kachel den
 * Zeiger und nicht der Verweis darin: Ziehen beginnt auch dann, wenn man sie
 * an einer Stelle anfasst, an der zufällig ein Verweis liegt. Die Tasten des
 * Griffs sind ausgenommen – sie sind die Bedienung dieses Modus.
 */
.entw-ordnen-aktiv .entw-karte a { pointer-events: none; }
.entw-ordnen-aktiv .entw-kachel-ordnen { pointer-events: auto; }

.entw-kachel-zieht { opacity: 0.5; }

.entw-raster {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
}

.entw-karte {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand);
    border-radius: 10px;
    padding: 1rem;
    min-width: 0;
}

.entw-karte h3 {
    margin: 0 0 0.75rem;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-leise);
}

/* Die Statuskarte: das Erste, was man sieht, und das Größte auf der Seite. */
.entw-status {
    padding: 1.1rem 1rem 1.25rem;
    display: flex;
    flex-direction: column;
}

/*
 * Der Textkörper der Statuskarte. Er trägt am Schreibtisch die reservierte
 * Höhe von innen: Wird der Inhalt einmal länger als der Platz – eine
 * ungewöhnlich lange Meldung, ein dreizeiliger Issue-Titel –, bekommt er ihn
 * hier und nicht dadurch, dass die Karte wächst.
 */
.entw-status-koerper { min-height: 0; }

.entw-zustand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 0.6rem;
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--text-stark);
    overflow-wrap: anywhere;
}

.entw-symbol { font-size: 1.5rem; line-height: 1; flex-shrink: 0; }

.entw-zustand-ruhig   { border-left-color: var(--erfolg-kraeftig); }
.entw-zustand-arbeit  { border-left-color: var(--warnung-kraeftig); }
.entw-zustand-gut     { border-left-color: var(--erfolg-kraeftig); }
.entw-zustand-fehler  { border-left-color: var(--fehler-kraeftig); }
.entw-zustand-unbekannt { border-left-color: var(--rand-still); }

.entw-meldung,
.entw-warnung,
.entw-handeln {
    margin: 0 0 0.7rem;
    padding: 0.6rem 0.75rem;
    border-radius: 8px;
    font-size: 0.9rem;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.entw-meldung { background: var(--flaeche-sanft); color: var(--text-normal); }
.entw-warnung { background: var(--warnung-flaeche); color: var(--warnung-text-tief); }
.entw-handeln { background: var(--info-flaeche-zart); color: var(--info-text-tief); font-weight: 600; }

/*
 * Der Satz für den ruhigen Fall: keine Warnfarbe, kein Kasten – es ist ja
 * nichts passiert. Er trägt die Karte, wenn sonst nichts darauf steht.
 */
.entw-hinweis-karte {
    margin: 0 0 0.7rem;
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--text-normal);
    overflow-wrap: anywhere;
}

/*
 * Ohne Statusdatei bleibt genau diese eine Karte übrig. Damit sie auf dem
 * Schreibtisch nicht als leerer Balken über 1400 px steht, bekommt sie eine
 * eigene, begrenzte Breite – bewusst schmal, statt Platz zu füllen, den es
 * nicht zu füllen gibt. Links bündig zur Überschrift wie jede andere Karte
 * des Backends; eine mittig schwebende Karte sähe aus wie ein Dialog.
 */
.entw-modus-leer {
    max-width: 46rem;
    padding: 1.25rem 1rem 1.4rem;
}

/* Bricht die Überschrift auf dem Handy um, gehört das Symbol nach oben –
 * mittig neben drei Zeilen sieht es aus wie verrutscht. */
.entw-modus-leer .entw-zustand { align-items: flex-start; }

.entw-modus-leer .entw-meldung {
    font-size: 0.85rem;
    background: transparent;
    padding: 0;
    color: var(--text-leise);
}

.entw-auftrag { margin-bottom: 0.7rem; }

.entw-issue { margin: 0; }

.entw-issue-titel {
    margin: 0.15rem 0 0;
    font-size: 1rem;
    color: var(--text-normal);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

/*
 * Antippbar mit dem Daumen: 44 px hoch, ohne dass der Text dadurch verrutscht.
 * Hover ist ausdrücklich nur Zugabe – auf dem iPhone gibt es ihn nicht.
 */
.entw-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 0.1rem;
    color: var(--text-stark);
    font-weight: 600;
    text-decoration: underline;
    overflow-wrap: anywhere;
}

.entw-link:hover { color: var(--akzent-text); }

.entw-laufzeit {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0.4rem 0 0.7rem;
}

.entw-laufzeit-wert {
    font-size: 1.9rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-stark);
}

.entw-laufzeit-text { font-size: 0.85rem; color: var(--text-leise); }

/*
 * Automatik: der Countdown ist die eine Zahl, auf die Martin schaut. Deshalb
 * steht er groß und mit fester Ziffernbreite (`tabular-nums`) – sonst
 * zappelte die Zeile bei jedem Sekundenwechsel.
 */
.entw-countdown {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 0.8rem;
}

.entw-countdown-wert {
    font-size: 1.9rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-stark);
}

.entw-countdown-text {
    font-size: 0.85rem;
    color: var(--text-leise);
    overflow-wrap: anywhere;
}

/*
 * Warteschlange: auf dem Handy je Auftrag eine Karte mit Beschriftungen, am
 * Schreibtisch eine scanbare Zeile – derselbe Gedanke wie bei der Historie.
 */
.entw-queue {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.5rem;
}

.entw-queue-eintrag {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.1rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-still);
    border-radius: 8px;
    background: var(--flaeche-still);
    min-width: 0;
}

.entw-queue-eintrag span { overflow-wrap: anywhere; min-width: 0; }

.entw-queue-position {
    font-weight: 700;
    color: var(--text-leise);
    font-variant-numeric: tabular-nums;
}

.entw-queue-titel { color: var(--text-stark); font-size: 0.95rem; }

.entw-queue-seit { color: var(--text-leise); font-size: 0.82rem; }
.entw-queue-seit::before { content: "angelegt "; }

.entw-queue-leer {
    margin: 0;
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--text-normal);
    overflow-wrap: anywhere;
}

/*
 * Fortschritt: auf dem Handy untereinander, am Schreibtisch kompakt in zwei
 * Spalten rechts neben der Statuskarte – mit Haken für Erledigtes.
 */
.entw-fortschritt {
    display: flex;
    flex-direction: column;
}

/*
 * „Aktuell: Qualitätsprüfung" – der laufende Schritt im Klartext, bevor die
 * Liste ihn als Kreis zeigt. In einer zweispaltigen Liste ist ein einzelner
 * hervorgehobener Eintrag sonst nichts, was man im Vorbeigehen findet.
 */
.entw-jetzt {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem;
    margin: 0 0 0.7rem;
    font-size: 1.05rem;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

.entw-jetzt-marke { color: var(--text-leise); font-size: 0.85rem; }
.entw-jetzt-titel { font-weight: 700; color: var(--text-stark); }

.entw-jetzt-aktuell  .entw-jetzt-titel { color: var(--warnung-mittel); }
.entw-jetzt-fehler   .entw-jetzt-titel { color: var(--fehler-text); }
.entw-jetzt-erledigt .entw-jetzt-titel { color: var(--erfolg-text); }

.entw-schritte {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.1rem;
}

.entw-schritt {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    min-height: 44px;
    padding: 0.25rem 0;
    font-size: 0.95rem;
    color: var(--text-still);
    overflow-wrap: anywhere;
}

.entw-schritt-marke {
    width: 1.4rem;
    height: 1.4rem;
    border-radius: 999px;
    border: 2px solid var(--rand-stark);
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
    line-height: 1;
}

.entw-schritt-erledigt { color: var(--erfolg-text); }
.entw-schritt-erledigt .entw-schritt-marke {
    border-color: var(--erfolg-kraeftig);
    background: var(--erfolg-kraeftig);
    color: var(--fuellung-text);
}
.entw-schritt-erledigt .entw-schritt-marke::before { content: "✓"; }

.entw-schritt-aktuell { color: var(--text-stark); font-weight: 700; }
.entw-schritt-aktuell .entw-schritt-marke {
    border-color: var(--warnung-kraeftig);
    background: var(--warnung-flaeche);
}
.entw-schritt-aktuell .entw-schritt-marke::before { content: "●"; color: var(--warnung-kraeftig); }

.entw-schritt-fehler { color: var(--fehler-text); font-weight: 700; }
.entw-schritt-fehler .entw-schritt-marke {
    border-color: var(--fehler-kraeftig);
    background: var(--fehler-flaeche);
}
.entw-schritt-fehler .entw-schritt-marke::before { content: "!"; color: var(--fehler-text); }

/* Angaben als Paarliste – auf dem Handy untereinander, sonst zweispaltig. */
.entw-angaben {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.15rem 1rem;
    margin: 0;
    font-size: 0.92rem;
}

.entw-angaben dt {
    color: var(--text-leise);
    font-size: 0.8rem;
}

.entw-angaben dd {
    margin: 0 0 0.6rem;
    color: var(--text-stark);
    overflow-wrap: anywhere;
}

.entw-titel { display: block; color: var(--text-normal); font-size: 0.9rem; }

.entw-commit {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

.entw-hinweis,
.entw-orientierung {
    margin: 0.5rem 0 0;
    font-size: 0.88rem;
    line-height: 1.55;
    color: var(--text-normal);
}

.entw-orientierung {
    padding-top: 0.6rem;
    border-top: 1px solid var(--rand-zart);
}


/*
 * Aktueller Stand der Aufgaben (Issue #87) – die kompakte Zusammenfassung
 * über den Einzelläufen.
 *
 * Dieselbe Formensprache wie die Historie darunter, und das mit Absicht: Es
 * sind zwei Sichten auf denselben Bestand, keine zwei Bereiche. Der
 * Unterschied steckt im Inhalt – hier steht je Aufgabe ihr **heutiger**
 * Zustand, darunter je Lauf sein Ergebnis von damals.
 *
 * Auf dem Handy eine Karte je Aufgabe mit Beschriftungen davor, am
 * Schreibtisch eine scanbare Zeile. Keine Tabelle, keine feste Breite: Was
 * hier ohne Medienabfrage steht, gilt auf 375 px.
 */
.entw-aufgaben {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.6rem;
}

.entw-aufgabe {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.2rem;
    padding: 0.75rem;
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-still);
    border-radius: 8px;
    background: var(--flaeche-still);
    font-size: 0.9rem;
    min-width: 0;
}

.entw-aufgabe span { overflow-wrap: anywhere; min-width: 0; }

/*
 * Derselbe Farbstreifen wie in den Laufzeilen – nur speist ihn hier der
 * heutige Zustand der Aufgabe und nicht das Ergebnis eines Laufs. Grün heißt
 * damit „abgenommen und geschlossen", auch wenn der letzte Lauf darunter rot
 * ist; genau das war der Befund aus Issue #87.
 */
.entw-aufgabe.entw-abn-abnahme-offen { border-left-color: var(--warnung-kraeftig); }
.entw-aufgabe.entw-abn-abgenommen    { border-left-color: var(--erfolg-kraeftig); }
.entw-aufgabe.entw-abn-fehler        { border-left-color: var(--fehler-kraeftig); }
.entw-aufgabe.entw-abn-unklar        { border-left-color: var(--rand-still); }
/* Vorgemerkte Wartung: eingeplant, nicht kaputt (Nachtrag zu Issue #87). */
.entw-aufgabe.entw-abn-vorgemerkt    { border-left-color: var(--info-kante); }

.entw-aufgabe .entw-pille { overflow-wrap: break-word; }

.entw-aufgabe-titel { font-weight: 600; color: var(--text-stark); }

.entw-aufgabe-bilanz,
.entw-aufgabe-zeit { color: var(--text-mittel); font-size: 0.85rem; }

/* Auf schmalen Geräten sagt eine Beschriftung, was die Zeile bedeutet. */
.entw-aufgabe-zustand::before { content: "Heute: "; color: var(--text-still); }
.entw-aufgabe-bilanz::before  { content: "Läufe: "; color: var(--text-still); }
.entw-aufgabe-zeit::before    { content: "Zuletzt: "; color: var(--text-still); }

.entw-aufgaben-kopf { display: none; }

/*
 * Der Satz „Aufgabe inzwischen abgeschlossen" (Issue #87).
 *
 * Er steht in der Statuszelle unter der roten Pille und ist bewusst **keine**
 * zweite Pille: Zwei farbige Marken nebeneinander sähen aus wie zwei
 * widersprüchliche Aussagen über denselben Lauf. Der Lauf bleibt rot – der
 * Satz sagt nur, dass seine Aufgabe heute erledigt ist.
 *
 * `--erfolg-text` und nicht `--text-leise`: Es ist eine gute Nachricht, und
 * sie muss neben einer roten Pille auch als solche zu erkennen sein.
 */
.entw-erledigt,
.entw-lauf .entw-erledigt {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.78rem;
    color: var(--erfolg-text);
    /* Kein `anywhere`: Die Zeilenregel `.entw-lauf span` ist spezifischer und
       hätte den Satz mitten im Wort getrennt – derselbe Fall wie bei der Pille
       eine Regel weiter oben. */
    overflow-wrap: break-word;
}

/*
 * Historie: auf dem Handy je Lauf eine Karte mit Beschriftungen davor, auf
 * dem Schreibtisch dieselben Felder als scanbare Zeile. Bewusst keine
 * Tabelle – die brächte auf 375 px eine waagerechte Scrollleiste mit.
 */
.entw-historie {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.6rem;
}

.entw-lauf {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.2rem;
    padding: 0.75rem;
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-still);
    border-radius: 8px;
    background: var(--flaeche-still);
    font-size: 0.9rem;
    min-width: 0;
}

.entw-lauf-fertig { border-left-color: var(--erfolg-kraeftig); }
.entw-lauf-fehler { border-left-color: var(--fehler-kraeftig); }

.entw-lauf span { overflow-wrap: anywhere; min-width: 0; }

.entw-lauf-titel { font-weight: 600; color: var(--text-stark); }
.entw-lauf-ergebnis,
.entw-lauf-abnahme,
.entw-lauf-dauer,
.entw-lauf-zeit,
.entw-lauf-tests,
.entw-lauf-deployment,
.entw-lauf-pruefung,
.entw-lauf-commit { color: var(--text-mittel); font-size: 0.85rem; }

/* Auf schmalen Geräten sagt eine Beschriftung, was die Zeile bedeutet. */
.entw-lauf-ergebnis::before   { content: "Ergebnis: "; color: var(--text-still); }
.entw-lauf-abnahme::before    { content: "Status: "; color: var(--text-still); }
.entw-lauf-dauer::before      { content: "Dauer: "; color: var(--text-still); }
.entw-lauf-zeit::before       { content: "Ende: "; color: var(--text-still); }
.entw-lauf-tests::before      { content: "Tests: "; color: var(--text-still); }
.entw-lauf-deployment::before { content: "Deployment: "; color: var(--text-still); }
.entw-lauf-pruefung::before   { content: "Prüfung: "; color: var(--text-still); }
.entw-lauf-commit::before     { content: "Commit: "; color: var(--text-still); }

/*
 * Das Ergebnis der unabhängigen Qualitätsprüfung in der Statuskarte. Es steht
 * bewusst über der Handlungsaufforderung: erst wissen, ob schon jemand
 * nachgesehen hat, dann lesen, was zu tun ist.
 */
/*
 * Der Browser-QM steht direkt darüber und sieht genauso aus: beides sind
 * Aussagen darüber, wer den Stand schon angesehen hat.
 */
.entw-pruefung,
.entw-browser {
    margin: 0.4rem 0 0;
    font-size: 0.9rem;
    color: var(--text-normal);
    overflow-wrap: anywhere;
}

.entw-pruefung-marke,
.entw-browser-marke { color: var(--text-leise); }

.entw-historie-kopf { display: none; }

.entw-verbindung-weg { color: var(--fehler-text); }


/*
 * Die vollständige Laufhistorie (Issue #72) – `/entwicklungsstatus/historie`.
 *
 * Dieselbe Formensprache wie die Historie auf der Statusseite, nur mit einer
 * Zeile mehr Aufgabe: Auf dem Telefon ist ein Lauf eine Karte mit
 * Beschriftungen davor, am Schreibtisch eine scanbare Zeile – und beides ist
 * aufklappbar. Das Aufklappen kann `<details>` selbst; das Dreieck des
 * Browsers weicht dabei einer eigenen Marke – es säße sonst im Rasterfluss
 * und verschöbe auf dem Telefon jede Zeile um seine Breite.
 *
 * Wieder keine Tabelle und wieder keine feste Breite: Was hier ohne
 * Medienabfrage steht, gilt auf 375 px.
 */
.entw-hist-bilanz {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem 1rem;
}

.entw-hist-bilanz h3 { margin: 0 0 0.5rem; }

.entw-hist-bereich {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
    color: var(--text-leise);
    font-variant-numeric: tabular-nums;
}

.entw-hist-alle,
.entw-hist-zurueck { font-size: 0.9rem; }

/* Suche, Ergebnisfilter und Zeitraum: auf dem Telefon untereinander. */
.entw-hist-filter {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0 1rem;
}

.entw-hist-filter .formular-zeile { margin-bottom: 0.8rem; }

/*
 * Ein Datumsfeld und die Taste, die es wieder leert (Issue #84).
 *
 * Sie steht **neben** dem Feld und nicht darunter: Die Zeilenhöhe ändert sich
 * dadurch nicht, wenn ein Datum gesetzt oder entfernt wird – die Taste kommt
 * und geht, ohne dass der Filterblock darunter springt. `flex: 0 0 auto` hält
 * sie in ihrer Breite; das Feld daneben gibt nach, nicht sie.
 */
.entw-hist-datum {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.5rem;
    min-width: 0;
}

/* Das Feld gibt nach, bis es 8 rem breit ist; darunter rutscht lieber die
   Taste unter das Feld, als dass der Kalender des Browsers unlesbar würde.
   Genau dafür bekommt es **keine** `min-width: 0`: Die Angabe hätte gesagt,
   was hier gerade nicht gemeint ist – ein Flex-Element mit `min-width: 0`
   schrumpft unter seinen Inhalt, und `flex-shrink` hätte das Feld an einer
   engen Stelle bis unter „TT.MM.JJJJ" zusammengezogen, statt die Taste
   umbrechen zu lassen. Ohne die Angabe gilt die selbsttätige Mindestgröße,
   und die ist bei einem Datumsfeld sein Inhalt. Am Schreibtisch trifft das
   die zweite Filterzeile: Dort steht „Abgeschlossen bis" in einer der
   schmalen Spalten, und knapp über 900 px bliebe von seinem Datum sonst nur
   ein Ausschnitt. */
.entw-hist-datum input[type="date"] {
    flex: 1 1 8rem;
}

.entw-hist-leeren {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
}

/* Der Vorgabeknopf des Filterformulars steht vor allen anderen, damit Enter
   im Suchfeld „Anzeigen" auslöst und nicht die erste „Leeren"-Taste. Er
   verschwindet, ohne zu verschwinden: `display: none` nähmen manche Browser
   zum Anlass, ihn beim Absenden zu übergehen. Er nimmt keinen Platz, fängt
   keine Berührung ab und bleibt damit ohne Wirkung auf das Bild der Seite. */
.entw-hist-vorgabe {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    pointer-events: none;
}

.entw-hist-tasten {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
}

.entw-hist-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.6rem;
}

.entw-hist-eintrag { min-width: 0; }

.entw-hist-lauf {
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-still);
    border-radius: 8px;
    background: var(--flaeche-still);
    min-width: 0;
}

/*
 * Der Farbstreifen sagt das Ergebnis, bevor man liest. „Zurückgerollt" ist
 * bewusst nicht rot wie ein Abbruch und nicht grün wie ein Erfolg: Der Lauf
 * war produktiv und ist wieder zurückgenommen worden – das ist ein dritter
 * Ausgang und kein Zwischenton.
 *
 * Alle drei ausdrücklich an `.entw-hist-lauf` gebunden: `.entw-lauf-fehler`
 * steht weiter oben und käme sonst **vor** der Kurzschreibweise `border-left`
 * dieser Karte – der rote Streifen wäre wieder grau.
 */
.entw-hist-lauf.entw-lauf-erfolgreich    { border-left-color: var(--erfolg-kraeftig); }
.entw-hist-lauf.entw-lauf-zurueckgerollt { border-left-color: var(--warnung-kraeftig); }
.entw-hist-lauf.entw-lauf-fehler         { border-left-color: var(--fehler-kraeftig); }

/*
 * Und darüber der **fachliche** Zustand (Issue #78). Er steht bewusst
 * dahinter und gewinnt damit den Streifen: Auf einen Blick soll die Zeile
 * nicht sagen „technisch durchgelaufen", sondern „muss ich hinsehen?".
 * Gelb heißt fertig, aber noch nicht abgenommen; grün heißt erledigt; rot
 * bleibt der technische Fehler; grau heißt, dass es keinen belastbaren
 * Abnahmestand gibt – geraten wird nicht.
 *
 * Beide Listen tragen dieselben Klassen: die lange Historie
 * (`.entw-hist-lauf`) und die kompakten letzten Läufe (`.entw-lauf`).
 */
.entw-hist-lauf.entw-abn-abnahme-offen,
.entw-lauf.entw-abn-abnahme-offen { border-left-color: var(--warnung-kraeftig); }
.entw-hist-lauf.entw-abn-abgenommen,
.entw-lauf.entw-abn-abgenommen    { border-left-color: var(--erfolg-kraeftig); }
.entw-hist-lauf.entw-abn-fehler,
.entw-lauf.entw-abn-fehler        { border-left-color: var(--fehler-kraeftig); }
.entw-hist-lauf.entw-abn-unklar,
.entw-lauf.entw-abn-unklar        { border-left-color: var(--rand-still); }

/*
 * Die Statuspille. Farbe **und** Wort, immer beide: Wer Farben nicht
 * unterscheiden kann, liest dasselbe wie alle anderen. Das Symbol davor ist
 * ausdrücklich `aria-hidden` – es wiederholt nur, was daneben steht, und
 * niemand möchte „gelber Kreis Abnahme offen" vorgelesen bekommen.
 */
.entw-pille {
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    padding: 0.1rem 0.5rem;
    border: 1px solid var(--rand-still);
    border-radius: 999px;
    background: var(--flaeche-sanft);
    color: var(--text-leise);
    font-size: 0.8rem;
    line-height: 1.5;
    /* Kein `nowrap`: In einer schmalen Spalte liefe die Pille sonst über ihre
       Zelle hinaus – auf einem 1280er Laptop reicht der Platz für „Abnahme
       offen" nicht immer. Sie darf lieber zweizeilig werden.

       Aber auch kein `anywhere` mehr (Issue #84). Der Unterschied ist genau
       der, an dem die Pille auf dem Telefon zerbrochen ist: `anywhere` zählt
       die Trennstelle in die **Mindestbreite** ein, und die einer Pille war
       damit ein einziges Zeichen. In einer Flex-Zeile neben einem langen
       Erklärungstext schrumpfte sie auf diese Breite zusammen – aus „Gelb"
       wurde „Gel" über „b", und aus der Pille ein Kreis. `break-word` trennt
       ein zu langes Wort genauso, lässt die Mindestbreite aber beim längsten
       Wort: Die Pille bleibt eine Pille und bricht erst, wenn es wirklich
       eng wird. */
    overflow-wrap: break-word;
}

/*
 * Und dieselbe Zusage in den Zeilen beider Listen (Issue #84): Dort steht
 * `overflow-wrap: anywhere` an `span` – für den Titel und den Commit genau
 * richtig, für die Pille genau falsch. Die Regel ist mit ihrer Zelle
 * spezifischer als `.entw-pille` und hätte den Bruch mitten im Wort dort
 * wieder eingeführt, den die Pille eine Zeile höher gerade abgelegt hat.
 */
.entw-hist-zeile .entw-pille,
.entw-lauf .entw-pille { overflow-wrap: break-word; }

.entw-pille-symbol { font-size: 0.7em; }

.entw-pille-abnahme-offen {
    background: var(--warnung-flaeche);
    border-color: var(--warnung-kraeftig);
    color: var(--warnung-text);
}

.entw-pille-abgenommen {
    background: var(--erfolg-flaeche);
    border-color: var(--erfolg-kraeftig);
    color: var(--erfolg-text);
}

.entw-pille-fehler {
    background: var(--fehler-flaeche);
    border-color: var(--fehler-kraeftig);
    color: var(--fehler-text);
}

/*
 * Vorgemerkte Wartung (Nachtrag zu Issue #87) – blau und ausdrücklich nicht
 * rot.
 *
 * An so einer Aufgabe hängt oft ein Fehler, aber der ist bereits in eine
 * Aktion überführt: Sie wartet nicht auf eine Entscheidung, sondern auf den
 * nächsten Lauf. Rot wäre ein Alarm für etwas, das schon eingeplant ist – und
 * grün oder gelb wären eine der vier vorhandenen Aussagen, die sie nicht
 * meint. Die Info-Token gibt es in beiden Modi; eine feste Farbe stünde im
 * dunklen Modus als zweite Quelle daneben.
 */
.entw-pille-vorgemerkt {
    background: var(--info-flaeche);
    border-color: var(--info-kante);
    color: var(--info-text);
}

/* „Unklar" bleibt bewusst farblos: ein Zustand ohne Aussage sieht auch aus
   wie einer ohne Aussage. */
.entw-pille-unklar {
    background: var(--flaeche-sanft);
    border-color: var(--rand-still);
    color: var(--text-leise);
}

/*
 * Die Liste der vorgemerkten Wartungsaktionen in der Warteschlangenkarte.
 *
 * Auf dem Telefon wie am Schreibtisch dieselbe Form: je Aktion ein kleiner
 * Block mit Nummer, Titel, Zustand und zwei Sätzen darunter. Bewusst **keine**
 * Spaltenzeile wie die Warteschlange darüber – die beiden Sätze („was tut
 * das" und „wann") sind der Inhalt, und in einer Spalte wären sie unlesbar
 * schmal. Was hier ohne Medienabfrage steht, gilt auf 375 px.
 */
.entw-wartung-block { margin-top: 0.9rem; }

.entw-wartung-titel {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-still);
}

.entw-wartung {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.5rem;
}

.entw-wartung-eintrag {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.25rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--rand);
    border-left: 4px solid var(--info-kante);
    border-radius: 8px;
    background: var(--flaeche-still);
    font-size: 0.9rem;
    min-width: 0;
}

/* Eine Marke, die nichts auslöst, sieht auch aus wie eine ohne Aussage. */
.entw-wartung-eintrag.entw-abn-unklar { border-left-color: var(--rand-still); }

.entw-wartung-eintrag span { overflow-wrap: anywhere; min-width: 0; }
.entw-wartung-eintrag .entw-pille { overflow-wrap: break-word; }

.entw-wartung-titelzeile { font-weight: 600; color: var(--text-stark); }

.entw-wartung-zustand { margin: 0.15rem 0; }

.entw-wartung-erklaerung,
.entw-wartung-wann {
    font-size: 0.82rem;
    color: var(--text-mittel);
}

/* „Wartet hinter dem laufenden Auftrag" ist die Antwort auf die Frage, wegen
   der dieser Block entstanden ist – sie darf nicht wie eine Fußnote wirken. */
.entw-wartung-wann { color: var(--info-text); }

/*
 * Die Legende über der Liste: dieselben vier Wörter wie in den Zeilen.
 *
 * Auf dem Telefon ist jeder Eintrag eine eigene Zeile – Farbe links, Erklärung
 * rechts daneben. Nebeneinander gesetzt bekämen vier Einträge dort je ein
 * Viertel der Breite, und jede Erklärung stünde als schmale Wortsäule da.
 * Nebeneinander stehen sie erst am Schreibtisch, wo der Platz dafür da ist
 * (siehe die Medienabfrage weiter unten).
 */
.entw-legende {
    list-style: none;
    margin: 0 0 0.8rem;
    padding: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.4rem;
}

.entw-legende-eintrag {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    min-width: 0;
}

/*
 * Die Farbmarke in der Legende bleibt eine Pille – auch dann, wenn der Text
 * daneben zweizeilig wird (Issue #84).
 *
 * Vier Angaben, und jede verhindert einen eigenen Bruch: `flex: 0 0 auto`
 * nimmt sie aus dem Zusammenschrumpfen der Zeile heraus, `nowrap` hält „Gelb"
 * und „Grün" in einem Stück, `overflow-wrap: normal` nimmt jede Trennstelle
 * innerhalb des Wortes zurück, und die Mindestbreite gibt allen vier dieselbe
 * Größe – „Rot" ist sonst deutlich schmaler als „Grau", und die Erklärungen
 * daneben begännen an vier verschiedenen Stellen. Der Text rechts darf
 * umbrechen, so oft er will; er ist der einzige Teil dieser Zeile, der Platz
 * abgibt.
 */
.entw-legende .entw-pille {
    flex: 0 0 auto;
    justify-content: center;
    min-width: 3.6rem;
    white-space: nowrap;
    overflow-wrap: normal;
}

.entw-legende-text {
    font-size: 0.85rem;
    color: var(--text-leise);
    overflow-wrap: break-word;
}

/* Der Issue-Fokus: „Historie für #73" mit seiner Bilanz. */
.entw-hist-fokus-titel {
    margin: 0 0 0.5rem;
    color: var(--text-stark);
    font-weight: 600;
    overflow-wrap: anywhere;
}

.entw-hist-fokus-bilanz {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 0.8rem;
    margin: 0;
}

.entw-hist-fokus-zahlen {
    font-size: 0.88rem;
    color: var(--text-leise);
}

/* Der Hinweis über der Aufgabensicht – ein Satz, keine Anleitung. */
.entw-hist-hinweis {
    margin: 0 0 0.8rem;
    font-size: 0.85rem;
    color: var(--text-leise);
}

/* Wie viele Läufe hinter einer Aufgabenzeile stehen.
 *
 * Bewusst `--text-leise` und nicht `--text-still`: Der Ton daneben wäre
 * hübscher, käme aber nur auf 2,5:1 gegen die Kartenfläche. Diese Angabe ist
 * eine Aussage über den Lauf und keine Verzierung – sie muss lesbar sein. */
.entw-lauf-weitere {
    display: inline-block;
    margin-left: 0.4rem;
    font-size: 0.78rem;
    font-weight: 400;
    color: var(--text-leise);
    white-space: nowrap;
}

/* Der kleine Pfeil zur Aufgabe auf GitHub, neben ihrer Nummer. */
.entw-lauf-extern {
    margin-left: 0.3rem;
    font-size: 0.85em;
    text-decoration: none;
}

.entw-hist-zeile {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.2rem;
    padding: 0.75rem 2.25rem 0.75rem 0.75rem;
    font-size: 0.9rem;
    min-width: 0;
    cursor: pointer;
    /* Das eingebaute Dreieck weicht der eigenen Marke – in beiden Browsern. */
    list-style: none;
}

.entw-hist-zeile::-webkit-details-marker { display: none; }

.entw-hist-zeile span { overflow-wrap: anywhere; min-width: 0; }

.entw-hist-zeile:hover { background: var(--flaeche-sanft); }

.entw-hist-marke {
    position: absolute;
    top: 0.7rem;
    right: 0.75rem;
    color: var(--text-still);
    font-size: 0.9rem;
}

.entw-hist-marke::before { content: "▸"; }
.entw-hist-lauf[open] .entw-hist-marke::before { content: "▾"; }

.entw-hist-lauf[open] .entw-hist-zeile {
    border-bottom: 1px solid var(--rand-zart);
}

.entw-hist-details { padding: 0.75rem; }

.entw-hist-blaettern {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.9rem;
}

.entw-hist-seitenzahl {
    font-size: 0.88rem;
    color: var(--text-leise);
    font-variant-numeric: tabular-nums;
}

.entw-hist-fuss { margin: 0.5rem 0 0; }

.entw-hist-kopf { display: none; }

/*
 * Ab hier der Schreibtisch. Der vorhandene Platz wird verteilt, statt die
 * Handyansicht breitzuziehen: oben links der laufende Auftrag und rechts
 * daneben der Fortschritt, darunter Automatik und Warteschlange, dann Zeiten
 * und letzter Lauf über die ganze Breite, ganz unten die Historie als
 * Zeilenraster mit Kopfzeile.
 */
@media (min-width: 900px) {
    .entw-raster { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .entw-voll { grid-column: 1 / -1; }

    /*
     * Die obere Kartenzeile: links der laufende Auftrag, rechts der
     * Fortschritt – beide mit derselben reservierten Höhe. Damit bleiben sie
     * dauerhaft bündig, und vor allem: Die Seite springt bei den
     * Zehn-Sekunden-Takten nicht. Ein Phasenwechsel von „Gesamttests laufen"
     * auf „Browser-QM läuft – geschützte Seiten werden angemeldet geprüft"
     * verändert die Außenhöhe der Karte nicht mehr.
     *
     * Nur im vollen Modus: Ohne laufenden Auftrag steht die Statuskarte
     * allein in der Zeile und darf so hoch sein, wie ihr einer Satz es
     * verlangt – eine halbleere Karte über 26 rem wäre kein ruhiges Layout,
     * sondern ein Loch.
     */
    .entw-status.entw-modus-voll,
    .entw-fortschritt { height: var(--entw-kopfhoehe); }

    .entw-status.entw-modus-voll .entw-status-koerper {
        flex: 1 1 auto;
        overflow-y: auto;
    }

    .entw-kopf h2 { font-size: 1.6rem; }
    .entw-takt { display: inline; margin-left: 0.4rem; }

    .entw-zustand { font-size: 1.5rem; }
    .entw-symbol { font-size: 1.8rem; }
    .entw-laufzeit-wert { font-size: 2.2rem; }
    .entw-countdown-wert { font-size: 2.2rem; }

    /* Position, Nummer, Titel, Alter – in einer Zeile statt untereinander. */
    .entw-queue-eintrag {
        grid-template-columns:
            minmax(0, 2rem) minmax(0, 4.5rem) minmax(0, 1fr) minmax(0, 8rem);
        align-items: baseline;
        gap: 0.75rem;
    }

    /* Steht die Infokarte allein, darf sie ruhig etwas Luft haben. */
    .entw-modus-leer { padding: 1.75rem 1.75rem 2rem; }

    /*
     * Elf Schritte untereinander sind eine halbe Bildschirmhöhe. In zwei
     * Spalten werden daraus sechs Zeilen. Gefüllt wird spaltenweise – erst
     * die linke von oben nach unten, dann die rechte –, damit die
     * Reihenfolge des Ablaufs beim Lesen erhalten bleibt; zeilenweise
     * gefüllt stünde Schritt 2 rechts neben Schritt 1.
     *
     * Die Zeilenzahl ist die Hälfte der Phasen aus
     * `app/entwicklungsstatus.py`, aufgerundet. Beides muss zusammenpassen,
     * sonst entstünde eine dritte Spalte – die Testsuite hält es zusammen.
     */
    .entw-fortschritt .entw-schritte {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-rows: repeat(6, auto);
        grid-auto-flow: column;
        align-content: start;
        column-gap: 1.25rem;
    }

    .entw-angaben {
        grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
        align-items: baseline;
    }
    /*
     * In einer halben Kachel bleiben von 13 rem Beschriftung zu wenig für den
     * Wert daneben – seit Issue #89 stehen `Zeiten` und `Letzter
     * abgeschlossener Lauf` dort. Die Beschriftungen sind kurz genug für
     * 10 rem („Letzter Statuszeitpunkt" ist die längste), und der Wert
     * bekommt damit den Platz, der ihm vorher fehlte. Volle Kacheln behalten
     * ihre 13 rem.
     */
    .entw-karte:not(.entw-voll) .entw-angaben {
        grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
    }
    .entw-angaben dt { font-size: 0.9rem; }
    .entw-angaben dd { margin-bottom: 0.35rem; }

    /*
     * Zehn Spalten seit Issue #78: Die Statuspille steht neben dem Ergebnis
     * und nicht an seiner Stelle – „erfolgreich" und „abgenommen" sind zwei
     * Aussagen. Die Issue-Spalte ist etwas breiter geworden, weil dort neben
     * der Nummer der Pfeil zur Aufgabe auf GitHub steht.
     */
    .entw-lauf {
        grid-template-columns:
            minmax(0, 5.5rem) minmax(0, 2.6fr) minmax(0, 1.2fr)
            minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1.5fr)
            minmax(0, 1.5fr) minmax(0, 1.5fr) minmax(0, 1fr);
        align-items: baseline;
        gap: 0.75rem;
    }

    /* Am Schreibtisch verrät die Spaltenstellung, was gemeint ist. */
    .entw-lauf span::before { content: none !important; }

    /*
     * Der aktuelle Stand je Aufgabe (Issue #87) – fünf Spalten, dieselbe
     * Stellung für Kopfzeile und Zeile. Die Spaltenmaße folgen den ersten
     * Spalten der Laufliste darunter, damit beide Listen fluchten: Nummer,
     * Titel, Zustand. Was danach kommt, ist bewusst schmaler – „3 Läufe, 2
     * fehlgeschlagen" ist eine Bilanz und keine Tabelle.
     */
    .entw-aufgabe,
    .entw-aufgaben-kopf {
        grid-template-columns:
            minmax(0, 5.5rem) minmax(0, 3fr) minmax(0, 2fr)
            minmax(0, 1.8fr) minmax(0, 1.4fr);
        gap: 0.75rem;
    }

    .entw-aufgabe { align-items: baseline; }
    .entw-aufgabe span::before { content: none !important; }

    .entw-aufgaben-kopf {
        display: grid;
        /* Links um Rahmen und Farbstreifen der Zeilen versetzt, damit die
         * Überschrift genau über ihrer Spalte steht. */
        padding: 0 0.75rem 0.4rem calc(0.75rem + 5px);
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        color: var(--text-still);
    }

    .entw-historie-kopf {
        display: grid;
        grid-template-columns:
            minmax(0, 5.5rem) minmax(0, 2.6fr) minmax(0, 1.2fr)
            minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1.5fr)
            minmax(0, 1.5fr) minmax(0, 1.5fr) minmax(0, 1fr);
        gap: 0.75rem;
        /* Links um Rahmen und Farbstreifen der Zeilen versetzt, damit die
         * Überschrift genau über ihrer Spalte steht. */
        padding: 0 0.75rem 0.4rem calc(0.75rem + 5px);
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        color: var(--text-still);
    }

    /* ── Die vollständige Laufhistorie (Issue #72) ──────────────────────── */
    /*
     * Die Filterfelder nebeneinander statt untereinander: Sie gehören zu einer
     * Frage („welche Läufe?") und sollen auch wie eine aussehen. Die
     * Schaltflächen bekommen die ganze Breite darunter.
     *
     * Vier Spalten und – seit dem Abnahmefilter und der Ansicht aus Issue #78 –
     * sechs Felder: Oben stehen Suche, Ergebnis, Abnahme und Ansicht, darunter
     * die beiden Datumsfelder in den ersten zwei Spalten. „Abgeschlossen bis"
     * landet damit in einer der schmalen; dass sein Datum dort trotzdem ganz
     * dasteht, hängt an der selbsttätigen Mindestgröße des Feldes weiter oben.
     */
    .entw-hist-filter {
        grid-template-columns:
            minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, 1.3fr) minmax(0, 1.3fr);
        align-items: end;
    }

    .entw-hist-tasten { grid-column: 1 / -1; }

    /*
     * Die Legende darf hier in eine Zeile: Vier Einträge nebeneinander sind
     * am Schreibtisch ein Streifen und keine Wortsäulen. Auf dem Telefon
     * bleibt es bei einem Eintrag je Zeile.
     *
     * Die gemeinsame Mindestbreite der vier Pillen fällt dabei weg: Sie richtet
     * die Erklärungen **untereinander** aus, und untereinander stehen sie hier
     * nicht mehr. Nebeneinander wäre sie nur zusätzliche Luft in „Rot".
     */
    .entw-legende {
        display: flex;
        flex-wrap: wrap;
        gap: 0.4rem 1rem;
    }

    .entw-legende .entw-pille { min-width: auto; }

    /* Sieben Spalten – dieselbe Stellung für Kopfzeile und Zeile. Die siebte
     * ist seit Issue #78 der Abnahmestatus; er steht neben dem technischen
     * Ergebnis, weil beides zusammen erst die Lage ergibt. */
    .entw-hist-zeile,
    .entw-hist-kopf {
        grid-template-columns:
            minmax(0, 4.5rem) minmax(0, 3fr) minmax(0, 1.3fr)
            minmax(0, 1.7fr) minmax(0, 1fr) minmax(0, 1.6fr) minmax(0, 1fr);
        gap: 0.75rem;
    }

    .entw-hist-zeile { align-items: baseline; }

    /*
     * Am Schreibtisch verrät die Spaltenstellung, was gemeint ist – die
     * Beschriftungen der Handyansicht fallen weg. Ausdrücklich aufgezählt und
     * nicht über `span::before`: Die Auf- und Zuklappmarke ist ebenfalls ein
     * `span` mit `::before`, und eine pauschale Regel löschte sie mit.
     */
    .entw-hist-zeile .entw-lauf-ergebnis::before,
    .entw-hist-zeile .entw-lauf-abnahme::before,
    .entw-hist-zeile .entw-lauf-dauer::before,
    .entw-hist-zeile .entw-lauf-zeit::before,
    .entw-hist-zeile .entw-lauf-commit::before { content: none !important; }

    .entw-hist-kopf {
        display: grid;
        /* Rechts um die Klappmarke versetzt, links um Rahmen und Farbstreifen –
         * dann steht jede Überschrift über ihrer Spalte. */
        padding: 0 2.25rem 0.4rem calc(0.75rem + 5px);
        font-size: 0.78rem;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        color: var(--text-still);
    }
}


/* ── Handbuch (Issue #56) ─────────────────────────────────────
 *
 * Ein Lesebereich, kein Arbeitswerkzeug. Deshalb gelten hier andere Maße als
 * im Sendeplan: eine begrenzte Zeilenlänge, mehr Zeilenabstand, deutliche
 * Abstände zwischen den Abschnitten. Alles, was hier steht, hängt an einer
 * `hb-`-Klasse und kann damit keine bestehende Seite verändern.
 *
 * Kein neuer Breakpoint: Die mobile Fassung steht unten im vorhandenen Block
 * `@media (max-width: 640px)`, dem Telefon-Breakpoint dieses Projekts.
 */

.hb-seite {
    /*
     * Die Zeilenlänge ist die wichtigste Einstellung eines Lesetexts. Bei
     * 1600 px Fensterbreite liefe eine Zeile sonst über den ganzen Schirm,
     * und das Auge fände den Anfang der nächsten nicht mehr.
     */
    max-width: 62rem;
    margin: 0 auto;
}

.hb-kopf { margin-bottom: 1.5rem; }

.hb-augenbraue {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-leise);
    margin-bottom: 0.3rem;
}

.hb-kopf h2 {
    font-size: 1.9rem;
    line-height: 1.2;
    margin-bottom: 0.5rem;
}

.hb-vorspann {
    font-size: 1.05rem;
    line-height: 1.6;
    color: var(--text-normal);
    max-width: 46rem;
}

.hb-abschnitt {
    margin: 2.5rem 0 1rem;
    font-size: 1.15rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--rand);
}

/* ── Brotkrumen ──────────────────────────────────────────── */

.hb-brotkrumen { margin-bottom: 1rem; }

.hb-brotkrumen ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    list-style: none;
    font-size: 0.85rem;
    color: var(--text-leise);
}

/* Der Trenner ist Dekoration und gehört deshalb nicht in den Text, den ein
   Vorleseprogramm ausgibt – `::before` steht dort nicht. */
.hb-brotkrumen li + li::before { content: "›"; margin-right: 0.35rem; }
.hb-brotkrumen a { color: var(--text-mittel); text-decoration: none; }
.hb-brotkrumen a:hover { text-decoration: underline; }
.hb-brotkrumen [aria-current="page"] { color: var(--text-stark); font-weight: 600; }

/* ── Suche ───────────────────────────────────────────────── */

.hb-suche {
    position: relative;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    padding: 1rem 1.1rem;
    margin-bottom: 1.5rem;
}

.hb-suche-beschriftung {
    display: block;
    font-weight: 600;
    margin-bottom: 0.45rem;
}

.hb-suche-zeile { display: flex; gap: 0.6rem; align-items: stretch; }

.hb-suche input[type="search"] {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--rand-stark);
    border-radius: 8px;
    font-size: 1rem;
    font-family: inherit;
}

.hb-suche input[type="search"]:focus {
    outline: 2px solid var(--kontur);
    outline-offset: 1px;
}

.hb-suche .hinweis { display: block; margin-top: 0.5rem; }

/*
 * Die Trefferliste beim Tippen. Sie liegt über dem Inhalt, damit die Seite
 * beim Tippen nicht wächst und wieder schrumpft – ein springendes Layout
 * unter dem Finger ist schlimmer als kein Vorschlag.
 */
.hb-vorschlaege {
    position: absolute;
    left: 1.1rem;
    right: 1.1rem;
    top: calc(100% - 0.5rem);
    z-index: 50;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand-stark);
    border-radius: 10px;
    box-shadow: var(--schatten-vorschlaege);
    padding: 0.6rem;
    max-height: 24rem;
    overflow-y: auto;
}

.hb-vorschlaege[hidden] { display: none; }

.hb-vorschlag-kopf {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-leise);
    padding: 0.2rem 0.4rem 0.5rem;
}

.hb-vorschlagsliste { list-style: none; }

.hb-vorschlag a {
    display: block;
    padding: 0.5rem 0.55rem;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
}

.hb-vorschlag a:hover, .hb-vorschlag a:focus { background: var(--flaeche-sanft); }

.hb-vorschlag-titel { display: block; font-weight: 600; color: var(--text-stark); }

.hb-vorschlag-bereich {
    display: block;
    font-size: 0.75rem;
    color: var(--text-leise);
    margin-bottom: 0.15rem;
}

.hb-vorschlag-ausschnitt {
    display: block;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--text-mittel);
}

.hb-vorschlag-alle {
    display: block;
    padding: 0.55rem;
    text-align: center;
    font-size: 0.9rem;
    font-weight: 600;
}

.hb-vorschlaege mark, .hb-treffer-ausschnitt mark {
    background: var(--treffer-flaeche);
    color: inherit;
    border-radius: 3px;
    padding: 0 0.1em;
}

/* ── Kapitelbaum ─────────────────────────────────────────── */

.hb-baum-bereich { margin-bottom: 1.75rem; }

.hb-baum-bereich h3 {
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-leise);
    margin-bottom: 0.6rem;
}

.hb-baum-liste { list-style: none; }

.hb-baum-eintrag {
    padding: 0.6rem 0.8rem;
    border-left: 3px solid var(--rand);
    margin-bottom: 0.35rem;
    background: var(--flaeche-karte);
    border-radius: 0 8px 8px 0;
}

.hb-baum-eintrag > a {
    font-weight: 600;
    color: var(--text-stark);
    text-decoration: none;
    display: block;
    /* Ein Kapitelverweis ist ein Tippziel wie jedes andere. */
    min-height: 24px;
}

.hb-baum-eintrag > a:hover { text-decoration: underline; }
.hb-baum-aktiv { border-left-color: var(--kontur); background: var(--flaeche-sanft); }

.hb-baum-kurz {
    display: block;
    font-size: 0.87rem;
    color: var(--text-leise);
    line-height: 1.45;
}

.hb-rollenmarke {
    display: inline-block;
    margin-top: 0.3rem;
    font-size: 0.75rem;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: var(--info-flaeche-zart);
    color: var(--info-text);
}

.hb-rollenmarke-gross { font-size: 0.85rem; padding: 0.25rem 0.7rem; }

/* ── Kapitelinhalt ───────────────────────────────────────── */

.hb-gliederung {
    /* Bezugspunkt für das Kästchen des Aufklappers, das auf dem Telefon
       absolut positioniert und unsichtbar, aber fokussierbar ist. */
    position: relative;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    padding: 0.85rem 1.1rem;
    margin-bottom: 1.75rem;
}

/*
 * Am Schreibtisch gibt es keinen Schalter: Der Kasten steht offen da, und
 * Kästchen und Beschriftung nehmen keinen Platz ein. Erst der Telefonblock
 * unten dreht das um.
 */
.hb-gliederung-schalter,
.hb-gliederung-schalter-marke { display: none; }

.hb-gliederung-titel { font-weight: 600; }

.hb-gliederung ol { list-style: none; margin-top: 0.6rem; }
.hb-gliederung li { padding: 0.15rem 0; }
.hb-gliederung-stufe3 { padding-left: 1.1rem; font-size: 0.9rem; }
.hb-gliederung a { color: var(--text-normal); }

.hb-inhalt {
    font-size: 1rem;
    line-height: 1.7;
    color: var(--text-lesetext);
}

.hb-inhalt p { margin-bottom: 1rem; max-width: 46rem; }

.hb-ueberschrift {
    /*
     * `scroll-margin-top` ist hier nicht Kosmetik: Der Kopfbereich klebt oben
     * (`position: sticky`). Ohne diesen Abstand landete eine angesprungene
     * Überschrift genau dahinter und wäre unsichtbar – gerade beim Sprung aus
     * der Trefferliste, dem häufigsten Weg in ein Kapitel.
     */
    scroll-margin-top: 5rem;
    margin: 2rem 0 0.8rem;
    line-height: 1.3;
    position: relative;
}

h3.hb-ueberschrift { font-size: 1.35rem; }
h4.hb-ueberschrift { font-size: 1.1rem; margin-top: 1.5rem; }

/* Der Verweis auf den eigenen Abschnitt. Er erscheint erst beim Überfahren
   oder bei Tastaturfokus – sichtbar wäre er ein Zeichensalat vor jeder
   Überschrift, und auf dem Telefon gäbe es kein Überfahren. */
.hb-ankerlink {
    position: absolute;
    left: -1.1rem;
    color: var(--text-still);
    text-decoration: none;
    opacity: 0;
}

.hb-ueberschrift:hover .hb-ankerlink, .hb-ankerlink:focus { opacity: 1; }

.hb-liste { margin: 0 0 1.2rem 1.3rem; max-width: 46rem; }
.hb-liste li { margin-bottom: 0.4rem; }

/*
 * Schrittfolgen als abgesetzte Karten mit großer Nummer.
 *
 * Der Auftrag verlangt ausdrücklich, dass Schrittfolgen „visuell gut erfassbar"
 * sind und keine Textwüste. Eine gewöhnliche `ol` mit kleinen Ziffern am Rand
 * erfüllt das nicht: Wer eine Anleitung mit dem Gerät in der Hand abarbeitet,
 * muss die Stelle nach jedem Blick wiederfinden.
 */
.hb-schritte {
    list-style: none;
    counter-reset: hb-schritt;
    margin: 0 0 1.5rem;
    max-width: 46rem;
}

.hb-schritte li {
    counter-increment: hb-schritt;
    position: relative;
    padding: 0.7rem 0.9rem 0.7rem 3rem;
    margin-bottom: 0.5rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
}

.hb-schritte li::before {
    content: counter(hb-schritt);
    position: absolute;
    left: 0.75rem;
    top: 0.6rem;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 50%;
    background: var(--fuellung);
    color: var(--fuellung-text);
    font-weight: 700;
    font-size: 0.9rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ── Hinweiskästen ───────────────────────────────────────── */

/*
 * Fünf Sorten plus der Rollenhinweis, jede mit eigener Farbe **und** eigener
 * Überschrift. Die Farbe allein wäre zu wenig: Wer sie nicht unterscheiden
 * kann, liest die Überschrift.
 */
.hb-kasten {
    border-left: 4px solid var(--rand-still);
    background: var(--flaeche-zart);
    border-radius: 0 10px 10px 0;
    padding: 0.85rem 1.1rem;
    margin: 0 0 1.25rem;
    max-width: 46rem;
}

.hb-kasten p { margin-bottom: 0; }

.hb-kasten-titel {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
    margin-bottom: 0.3rem !important;
}

.hb-kasten-hinweis { border-left-color: var(--hinweis-kante); background: var(--hinweis-flaeche); }
.hb-kasten-hinweis .hb-kasten-titel { color: var(--hinweis-text); }

.hb-kasten-voraussetzung { border-left-color: var(--voraussetzung-kante); background: var(--voraussetzung-flaeche); }
.hb-kasten-voraussetzung .hb-kasten-titel { color: var(--voraussetzung-text); }

.hb-kasten-warnung { border-left-color: var(--fehler-kraeftig); background: var(--gefahr-flaeche-zart); }
.hb-kasten-warnung .hb-kasten-titel { color: var(--fehler-text); }

.hb-kasten-ergebnis { border-left-color: var(--erfolg-zart-kante); background: var(--erfolg-zart-flaeche); }
.hb-kasten-ergebnis .hb-kasten-titel { color: var(--erfolg-zart-text); }

.hb-kasten-fehler { border-left-color: var(--warnung-kraeftig); background: var(--warnung-flaeche-blass); }
.hb-kasten-fehler .hb-kasten-titel { color: var(--warnung-mittel); }

.hb-kasten-rolle { border-left-color: var(--info-kante); background: var(--info-flaeche-zart); }
.hb-kasten-rolle .hb-kasten-titel { color: var(--info-text); }

.hb-start-hinweise { margin-bottom: 1rem; }

/* ── PDF-Ausgabe ─────────────────────────────────────────────
   Die Aktion steht auf der Startseite offen da und nicht in einem Menü: Wer
   das Handbuch weitergeben oder ausdrucken will, soll nicht danach suchen.
   Die Schaltfläche selbst ist die gewöhnliche `.schaltflaeche` – dadurch gilt
   auch auf dem Telefon die 44-px-Regel aus Issue #43, ohne eine zweite. */

.hb-pdf {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    flex-wrap: wrap;
    background: var(--flaeche-zart);
    border: 1px solid var(--rand);
    border-radius: 10px;
    padding: 0.9rem 1.1rem;
    margin-bottom: 1.25rem;
}

.hb-pdf-text { flex: 1 1 18rem; font-size: 0.9rem; color: var(--text-mittel); line-height: 1.5; }

.hb-pdf-text strong { display: block; color: var(--text-stark); }

/* ── Bilder ──────────────────────────────────────────────── */

.hb-bild { margin: 0 0 1.5rem; max-width: 46rem; }

/* Der Zeiger sagt vorher, was der Klick tut: vergrößern. */
.hb-bild-verweis { display: block; cursor: zoom-in; }

.hb-bild img {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--rand);
    border-radius: 10px;
    background: var(--bild-unterlage);
}

.hb-bild figcaption {
    font-size: 0.85rem;
    color: var(--text-leise);
    line-height: 1.5;
    margin-top: 0.45rem;
}

/* ── Die vergrößerte Bildansicht (Issue #61) ─────────────────
   Sie entsteht erst durch `static/handbuch-lupe.js`; ohne Skript gibt es
   keinen `.hb-lupe`-Knoten und diese Regeln greifen an nichts.

   Die Ansicht ist das ganze Fenster und kein Kasten in der Mitte: Ein
   Screenshot des Schreibtischs braucht jeden Pixel Breite, den ein Telefon
   hergibt. Aufgeteilt ist sie in zwei Teile, und diese Trennung ist der Kern
   der Sache:

     .hb-lupe-flaeche     scrollt – hier liegt das Bild, das höher sein darf
                          als das Fenster
     .hb-lupe-schliessen  scrollt nicht – das X liegt daneben in der Ansicht
                          selbst und steht deshalb immer an derselben Stelle

   Waagerecht wird nirgends gescrollt: Das Bild ist nie breiter als die
   Fläche. */

.hb-lupe {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    background: rgba(15, 23, 42, 0.94);
}

.hb-lupe::backdrop { background: rgba(15, 23, 42, 0.94); }

.hb-lupe-flaeche {
    position: absolute;
    inset: 0;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    /* Oben bleibt Platz für das X: Beim Öffnen liegt es neben dem Bild und
       nicht darauf. Wird ein hohes Bild gescrollt, schiebt sich Bildinhalt
       darunter – dafür hat das X seinen Ring und seinen Schatten. */
    padding: 4.75rem 1.25rem 2.5rem;
    /* Der abgedunkelte Rand ist selbst ein Bedienelement: ein Klick darauf
       schließt. */
    cursor: zoom-out;
}

.hb-lupe-figur { margin: 0; }

.hb-lupe-bild {
    display: block;
    margin: 0 auto;
    max-width: 100%;
    height: auto;
    border-radius: 6px;
    background: var(--bild-unterlage);
    cursor: default;
}

.hb-lupe-unterschrift {
    max-width: 46rem;
    margin: 0.85rem auto 0;
    color: #e5e7eb;
    font-size: 0.9rem;
    line-height: 1.5;
    text-align: center;
    cursor: default;
}

.hb-lupe-schliessen {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Deutlich über der 44-px-Untergrenze dieses Projekts: Das X ist auf dem
       Telefon das einzige Bedienelement der Ansicht. */
    min-width: 48px;
    min-height: 48px;
    padding: 0;
    border-radius: 50%;
    /* Gegen jeden Bildinhalt: dunkle Fläche, weißer Ring, weißes Zeichen.
       Ein heller Screenshot dahinter lässt den Ring stehen, ein dunkler die
       Fläche – verschmelzen kann das X mit keinem von beiden. */
    border: 2px solid #ffffff;
    background: #111827;
    color: #ffffff;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.55);
    cursor: pointer;
}

.hb-lupe-schliessen:hover { background: #374151; }

.hb-lupe-schliessen:focus-visible {
    outline: 3px solid #93c5fd;
    outline-offset: 2px;
}

.hb-lupe-kreuz { font-size: 1.75rem; line-height: 1; }

/* Solange die Ansicht offen ist, scrollt die Seite darunter nicht mit. Die
   Stelle im Kapitel bleibt damit stehen, wo sie war; das Skript setzt sie
   beim Schließen zusätzlich ausdrücklich zurück. */
.hb-lupe-offen, .hb-lupe-offen body { overflow: hidden; }

/* ── Blättern ────────────────────────────────────────────── */

.hb-blaettern {
    display: flex;
    gap: 1rem;
    margin: 2.5rem 0 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--rand);
}

.hb-blaettern-seite { flex: 1 1 0; min-width: 0; }
.hb-blaettern-rechts { text-align: right; }

.hb-blaettern a {
    display: block;
    padding: 0.7rem 0.9rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    text-decoration: none;
    color: inherit;
    /* Vor und Zurück sind Tippziele – hier gilt dieselbe Untergrenze wie
       überall sonst im Backend. */
    min-height: 44px;
}

.hb-blaettern a:hover { border-color: var(--rand-still); }

.hb-blaettern-marke {
    display: block;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-leise);
}

.hb-blaettern-titel { display: block; font-weight: 600; color: var(--text-stark); }

.hb-fussbereich { margin-top: 2rem; }

/* ── Trefferliste ────────────────────────────────────────── */

.hb-trefferbilanz {
    font-size: 0.9rem;
    color: var(--text-leise);
    margin-bottom: 0.75rem;
}

.hb-treffer { list-style: none; }

.hb-treffer-eintrag {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    padding: 0.85rem 1.1rem;
    margin-bottom: 0.6rem;
}

.hb-treffer-titel {
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--text-stark);
    text-decoration: none;
}

.hb-treffer-titel:hover { text-decoration: underline; }

.hb-treffer-bereich {
    display: block;
    font-size: 0.75rem;
    color: var(--text-leise);
    margin-bottom: 0.3rem;
}

.hb-treffer-ausschnitt {
    font-size: 0.92rem;
    line-height: 1.55;
    color: var(--text-mittel);
}

.hb-leer {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    padding: 1.1rem;
}

.hb-leer p { margin-bottom: 0.6rem; }


/*
 * Die mobile Fassung des Handbuchs – im vorhandenen Telefon-Breakpoint.
 *
 * Der Auftrag nennt die Hochkantansicht ausdrücklich. Drei Dinge ändern sich:
 * die Zeilenlängenbegrenzung fällt weg (bei 390 px gibt es nichts zu
 * begrenzen), die Gliederung eines Kapitels steht zugeklappt statt offen, und
 * Vor/Zurück stehen untereinander statt nebeneinander – zwei Kacheln in einer
 * 390-px-Zeile wären zwei Wortsalate.
 */
@media (max-width: 640px) {
    .hb-seite { max-width: none; }
    .hb-kopf h2 { font-size: 1.5rem; }
    .hb-vorspann { font-size: 1rem; max-width: none; }
    .hb-inhalt p, .hb-liste, .hb-schritte, .hb-kasten, .hb-bild { max-width: none; }

    .hb-suche { padding: 0.85rem; }
    .hb-suche-zeile { flex-direction: column; }
    .hb-suche input[type="search"] { min-height: 44px; }
    .hb-vorschlaege { left: 0.5rem; right: 0.5rem; max-height: 60vh; }
    .hb-vorschlag a { min-height: 44px; }

    /*
     * Zugeklappt: Der Weg zur ersten Zeile Text ist auf dem Telefon kostbar,
     * und eine Gliederung über sieben Zeilen wäre genau der Umweg, den der
     * Auftrag „nicht als Textwüste" meint.
     *
     * Die Liste ist da, sie steht nur nicht offen – ein Fingertipp auf die
     * Beschriftung holt sie hervor. Aus dem Dokument verschwindet sie nicht:
     * Ein Vorleseprogramm findet sie, und ein Sprungziel bleibt gültig.
     */
    .hb-gliederung-titel { display: none; }
    .hb-gliederung > ol { display: none; }
    .hb-gliederung-schalter:checked ~ ol { display: block; }

    .hb-gliederung-schalter-marke {
        display: flex;
        align-items: center;
        min-height: 44px;
        font-weight: 600;
        cursor: pointer;
    }

    .hb-gliederung-schalter-marke::before {
        content: "▸";
        margin-right: 0.5rem;
        color: var(--text-leise);
    }

    .hb-gliederung-schalter:checked ~ .hb-gliederung-schalter-marke::before {
        content: "▾";
    }

    /* Für die Tastatur sichtbar, für das Auge nicht: Das Kästchen selbst
       bleibt fokussierbar, ohne neben der Beschriftung zu stehen. */
    .hb-gliederung-schalter {
        display: block;
        position: absolute;
        opacity: 0;
        width: 1px;
        height: 1px;
    }

    .hb-gliederung-schalter:focus-visible ~ .hb-gliederung-schalter-marke {
        outline: 2px solid var(--kontur);
        outline-offset: 2px;
    }

    /* Ein umbrechender Eintrag soll zwei enge Zeilen ergeben und nicht zwei
       44 px hohe – deshalb ein Mindestmaß und keine feste Zeilenhöhe. */
    .hb-gliederung a {
        display: flex;
        align-items: center;
        min-height: 44px;
        line-height: 1.35;
    }

    .hb-baum-eintrag { padding: 0.55rem 0.7rem; }
    .hb-baum-eintrag > a { min-height: 44px; display: flex; align-items: center; }

    .hb-blaettern { flex-direction: column; }
    .hb-blaettern-rechts { text-align: left; }

    .hb-treffer-titel { display: flex; align-items: center; min-height: 44px; }

    /* Der Ankerlink hätte auf dem Telefon kein Überfahren, unter dem er
       erscheinen könnte – dort steht er gar nicht erst. */
    .hb-ankerlink { display: none; }

    /*
     * Die vergrößerte Bildansicht auf dem Telefon.
     *
     * Der seitliche Rand schrumpft – bei 390 px zählt jeder Pixel Bildbreite –,
     * der Platz über dem Bild bleibt: Er ist es, der das X vom Bildinhalt
     * trennt. Das X selbst wird nicht kleiner, sondern rückt näher an die
     * Ecke; 48 px sind auch hier die Tippfläche, und zum Rand bleiben
     * sichtbare 10 px, damit es nicht am Displayrand klebt.
     */
    .hb-lupe-flaeche { padding: 4.5rem 0.5rem 1.5rem; }
    .hb-lupe-schliessen {
        top: 0.625rem;
        right: 0.625rem;
        min-width: 48px;
        min-height: 48px;
    }
    .hb-lupe-unterschrift { max-width: none; font-size: 0.85rem; }
}

/* ── Rollen & Rechte (Issue #68) ────────────────────────────── */

/*
 * Die Rollenkarten – dieselbe Bauform wie die Benutzerkarten daneben, nur
 * breiter: Auf einer Rollenkarte stehen zwei Listen (wer sie hat, was sie
 * darf), und die brauchen mehr Zeile als Kennung und E-Mail-Adresse.
 */
.rollenkarten {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(26rem, 100%), 1fr));
    gap: 0.9rem;
    margin-bottom: 1.4rem;
}

.rollenkarte {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    padding: 1rem 1.1rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 10px;
    box-shadow: var(--schatten-zart);
}
.rollenkarte:hover { border-color: var(--rand-akzent); }

.rollenkarte-kopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.rollenkarte-name { margin: 0; font-size: 1rem; }
.rollenkarte-beschreibung {
    margin: 0;
    font-size: 0.88rem;
    color: var(--text-mittel);
}

.rollenkarte-abschnitt h4 {
    margin: 0 0 0.3rem;
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-still);
}
/* Die Zahl gehört zur Überschrift und nicht daneben – sie beantwortet die
   Frage „wie viele" ohne eine zweite Zeile. */
.rollenkarte-zahl {
    display: inline-block;
    min-width: 1.4rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background: var(--flaeche-sanft);
    color: var(--text-mittel);
    font-size: 0.78rem;
    text-align: center;
    letter-spacing: 0;
}

.rollenkarte-benutzer {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.86rem;
    color: var(--text-normal);
}
.rollenkarte-benutzer li { margin-bottom: 0.15rem; }

.rollenkarte-rechte {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.84rem;
}
.rollenkarte-rechte li {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 0.6rem;
    padding: 0.2rem 0;
    border-bottom: 1px solid var(--rand-zart);
}
.rollenkarte-rechte li:last-child { border-bottom: none; }
.rollenkarte-bereich { flex: 0 0 9rem; color: var(--text-mittel); }
.rollenkarte-verben { flex: 1 1 10rem; color: var(--text-leise); }

/*
 * Der Aufklapper der Rollenkarte gehört dem Telefon.
 *
 * Am Schreibtisch steht die Rechteliste offen – dort ist sie eine Spalte neben
 * anderen und kein Weg, den man scrollt. Kästchen, Beschriftung und die
 * Kurzfassung sind hier deshalb `display: none`; die Karte sieht aus wie vorher.
 */
.rollen-klapp-schalter,
.rollen-klapp-taste,
.rollenkarte-rechte-summe { display: none; }

.rollenkarte-aktionen {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    align-items: center;
    margin-top: auto;
    padding-top: 0.6rem;
    border-top: 1px solid var(--rand-zart);
}

.rollen-fusshinweis { max-width: 62rem; }
.rollen-zuordnung { margin-top: 1.6rem; }
.rollen-zuordnung h3 { font-size: 1rem; margin-bottom: 0.4rem; }

/*
 * Das Rollenformular ist breiter als die anderen.
 *
 * Wie viel breiter, steht seit Issue #76 nicht mehr hier, sondern einmal je
 * Seite bei `--flucht`: Der Wrapper liest die Klasse dieses Formulars und
 * setzt daraus die Flucht, an der sich auch die Zuordnungsliste und der
 * Löschbereich darunter ausrichten. Vorher stand die Zahl nur an dieser
 * Regel – und die beiden Kacheln darunter waren so breit wie der Wrapper.
 *
 * `width: 100%` sorgt dafür, dass daraus auf schmalen Fenstern nichts wird:
 * `max-width` ist eine Obergrenze, keine Vorgabe.
 */
.formular-rollen { width: 100%; }

/*
 * Die Rechte-Matrix.
 *
 * Ein Raster und keine Tabelle: Auf dem Schreibtisch stehen die vier Aktionen
 * als Spalten, auf dem Telefon rutschen sie unter den Bereichsnamen und werden
 * zu einer umbrechenden Reihe. Dafür genügt es, `grid-template-columns` zu
 * ändern – dasselbe HTML trägt beide Formen, und es gibt keine zweite Matrix
 * für schmale Fenster, die man mitpflegen müsste.
 *
 * `display: contents` an `.rechte-zellen` löst den Zwischenkasten auf dem
 * Schreibtisch auf, damit die Zellen direkt im Raster der Zeile liegen. Auf dem
 * Telefon wird derselbe Kasten wieder sichtbar und zur umbrechenden Reihe.
 */
.rechte-matrix {
    border: 1px solid var(--rand);
    border-radius: 8px;
    overflow: hidden;
}

.rechte-kopf,
.rechte-zeile {
    display: grid;
    grid-template-columns: minmax(0, 1fr) repeat(4, 6.5rem);
    align-items: center;
    gap: 0.4rem;
    padding: 0.55rem 0.8rem;
}

.rechte-kopf {
    background: var(--fuellung);
    color: var(--fuellung-text);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.rechte-kopf .rechte-spalte { text-align: center; }
.rechte-kopf .rechte-bereich { color: var(--fuellung-text-leise); }

.rechte-zeile { border-top: 1px solid var(--rand-zart); }
.rechte-zeile:nth-child(odd) { background: var(--flaeche-still); }

.rechte-bereich { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.rechte-bereich-titel { font-weight: 600; color: var(--text-stark); font-size: 0.92rem; }
.rechte-bereich-kurz { font-size: 0.78rem; color: var(--text-leise); }

.rechte-zellen { display: contents; }

/*
 * Eine Zelle ist die Tippfläche – nicht das Kästchen darin. 44 px sind das
 * Maß, das dieses Projekt überall für den Finger ansetzt.
 */
.rechte-zelle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-height: 44px;
    border-radius: 6px;
    cursor: pointer;
}
.rechte-zelle:hover { background: var(--flaeche-zart); }
.rechte-zelle input[type="checkbox"] { width: 1.05rem; height: 1.05rem; cursor: pointer; }

/* Auf dem Schreibtisch sagt die Spaltenüberschrift, welches Verb gemeint ist –
   der Text an der Zelle bleibt für Vorlesewerkzeuge da und nur für sie. */
.rechte-verb {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Eine Aktion, die es in diesem Bereich nicht gibt: ein Strich, kein Kästchen. */
.rechte-zelle-leer { color: var(--text-still); cursor: default; }
.rechte-zelle-leer:hover { background: none; }

/* Ein festgesetztes Häkchen der Systemrolle. Sichtbar anders, damit niemand
   vergeblich daran klickt – und mit dem Grund im `title`. */
.rechte-zelle-fest { cursor: not-allowed; background: var(--flaeche-gesperrt); }
.rechte-zelle-fest input[type="checkbox"] { cursor: not-allowed; }

.rechte-alles {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.2rem;
    font-size: 0.78rem;
    color: var(--text-leise);
    cursor: pointer;
}
.rechte-alles input[type="checkbox"] { width: 0.95rem; height: 0.95rem; }
/*
 * `hidden` an einem Element, dem das Stylesheet ein `display` gibt, wirkt
 * nicht: Eine Autorenregel schlägt die des Browsers, gleich welcher
 * Spezifität. Ohne diese Zeile stünde die Sammelaktion auch ohne JavaScript
 * da – als Kästchen, das niemand einsammelt.
 */
.rechte-alles[hidden] { display: none; }

/*
 * Der Aufklapper eines Rechtebereichs gehört ebenfalls dem Telefon. Am
 * Schreibtisch trägt die Zeile ihre vier Spalten und ist damit fertig.
 */
.rechte-klapp-schalter,
.rechte-klapp-taste { display: none; }

/*
 * Der Laptop. Vier Spalten zu 6,5 rem plus Bereichsname passen ab etwa
 * 900 px bequem; darunter werden die Spalten schmaler, bevor sie ganz
 * umbrechen.
 */
@media (max-width: 900px) {
    .rechte-kopf,
    .rechte-zeile { grid-template-columns: minmax(0, 1fr) repeat(4, 4.6rem); }
    .rechte-bereich-kurz { display: none; }
}

/*
 * Das Telefon. Die Spalten verschwinden, die Aktionen rücken unter den
 * Bereichsnamen und tragen ihre Beschriftung wieder sichtbar – ohne
 * Spaltenkopf wüsste sonst niemand, welches Kästchen welches ist.
 */
@media (max-width: 640px) {
    .rechte-kopf { display: none; }
    .rechte-zeile { grid-template-columns: minmax(0, 1fr); gap: 0.3rem; }
    .rechte-bereich-kurz { display: block; }

    .rechte-zellen {
        display: flex;
        flex-wrap: wrap;
        gap: 0.3rem 0.5rem;
    }
    /*
     * Die Grundbreite ist eine Untergrenze, keine Vorgabe: Die Kästchen füllen
     * die Zeile und brechen um, sobald der Platz nicht mehr reicht. Auf einem
     * 390 px breiten Telefon bleibt der Zellenreihe so wenig Raum, dass jedes
     * für sich steht – das ist dort das richtige Ergebnis, denn ein 44 px
     * hoher Streifen mit lesbarer Beschriftung trifft sich mit dem Daumen. Auf
     * einem breiteren Gerät rücken sie von selbst nebeneinander.
     */
    .rechte-zelle {
        justify-content: flex-start;
        flex: 1 1 7rem;
        padding: 0 0.5rem;
        border: 1px solid var(--rand-zart);
        background: var(--flaeche-karte);
    }
    /*
     * Auf dem Telefon fällt weg, was es nicht gibt.
     *
     * Auf dem Schreibtisch steht in der Spalte ein Strich – dort trägt die
     * Spaltenüberschrift die Bedeutung, und die Zeile bliebe ohne Platzhalter
     * lückenhaft. Hier gibt es keine Spalten: Ein Kästchen mit dem Text
     * „Anlegen: gibt es hier nicht" wäre eine volle Zeile Bildschirm für eine
     * Auskunft, die niemand gesucht hat. Vier Bereiche kennen nur „Sehen“ –
     * ohne diese Regel wären das zwölf Zeilen zusätzliches Scrollen.
     */
    .rechte-zelle-leer { display: none; }
    .rechte-verb {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        overflow: visible;
        clip-path: none;
        font-size: 0.85rem;
        color: var(--text-normal);
    }
    .rechte-zelle-leer .rechte-verb { color: var(--text-still); }

    .rollenkarte-bereich { flex: 1 1 100%; }
}

/* ── Rollen & Rechte auf dem Telefon: verdichtet ─────────────────────────────
 *
 * Die Nacharbeit zur Abnahme von Issue #68. Was vorher stand, war responsiv:
 * nichts lief über den Rand, jede Tippfläche traf ihre 44 px. Was fehlte, war
 * Verdichtung – dieselbe Unterscheidung, die schon der Mobile-Audit (#35) für
 * Personen und Klärungen getroffen hat.
 *
 * Gemessen bei 375 px am Bestand mit sechs Rollen:
 *
 *   * **Die Rollenübersicht.** Jede Karte schrieb alle Bereiche der Rolle mit
 *     ihren Verben aus. Die Systemrolle allein sind zwölf Zeilen, und
 *     „Bearbeiten“ und „Löschen“ stehen darunter: Wer eine Rolle ändern will,
 *     scrollt zuerst an ihren Rechten vorbei. Genau der Befund, den der Audit
 *     für das Klärungsarchiv beschreibt.
 *   * **Der Rechte-Editor.** Zwölf Bereiche, je bis zu vier Kästchen in voller
 *     Zeilenbreite und darüber „alles in diesem Bereich“ – eine Maske, durch
 *     die man nur noch fährt.
 *   * **Der Kopf der Maske.** `.seite-kopf` ist `space-between`: Bei „Rolle
 *     bearbeiten: <langer Name>“ rutschte der Rückweg unter die Überschrift,
 *     bei „Neue Rolle“ blieb er daneben stehen. Dieselbe Maske, zwei Bilder.
 *
 * Das Mittel ist überall dasselbe und in diesem Projekt eingeführt: ein
 * Kontrollkästchen mit Beschriftung, kein Skript – wie beim Hauptmenü (#26),
 * bei „Ansicht“ im Sendeplan (#44) und beim Klärungsarchiv (#46). Zugeklappt
 * ist der Ausgangszustand; was zugeklappt ist, bleibt beziffert. An der
 * Rechte-Logik ändert sich nichts: Ein zugeklappter Bereich ist unsichtbar,
 * und ein unsichtbares Kontrollkästchen wird mit abgeschickt.
 *
 * Der Schreibtisch bleibt außen vor – alle Regeln stehen in dieser
 * Medienabfrage, und die Kästchen selbst sind außerhalb `display: none`.
 */
@media (max-width: 640px) {

    /* ── 1) Die Rollenübersicht ────────────────────────────────────────── */

    /* Weniger Polster, dieselbe Karte – die Dichte der Listen aus #45. */
    .rollenkarte {
        gap: 0.55rem;
        padding: 0.8rem 0.75rem;
    }

    .rollenkarte-rechteblock { position: relative; }

    /*
     * Der Rollenname ist freier Text und kann so lang sein, wie ein Admin ihn
     * tippt – „Programmredaktion mit Sendungspflege“ ragte bei 320 px zwei
     * Pixel über den Rand hinaus, und die Seite bekam eine waagerechte
     * Bildlaufleiste für zwei Pixel. Eine Marke ist sonst kurz und darf
     * deshalb `white-space: nowrap` tragen; diese eine trägt einen Namen und
     * bricht auf dem Telefon um.
     */
    .rollenkarte-name .marke {
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /*
     * Überschrift und Schalter in einer Zeile: Links steht, wie viele Rechte
     * die Rolle hat, rechts kommt man an sie heran.
     */
    .rollenkarte-rechte-kopf {
        display: flex;
        align-items: center;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: 0.3rem 0.6rem;
    }
    .rollenkarte-rechte-kopf h4 { margin: 0; }

    /*
     * Sichtbar ausgeblendet, für die Tastatur erreichbar – `display: block`
     * steht hier ausdrücklich, weil das Kästchen außerhalb dieser Abfrage
     * `display: none` ist und damit auch der Tastatur fehlte.
     */
    .rollen-klapp-schalter {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .rollen-klapp-taste {
        display: inline-flex;
        align-items: center;
        gap: 0.4rem;
        /* Ein Tippziel, kein Textlink – dasselbe Maß wie überall seit #43. */
        min-height: 44px;
        padding: 0 0.7rem;
        border: 1px solid var(--rand-stark);
        border-radius: 6px;
        background: var(--flaeche-zart);
        font-size: 0.85rem;
        font-weight: 600;
        color: var(--text-normal);
        cursor: pointer;
        /* Sonst markiert ein zweites Antippen die Beschriftung. */
        -webkit-user-select: none;
        user-select: none;
    }
    .rollen-klapp-schalter:focus-visible ~ .rollenkarte-rechte-kopf .rollen-klapp-taste {
        outline: 2px solid var(--kontur);
        outline-offset: 2px;
    }
    /*
     * Das Dreieck als Ränder eines leeren Kastens statt als Schriftzeichen –
     * derselbe Grund wie bei „Ansicht“: „▸“ fehlt in manchen Systemschriften
     * und wäre dort ein Ersatzkästchen.
     */
    .rollen-klapp-pfeil {
        width: 0;
        height: 0;
        border: 4px solid transparent;
        border-bottom: 0;
        border-top-color: currentColor;
    }
    .rollen-klapp-schalter:checked ~ .rollenkarte-rechte-kopf .rollen-klapp-pfeil {
        border-top: 0;
        border-bottom: 4px solid currentColor;
    }

    /* Die Beschriftung sagt, was der nächste Tipp tut. */
    .rollen-klapp-zu { display: none; }
    .rollen-klapp-schalter:checked ~ .rollenkarte-rechte-kopf .rollen-klapp-auf { display: none; }
    .rollen-klapp-schalter:checked ~ .rollenkarte-rechte-kopf .rollen-klapp-zu { display: inline; }

    /*
     * Zugeklappt ist der Ausgangszustand. Statt der ausgeschriebenen Liste
     * steht dort die Kurzfassung: wie viele Rechte, in welchen Bereichen. Das
     * ist die Auskunft, für die man eine Übersicht öffnet – die Verben je
     * Bereich sind die Frage danach.
     */
    .rollenkarte-rechte-summe {
        display: block;
        margin: 0;
        font-size: 0.84rem;
        line-height: 1.4;
        color: var(--text-leise);
    }
    .rollenkarte-rechte-voll { display: none; }
    .rollen-klapp-schalter:checked ~ .rollenkarte-rechte-summe { display: none; }
    .rollen-klapp-schalter:checked ~ .rollenkarte-rechte-voll { display: block; }

    /*
     * „Bearbeiten“ und „Löschen“ teilen sich die Zeile. Beide tragen ihre
     * Beschriftung vollständig, beide sind 44 px hoch, und mit zugeklappten
     * Rechten stehen sie wieder in Daumenreichweite unter dem Kartenkopf.
     * `.rollenkarte-aktionen form` ist der Kasten um „Löschen“ – ohne diese
     * Zeile wüchse der Knopf nicht mit.
     */
    .rollenkarte-aktionen { gap: 0.5rem; }
    .rollenkarte-aktionen form { flex: 1 1 8rem; display: flex; }
    .rollenkarte-aktionen > .schaltflaeche,
    .rollenkarte-aktionen form > .schaltflaeche {
        flex: 1 1 8rem;
        min-height: 44px;
        white-space: nowrap;
    }

    /* ── 2) Der Rechte-Editor ──────────────────────────────────────────── */

    /*
     * Bezugspunkt für das ausgeblendete Kästchen der Zeile. Ohne ihn hinge es
     * am nächsten positionierten Vorfahren und könnte die Seite verbreitern.
     */
    .rechte-zeile { position: relative; }

    .rechte-klapp-schalter {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
    .rechte-klapp-taste {
        display: inline-flex;
        align-items: center;
        align-self: flex-start;
        gap: 0.4rem;
        min-height: 44px;
        margin-top: 0.15rem;
        padding: 0 0.7rem;
        border: 1px solid var(--rand-stark);
        border-radius: 6px;
        background: var(--flaeche-zart);
        font-size: 0.85rem;
        font-weight: 600;
        color: var(--text-normal);
        cursor: pointer;
        -webkit-user-select: none;
        user-select: none;
    }
    .rechte-klapp-schalter:focus-visible ~ .rechte-bereich .rechte-klapp-taste {
        outline: 2px solid var(--kontur);
        outline-offset: 2px;
    }
    .rechte-klapp-pfeil {
        width: 0;
        height: 0;
        border: 4px solid transparent;
        border-bottom: 0;
        border-top-color: currentColor;
    }
    .rechte-klapp-schalter:checked ~ .rechte-bereich .rechte-klapp-pfeil {
        border-top: 0;
        border-bottom: 4px solid currentColor;
    }

    /*
     * Der Stand des zugeklappten Bereichs: „2 von 4“. Er kommt gezählt vom
     * Server und wird vom Skript fortgeschrieben. Dass überhaupt etwas gesetzt
     * ist, sagt zusätzlich die Farbe – und die hängt an `:has()` und damit am
     * Kästchen selbst, nicht am Skript: Ohne JavaScript stimmt sie trotzdem.
     */
    .rechte-klapp-stand {
        padding: 0.05rem 0.4rem;
        border-radius: 999px;
        background: var(--flaeche-sanft);
        font-size: 0.78rem;
        font-weight: 600;
        color: var(--text-leise);
    }
    .rechte-zeile:has(input[name="recht"]:checked) .rechte-klapp-stand {
        background: var(--flaeche-gewaehlt);
        color: var(--text-stark);
    }

    /*
     * Zugeklappt ist der Ausgangszustand: Sichtbar sind Bereichsname, Kurztext
     * und der Stand. „alles in diesem Bereich“ und die einzelnen Kästchen
     * kommen auf Antippen – die Sammelaktion gehört zu den Rechten, die sie
     * setzt, und stünde darüber allein in der Luft.
     */
    .rechte-klapp-schalter:not(:checked) ~ .rechte-zellen { display: none; }
    .rechte-klapp-schalter:not(:checked) ~ .rechte-bereich .rechte-alles { display: none; }
    /* Aufgeklappt ist die Sammelaktion selbst ein Tippziel. */
    .rechte-alles {
        min-height: 44px;
        font-size: 0.85rem;
    }

    /* ── 3) Der Kopf der Maske und ihre Abstände ───────────────────────── */

    /*
     * Überschrift oben, Rückweg darunter – unabhängig davon, wie lang der
     * Rollenname ist. Der Rückweg bleibt so breit wie seine Beschriftung: Eine
     * Schaltfläche über die volle Zeile läse sich als das Wichtigste der Seite,
     * und das ist sie nicht.
     */
    .seite-kopf-formular {
        flex-direction: column;
        align-items: stretch;
        gap: 0.5rem;
        margin-bottom: 1rem;
    }
    .seite-kopf-formular h2 { font-size: 1.2rem; }
    .seite-kopf-rueckweg {
        align-self: flex-start;
        padding: 0 0.7rem;
        font-size: 0.85rem;
    }

    /*
     * Mehr Nutzfläche im Rollenformular: Der Rahmen des Abschnitts darf
     * schmaler polstern als anderswo, weil die Matrix darin ihre eigenen
     * Kästchen mit eigenem Rand trägt – zwei Rahmen mit je 0,9 rem sind auf
     * 320 px zusammen fast ein Fünftel der Breite.
     *
     * `min-width: 0` steht aus einem anderen Grund dabei: Ein `fieldset` ist
     * in der Voreinstellung des Browsers mindestens so breit wie sein längstes
     * unteilbares Wort. In „Rolle bearbeiten“ ist dieses Wort der technische
     * Schlüssel im Hinweis unter dem Namensfeld, und bei einem langen
     * Rollennamen schob er die Maske bei 320 px um 27 px nach rechts. Zusammen
     * mit der Zeile darunter heißt das: Der Rahmen darf schmaler werden als
     * sein Inhalt, und der Schlüssel bricht um, statt zu schieben.
     */
    .formular-rollen .formular-abschnitt {
        padding: 0.8rem 0.6rem;
        min-width: 0;
    }
    .formular-rollen code { overflow-wrap: anywhere; }
    .formular-rollen .rechte-kopf,
    .formular-rollen .rechte-zeile { padding: 0.5rem 0.55rem; }
}


/* ══ Redaktionsaufgaben (Issue #71) ══════════════════════════════════════
 *
 * Ein Bereich, der täglich benutzt wird – und zwar von unterwegs genauso wie
 * am Schreibtisch. Deshalb ist hier alles eine **Karte** und keine Tabelle:
 * Was der Mobile-Audit #35 für die übrigen Listen nachträglich umgebaut hat,
 * fängt hier gar nicht erst als Tabelle an.
 *
 * Kein einziger fester Farbwert. Jede Farbe kommt aus den Tokens ganz oben und
 * hat dadurch im dunklen Modus ihre Entsprechung, ohne dass hier eine zweite
 * Regel stünde. Die Status- und Prioritätsmarken benutzen dieselben Paare wie
 * die vorhandenen Marken der Anwendung – ein neues Farbschema für ein neues
 * Modul wäre genau die Zersplitterung, die Issue #65 beendet hat.
 */

/* Zwei bis drei Knöpfe im Seitenkopf. `flex-wrap`, weil auf einem Telefon
   sonst der zweite aus dem Bild liefe. */
.kopf-aktionen {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    align-items: center;
}

/* ── Die drei Zahlen über der Liste ─────────────────────────────────────── */
.aufgaben-bilanz {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.75rem;
    margin-bottom: 1.2rem;
}

.bilanz-kachel {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.8rem 1rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    text-decoration: none;
    box-shadow: var(--schatten-zart);
}
.bilanz-kachel:hover { border-color: var(--rand-stark); }
.bilanz-zahl { font-size: 1.5rem; font-weight: 700; color: var(--text-stark); }
.bilanz-text { font-size: 0.82rem; color: var(--text-leise); }
.bilanz-warnung .bilanz-zahl { color: var(--fehler-text); }
.bilanz-wartend .bilanz-zahl { color: var(--violett-text); }

/* ── Schnelleingabe: eine Aufgabe in drei Feldern ───────────────────────── */
.schnelleingabe {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    padding: 1rem 1.2rem;
    margin-bottom: 1.2rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    box-shadow: var(--schatten-zart);
}

.schnelleingabe-klein { margin-top: 1rem; margin-bottom: 0; }

.schnell-feld { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
.schnell-titel { flex: 1 1 16rem; }

.schnell-feld label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-normal);
}

.schnell-feld input,
.schnell-feld select {
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    font-size: 0.92rem;
    font-family: inherit;
    background: var(--flaeche-eingabe);
    color: var(--text-normal);
}
.schnell-feld input:focus,
.schnell-feld select:focus { outline: none; border-color: var(--kontur); }

/* Der Knopf steht auf der Grundlinie der Felder und nicht unter einer leeren
   Beschriftung – deshalb bekommt er den Platz der Beschriftung als Polster. */
.schnell-knopf { justify-content: flex-end; }

/* ── Die Filterleiste ───────────────────────────────────────────────────── */
.aufgaben-filter {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: 0.75rem;
    padding: 1rem 1.2rem;
    margin-bottom: 1.2rem;
    background: var(--flaeche-still);
    border: 1px solid var(--rand);
    border-radius: 8px;
}

.filter-feld { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
.filter-suche { grid-column: 1 / -1; }

.filter-feld label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-leise);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.filter-feld input,
.filter-feld select {
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    font-size: 0.9rem;
    font-family: inherit;
    background: var(--flaeche-eingabe);
    color: var(--text-normal);
    min-width: 0;
}
.filter-feld input:focus,
.filter-feld select:focus { outline: none; border-color: var(--kontur); }

.filter-knoepfe {
    flex-direction: row;
    align-items: flex-end;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* ── Die Aufgabenkarte ──────────────────────────────────────────────────── */
.aufgaben-liste { display: flex; flex-direction: column; gap: 0.75rem; }
.aufgaben-liste-kinder { margin-bottom: 0.5rem; }

.aufgabe-karte {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-stark);
    border-radius: 8px;
    padding: 0.9rem 1.1rem;
    box-shadow: var(--schatten-zart);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/*
 * Die farbige Kante links ist die eigentliche Auskunft der Liste: Sie sagt
 * ohne Lesen, ob etwas wartet, brennt oder erledigt ist. Deshalb hängt sie am
 * Status und nicht an der Priorität – eine dringende Aufgabe, die längst
 * erledigt ist, muss nicht mehr leuchten.
 */
.aufgabe-status-offen       { border-left-color: var(--warnung-kraeftig); }
.aufgabe-status-in_arbeit   { border-left-color: var(--hinweis-kante); }
.aufgabe-status-rueckfrage  { border-left-color: var(--voraussetzung-kante); }
.aufgabe-status-wartet      { border-left-color: var(--info-kante); }
.aufgabe-status-erledigt    { border-left-color: var(--erfolg-kraeftig); }
.aufgabe-status-abgebrochen { border-left-color: var(--rand-still); }
.aufgabe-ueberfaellig       { border-left-color: var(--fehler-kraeftig); }

.aufgabe-status-erledigt .aufgabe-titel a,
.aufgabe-status-abgebrochen .aufgabe-titel a { color: var(--text-leise); }

.aufgabe-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.aufgabe-titel {
    font-size: 1rem;
    font-weight: 600;
    margin: 0;
    flex: 1 1 12rem;
    min-width: 0;
}
.aufgabe-titel a { color: var(--text-stark); text-decoration: none; }
.aufgabe-titel a:hover { text-decoration: underline; }

/* Die Statusmarke. Dieselben Farbpaare wie bei den vorhandenen Marken –
   ein eigenes Schema für dieses Modul gäbe es keinen Grund. */
.aufgabe-marke-offen       { background: var(--warnung-flaeche); color: var(--warnung-text); }
.aufgabe-marke-in_arbeit   { background: var(--blau-flaeche); color: var(--blau-text); }
.aufgabe-marke-rueckfrage  { background: var(--violett-flaeche); color: var(--violett-text); }
.aufgabe-marke-wartet      { background: var(--info-flaeche); color: var(--info-text); }
.aufgabe-marke-erledigt    { background: var(--erfolg-flaeche); color: var(--erfolg-text); }
.aufgabe-marke-abgebrochen { background: var(--flaeche-sanft); color: var(--text-leise); }

.aufgabe-prio-dringend { background: var(--fehler-flaeche); color: var(--fehler-text); }
.aufgabe-prio-hoch     { background: var(--warnung-flaeche-zart); color: var(--warnung-text-tief); }
.aufgabe-prio-normal   { background: var(--flaeche-sanft); color: var(--text-leise); }
.aufgabe-prio-niedrig  { background: var(--flaeche-sanft); color: var(--text-leise); }

.aufgabe-daten {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    font-size: 0.85rem;
    color: var(--text-mittel);
}

.aufgabe-frist { font-variant-numeric: tabular-nums; }

/* Die kleine Beschriftung vor einem Wert auf der Karte – „Frist", „Zuständig".
   Aus demselben Grund ein Wort und kein Symbol wie in der Historie. */
/* `--text-leise` und nicht `--text-still`: Der stillere Ton kommt im hellen
   Modus nur auf 2,5:1 und liegt damit unter AA. Für eine Beschriftung, die
   sagt, was der Wert daneben bedeutet, ist das zu wenig. */
.daten-marke {
    color: var(--text-leise);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin-right: 0.15rem;
}
.aufgabe-frist-spaet .daten-marke,
.aufgabe-frist-heute .daten-marke { color: inherit; }
.aufgabe-frist-spaet { color: var(--fehler-text); font-weight: 600; }
.aufgabe-frist-heute { color: var(--warnung-mittel); font-weight: 600; }

.aufgabe-einordnung {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.5rem;
    font-size: 0.8rem;
}

.aufgabe-bezug,
.aufgabe-kategorie,
.aufgabe-tag {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    background: var(--flaeche-sanft);
    color: var(--text-mittel);
}
.aufgabe-bezug { background: var(--info-flaeche-zart); color: var(--info-text-tief); }
.aufgabe-bezug a { color: var(--info-text-tief); }
.aufgabe-bezug-fehlt { background: var(--gefahr-flaeche-zart); color: var(--fehler-text); }
.aufgabe-tag { background: var(--flaeche-gewaehlt); color: var(--text-mittel); }

.aufgabe-aktionen {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
}
.aufgabe-aktionen form { display: inline; }

/* ── „Meine Aufgaben": die Sichten ──────────────────────────────────────── */
.sicht-wahl {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.8rem;
}

.sicht-knopf {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.8rem;
    border: 1px solid var(--rand-stark);
    border-radius: 999px;
    background: var(--flaeche-karte);
    color: var(--text-normal);
    font-size: 0.86rem;
    text-decoration: none;
}
.sicht-knopf:hover { background: var(--flaeche-zart); }
.sicht-aktiv {
    background: var(--fuellung);
    border-color: var(--fuellung);
    color: var(--fuellung-text);
}
.sicht-aktiv .sicht-zahl { color: var(--fuellung-text-leise); }
.sicht-zahl { font-weight: 700; color: var(--text-leise); }
.sicht-warnung .sicht-zahl { color: var(--fehler-text); }
.sicht-aktiv.sicht-warnung .sicht-zahl { color: var(--fuellung-text); }

.sicht-erklaerung {
    font-size: 0.85rem;
    color: var(--text-leise);
    margin-bottom: 1rem;
}

/* ── Die Detailseite ────────────────────────────────────────────────────── */
.aufgabe-kopfdaten {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-stark);
    border-radius: 8px;
    padding: 1.2rem 1.4rem;
    margin-bottom: 1.2rem;
    box-shadow: var(--schatten-karte);
}

.kopfdaten-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.kopfdaten-liste {
    display: grid;
    grid-template-columns: 10rem 1fr;
    gap: 0.4rem 1rem;
    font-size: 0.9rem;
    margin: 0 0 1rem;
}
.kopfdaten-liste dt { font-weight: 600; color: var(--text-leise); }
.kopfdaten-liste dd { margin: 0; color: var(--text-normal); }

.aufgabe-beschreibung {
    white-space: pre-wrap;
    line-height: 1.55;
    color: var(--text-lesetext);
    background: var(--flaeche-still);
    border-radius: 6px;
    padding: 0.8rem 1rem;
    margin-bottom: 1rem;
}

.status-wahl {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}
.status-wahl form { display: inline; }
.status-wahl-titel {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text-leise);
    margin-right: 0.2rem;
}

.aufgabe-block { margin-bottom: 1.6rem; }

/* ── Beiträge und Historie ──────────────────────────────────────────────── */
.beitraege { display: flex; flex-direction: column; gap: 0.6rem; }

.beitrag {
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    padding: 0.7rem 1rem;
}
.beitrag-kopf {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    font-size: 0.85rem;
    margin-bottom: 0.3rem;
    color: var(--text-normal);
}
.beitrag-datum { color: var(--text-leise); }
.beitrag-text { white-space: pre-wrap; color: var(--text-lesetext); line-height: 1.5; }

.beitrag-form {
    margin-top: 1rem;
    background: var(--flaeche-karte);
    border: 1px solid var(--rand);
    border-radius: 8px;
    padding: 1rem 1.2rem;
}
.beitrag-form textarea {
    width: 100%;
    padding: 0.55rem 0.8rem;
    border: 1px solid var(--rand-stark);
    border-radius: 6px;
    font-size: 0.92rem;
    font-family: inherit;
    background: var(--flaeche-eingabe);
    color: var(--text-normal);
}
.beitrag-form textarea:focus { outline: none; border-color: var(--kontur); }
.beitrag-aktionen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

/*
 * Die Historie ist eine Liste und kein Logdump: ein Zeichen, eine Zeit, ein
 * Name, ein Satz. Was sie ausdrücklich nicht zeigt, sind technische Felder –
 * der Verlaufstext entsteht schon im Router als deutscher Satzteil.
 */
.historie { list-style: none; margin: 0; padding: 0; }

.historie-zeile {
    display: grid;
    grid-template-columns: 6rem 9.5rem 8rem 1fr;
    gap: 0.5rem;
    align-items: baseline;
    padding: 0.35rem 0;
    border-top: 1px solid var(--rand-zart);
    font-size: 0.85rem;
}
.historie-zeile:first-child { border-top: none; }
/* Die Marke sagt in einem Wort, worum es in der Zeile ging. Sie ist bewusst
   kein Emoji: Was in der Bildpipeline des Handbuchs als leeres Kästchen
   ankommt, erklärt im Handbuch nichts. */
.historie-marke {
    color: var(--text-leise);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.historie-zeit { color: var(--text-leise); font-variant-numeric: tabular-nums; }
.historie-akteur { color: var(--text-leise); font-weight: 600; }
.historie-text { color: var(--text-normal); overflow-wrap: anywhere; }

/* Die Zuständigen im Formular: Kästchen nebeneinander statt untereinander. */
.zustaendig-wahl {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.2rem;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--rand);
    border-radius: 6px;
    background: var(--flaeche-still);
}

/* ── Stufe B: Blockaden, Takte und Vorlagen ─────────────────────────────── */

/* Die Blockade. Sie liest sich wie eine Statusmarke, ist aber keine: Ein
   blockierter Stand wäre ein siebter Status, den niemand setzt – die Blockade
   ergibt sich aus einer anderen Aufgabe und verschwindet mit ihr. */
.aufgabe-marke-blockiert { background: var(--fehler-flaeche); color: var(--fehler-text); }

.aufgabe-blockade {
    margin: 0.5rem 0 0;
    font-size: 0.85rem;
    color: var(--text-mittel);
}
.aufgabe-blockade a { color: var(--text-stark); }

.abhaengig-spalten {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: 1.2rem;
}
.abhaengig-spalte h4 {
    margin: 0 0 0.5rem;
    font-size: 0.9rem;
    color: var(--text-mittel);
}
.abhaengig-liste { list-style: none; margin: 0; padding: 0; }
.abhaengig-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--rand-zart);
    font-size: 0.9rem;
}
/* Was noch offen ist, bremst wirklich – und steht deshalb kräftiger da als
   das, was längst erledigt ist und nur noch zeigt, worauf gewartet wurde. */
.abhaengig-zeile a { color: var(--text-leise); text-decoration: none; }
.abhaengig-offen a { color: var(--text-stark); font-weight: 600; }
.abhaengig-zeile a:hover { text-decoration: underline; }

.vorlagen-liste {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
    gap: 1rem;
}
.vorlage-karte {
    border: 1px solid var(--rand);
    border-radius: 8px;
    background: var(--flaeche);
    padding: 1rem 1.1rem;
}
/* Eine abgeschaltete Vorlage bleibt lesbar und tritt zurück – sie ist nicht
   kaputt, sondern gerade nicht in Gebrauch. */
.vorlage-inaktiv { background: var(--flaeche-still); }
.vorlage-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.vorlage-kopf h3 { margin: 0; font-size: 1rem; flex: 1 1 10rem; }
.vorlage-beschreibung { margin: 0 0 0.7rem; font-size: 0.9rem; color: var(--text-mittel); }
.vorlage-schritte {
    margin: 0;
    padding-left: 1.3rem;
    font-size: 0.88rem;
    color: var(--text-mittel);
}
.vorlage-schritte li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem 0.8rem;
    padding: 0.2rem 0;
}
.vorlage-schritt-titel { color: var(--text-stark); }
.vorlage-schritt-frist,
.vorlage-schritt-person { color: var(--text-leise); font-size: 0.82rem; }
.vorlage-aktionen {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.8rem;
}

/* Die Schritte in der Maske: vier Felder in einer Zeile, und der Titel nimmt
   den Platz, der übrig bleibt. */
.vorlage-posten-zeile {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 0.8rem;
    align-items: flex-end;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--rand-zart);
}
.vorlage-posten-zeile .formular-zeile { margin: 0; }
.posten-titel { flex: 3 1 14rem; }
.posten-versatz { flex: 0 0 5.5rem; }
.posten-prio { flex: 1 1 8rem; }
.posten-person { flex: 1 1 9rem; }

/*
 * Das Telefon. Nichts wird versteckt – der Auftrag verlangt ausdrücklich, dass
 * die schnellen Aktionen auf dem Handy erreichbar bleiben. Sie werden nur
 * größer und rutschen in eine eigene Zeile.
 */
@media (max-width: 640px) {
    .aufgaben-filter,
    .schnelleingabe { padding: 0.8rem; }

    /* Vier Felder nebeneinander sind auf 390 px vier Wortfetzen. Ein Schritt
       einer Vorlage steht auf dem Telefon deshalb untereinander. */
    .vorlage-posten-zeile .formular-zeile { flex: 1 1 100%; }
    .vorlage-posten-zeile { padding: 0.6rem 0; }
    .vorlage-posten-zeile input,
    .vorlage-posten-zeile select { min-height: 44px; }
    .vorlage-aktionen .schaltflaeche,
    .abhaengig-zeile .schaltflaeche { min-height: 44px; display: inline-flex; align-items: center; }

    .schnell-feld,
    .schnell-titel { flex: 1 1 100%; }
    .schnell-knopf .schaltflaeche,
    .filter-knoepfe .schaltflaeche { width: 100%; text-align: center; }
    .filter-knoepfe { flex-direction: column; align-items: stretch; }

    /* 44 px sind das Maß, das der Mobile-Audit #35 für jedes Tippziel gesetzt
       hat. Es gilt hier für die schnellen Aktionen genauso wie überall. */
    .schnell-feld input,
    .schnell-feld select,
    .filter-feld input,
    .filter-feld select { min-height: 44px; }

    .aufgabe-aktionen .schaltflaeche,
    .status-wahl .schaltflaeche,
    .sicht-knopf { min-height: 44px; display: inline-flex; align-items: center; }

    .aufgabe-karte { padding: 0.8rem 0.9rem; }
    .aufgabe-titel { flex: 1 1 100%; }

    .kopfdaten-liste { grid-template-columns: 1fr; gap: 0.1rem 0; }
    .kopfdaten-liste dd { margin-bottom: 0.5rem; }

    /* Die Historie bricht auf zwei Zeilen um: oben Zeichen, Zeit und Name,
       darunter der Satz über die volle Breite. Vier Spalten auf 390 px
       ließen von jeder Spalte zwei Wörter übrig. */
    .historie-zeile {
        grid-template-columns: auto auto 1fr;
        row-gap: 0.15rem;
    }
    .historie-text { grid-column: 1 / -1; }
}
