/* ============================================================================
   GRAVID - Userverwaltung (/portal/): zusätzliche Styles, die tools.css/
   shared.css nicht abdecken. Nutzt dieselben CSS-Variablen (Design-Token,
   siehe css/tokens.css) - keine eigenen Farben/Radien. Siehe _intern/STANDARD-Sicherheit.md
   "Userverwaltung".
   ============================================================================ */

/* ---------- Content-Flächen: Kontur + Schlagschatten wie die
   "Ausblick"-Kachel (KI-Akzent) auf der Startseite (seit 2026-07-31,
   Nutzerwunsch: "Alle Flächen, wo Inhalt dargestellt wird, sollen vom Stil
   so aussehen wie das KI-Feld - nur in Weiß, wie es schon ist"). Dort:
   Rahmen (1px, --line bzw. dort ausnahmsweise grün getönt), --shadow-tight,
   --squircle-lg/-sm-Radius, Hintergrund --paper-raised - identisch zum
   bereits bestehenden .section-tile/.tool-row/.kontakt-card-Muster, nur
   eben MIT sichtbarer Kontur statt nur Schatten+Radius. Gilt hier bewusst
   NUR im KundenPORTAL/Admin (diese Datei lädt ausschließlich dort) - die
   Startseite selbst hat dieses Muster größtenteils schon (dort ist es ja
   die Vorlage), Tool-Seiten bleiben unangetastet.
   .tool-panel selbst hatte bisher Schatten + Radius aus tools.css
   (--card-shadow = das kräftigere --shadow, nicht --shadow-tight), aber
   KEINEN Rahmen - hier ergänzt/angeglichen. */
.tool-panel {
    border: 1px solid var(--line);
    box-shadow: var(--shadow-tight);
}

/* ---------- Backend-Layout (Konto/Admin) ----------
   Regel siehe _intern/STANDARD-Portal.md: Panels/Felder im Backend-Bereich (Konto,
   Admin) nutzen IMMER die volle Breite von .tool-panel/.container - keine
   künstlich schmalen Karten. Nur wenn mehrere Felder inhaltlich
   zusammengehören (z. B. "Neues Passwort" + "Passwort wiederholen"), teilen
   sie sich die Breite über dieses Grid, statt einzeln volle Breite
   untereinander zu stehen. .auth-card (Login/Registrierung, siehe unten) ist
   davon bewusst ausgenommen - eigenes, öffentliches Formular vor dem Login,
   kein Backend-Bereich. */
.backend-row {
    display: grid;
    gap: 1.2rem;
}
.backend-row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.backend-row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 720px) {
    .backend-row--2, .backend-row--3 { grid-template-columns: 1fr; }
}
.backend-row .field { margin-bottom: 0; }

/* Admin: horizontale Tab-Navigation statt gestapelter Panels (seit
   2026-08-01, Nutzerwunsch: "Offene Anfragen"/"Aktive Nutzer"/"Bereiche"
   nicht mehr untereinander, sondern als Reiter). Umschalten per JS (siehe
   portal/admin/index.php) - nur der aktive Tab-Inhalt (.admin-tab-panel)
   ist sichtbar, über das native hidden-Attribut (braucht dafür keine
   eigene CSS-Regel). "Vom Kunden gelöscht"/"Abgelehnt/Deaktiviert" bleiben
   bewusst AUSSERHALB der Tabs (nicht vom Nutzerwunsch erfasst) - seltene
   Fälle, die ohnehin nur erscheinen, wenn tatsächlich Daten vorhanden
   sind. Aktiver Tab wird bei jedem Formular-Submit innerhalb eines Panels
   mitgeschickt (siehe JS), damit nach Freigeben/Ablehnen/Speichern
   derselbe Tab aktiv bleibt statt immer auf den ersten zurückzufallen
   (diese Seite leitet nach POST nicht per Location-Header um). */
/* min-height fest statt dem Inhalt überlassen (seit 2026-08-01,
   Nutzerwunsch: "keine Höhenunterschiede beim Wechsel zwischen Mein Konto
   und Admin") - .admin-tabs ist dieselbe Klasse auf beiden Seiten, aber
   konto.php hängt zusätzlich die Identität (Avatar + zweizeiliger Text)
   an, die von Natur aus höher ist als eine reine Tab-Zeile. Ohne
   min-height begann der Inhalt darunter je nach Seite an leicht
   unterschiedlicher Höhe - sichtbares "Zucken" beim Hin- und Herspringen.
   Der Wert entspricht der natürlichen Höhe MIT Identität (live gemessen),
   die Admin-Seite bekommt dadurch etwas Luft unter den reinen Textlabels
   statt umgekehrt die Identität zu stauchen.

   NACHGEMESSEN am 2026-08-06: Der Nutzerblock ist inzwischen 54,59px hoch
   (er hat am 2026-08-02 die Einstellungen-Schaltfläche dazubekommen), die
   Leiste mit Linie also 55,68px. Der alte Wert 3.3rem = 52,8px lag darunter
   und griff deshalb gar nicht mehr - "Mein Konto" war 3px höher als Admin
   und Cockpit, genau das Zucken, das die Regel verhindern sollte. Wer den
   Nutzerblock ändert, misst diesen Wert neu. */
.admin-tabs {
    display: flex;
    align-items: flex-end;
    min-height: 3.48rem;
    gap: 1.8rem;
    border-bottom: 1px solid var(--line);
    /* ---- Der Abstand nach OBEN gehört der Leiste (seit 2026-08-06) ------
       Vorher trug ihn der Beschreibungsabsatz als margin-bottom. Das ging
       gut, solange nichts dazwischenstand - auf "Mein Konto" und im Admin
       erscheinen zwischen Beschreibung und Tabs aber Meldungen (.flash,
       z. B. "Der Adminbereich ist gesperrt, bis 2FA eingerichtet ist").
       Dann landete der große Abstand über der MELDUNG, und die Tab-Leiste
       rückte auf 1,2rem an sie heran - der mühsam eingestellte Abstand galt
       ausgerechnet dann nicht, wenn die Seite am vollsten war.

       Jetzt hält die Leiste ihren Abstand zu allem, was über ihr steht:
       Überschrift, Beschreibung oder Meldung. Ein Wert an einer Stelle,
       unabhängig vom Vorgänger.

       Bewusst KEIN Wrapper um Überschrift und Beschreibung (naheliegender
       Gedanke, hier verworfen): Der hätte dasselbe Problem gehabt - sein
       Außenabstand nach unten wäre bei einer Meldung ebenfalls über ihr
       gelandet, nicht über den Tabs. Dazu käme Markup in drei Dateien, das
       jede neue Seite mitzuschreiben hätte.

       Benachbarte Ränder fallen zusammen: Der Rückfallwert am Absatz
       (1.5rem) und ggf. der einer Meldung (1.2rem) verschwinden gegen diesen
       Wert, ohne dass sie sich addieren.

       Am 2026-08-06 wieder halbiert (von 3/5.6vw/4.5rem): 36px am Rechner,
       24px am Telefon. Zusammen mit den 19px Leerraum in der Leiste selbst
       (siehe min-height oben) sind es 54px bis zur Beschriftung. */
    margin-top: clamp(1.5rem, 2.8vw, 2.25rem);
    margin-bottom: 1.5rem;
}
.admin-tab {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    /* Bezugspunkt für die Sprechblase, die unter 940px die Beschriftung
       ersetzt (siehe unten). */
    position: relative;
    background: none;
    border: none;
    border-bottom: 3px solid transparent;
    padding: 0 0 0.85rem;
    font-family: var(--font-family);
    font-weight: 700;
    font-size: 0.98rem;
    color: var(--secondary-color);
    cursor: pointer;
    transition: color 0.2s ease, border-color 0.2s ease;
}
/* Oberhalb der Schwelle steht die Beschriftung daneben - eine Sprechblase
   wäre dort nur eine Wiederholung. */
.admin-tab > .tooltip-bubble { display: none; }

/* Ab hier nur noch Symbole (seit 2026-08-01, Nutzerwunsch): unterhalb von
   940px greift ohnehin schon das Mobilmenü, und mehrere ausgeschriebene
   Tab-Beschriftungen nebeneinander brauchen dort mehr Platz, als vorhanden
   ist - sie brachen um oder drängten sich. Der Text wandert in die
   Sprechblase, die Symbole bleiben. Der Abstand zwischen den Tabs wird
   zugleich enger, weil ohne Text weniger Trennung nötig ist.

   Bewusst KEIN Ausblenden der Zähler-Pillen: gerade die Anzahl offener
   Anfragen bzw. Reminder ist die Information, für die man überhaupt
   hinschaut. */
@media (max-width: 940px) {
    /* Mehr Luft zwischen den Tabs, damit die Symbole als eigenständige
       Schaltflächen lesbar bleiben (Nutzerwunsch 2026-08-01). Seit die
       Zähler-Pille rechts NEBEN dem Symbol steht, ragt sie in den Zwischen-
       raum hinein - der Abstand ist deshalb noch einmal größer, damit sie
       nicht am nächsten Symbol klebt. */
    .admin-tabs { gap: 2.6rem; }
    .admin-tab > .admin-tab-label { display: none; }
    .admin-tab > .tooltip-bubble { display: block; }
    /* Breitere, mittige Trefferfläche je Symbol - ohne Beschriftung wäre
       der Tab sonst nur so breit wie das Zeichen selbst. */
    .admin-tab {
        justify-content: center;
        min-width: 2.4rem;
    }
    .admin-tab > i { font-size: 1.2rem; }

    /* Zähler-Pille steht rechts NEBEN dem Symbol und auf dessen Höhe
       (Nutzerwunsch 2026-08-01) - als Ecke oben war sie zwar platzsparend,
       aber schlechter zu lesen.

       Weiterhin absolut positioniert, und das ist der entscheidende Punkt:
       nur "Reminder" und "Offene Anfragen" tragen eine Pille. Läge sie im
       Fluss, würde sie das Symbol dieser beiden Tabs nach links aus der
       Mitte schieben, während die Symbole der übrigen Tabs mittig stehen -
       genau die Fehlausrichtung, die vorher gemeldet wurde.

       top/bottom spannen die Pille exakt über die Höhe des Symbols
       (bottom = padding-bottom des Tabs), ihr eigenes align-items:center
       zentriert die Zahl darin. Dadurch sitzt sie sauber auf einer Linie
       mit dem Symbol, ohne dass eine feste Pixelhöhe geraten werden muss. */
    .admin-tab > .status-badge {
        position: absolute;
        top: 0;
        bottom: 0.85rem;
        left: 50%;
        /* 0.85rem = halbe Symbolbreite plus ein paar Pixel Luft, damit die
           Pille nicht an der Symbolkante klebt. */
        margin-left: 0.85rem;
        padding: 0 0.34rem;
        font-size: 0.68rem;
        letter-spacing: 0;
        pointer-events: none;
    }
}
.admin-tab:hover { color: var(--accent-color); }
.admin-tab.active { color: var(--primary-color); border-bottom-color: var(--accent-color); }

/* "Mein Konto": Tabs links, angemeldetes Konto rechts in derselben Zeile
   (seit 2026-08-01, Nutzerwunsch - vorher stand die Identität links vor
   den Tabs). Identität steht im Markup NACH den Tabs und wird über
   margin-left:auto ans rechte Ende geschoben, statt die Tabs zu
   verdrängen. */
/* Bewusst KEIN eigenes align-items mehr (seit 2026-08-06): Hier stand
   "stretch", womit die Tab-Knöpfe auf die Höhe des Nutzerblocks gestreckt
   wurden. Da .admin-tab seinen Inhalt mittig setzt, rutschte die
   Beschriftung damit in die Mitte einer 55px hohen Fläche - der Abstand
   zwischen Beschriftung und Unterstrich betrug 27px statt der 18px im
   Admin (Nutzermeldung: "der Unterstrich der Tabs hat einen größeren
   Abstand"). Ohne die Zeile gilt das flex-end von .admin-tabs, und alle
   drei Backend-Seiten setzen ihre Beschriftungen auf dieselbe Grundlinie.
   Der Nutzerblock braucht die Streckung nicht: Er trägt seine Höhe selbst
   und sitzt mit flex-end genauso an der Linie. */
/* ---- Nutzerblock = Einstellungen (seit 2026-08-02) ---------------------
   Trägt zusätzlich .admin-tab und ist damit ein vollwertiger Tab: gleiche
   Grundlinie, gleiche Akzent-Unterlinie im aktiven Zustand. Hier stehen nur
   die Abweichungen von einem gewöhnlichen Tab.

   margin-left:auto schiebt ihn ans rechte Ende der Leiste - links die
   Inhalte, rechts die Person. text-align:left, weil .admin-tab als
   <button> sonst zentrieren würde und Name und Adresse dadurch gegeneinander
   verrutschten. */
.konto-identity {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-left: auto;
    padding-bottom: 0.85rem;
    text-align: left;
    text-decoration: none;
}
/* Im Adminbereich ist der Block ein <a> - der Unterstrich des Browsers hat
   in einer Tab-Leiste nichts verloren, die Textfarbe kommt aus den Kindern. */
.konto-identity:hover { text-decoration: none; }
.konto-avatar {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    corner-shape: round;
    background: var(--accent-tint);
    color: var(--accent-color);
    font-weight: 700;
    font-size: 1rem;
}
.konto-identity-text { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.konto-identity-text strong { font-size: 0.95rem; color: var(--primary-color); }
.konto-identity-text span {
    font-size: 0.82rem;
    color: var(--secondary-color);
    overflow-wrap: anywhere;
}
/* ---- Die Schaltfläche im Nutzerblock ----------------------------------
   Nutzervorgabe 2026-08-02: "das muss klar ersichtlich sein!" - gemeint
   war, dass man dem Block ansehen muss, dass er zu den Kontoeinstellungen
   führt. Ein Block aus Name und E-Mail-Adresse liest sich zunächst als
   Anzeige, nicht als Bedienelement.

   Deshalb das Wort AUSGESCHRIEBEN und DAUERHAFT sichtbar, nicht nur ein
   Zahnrad und nicht erst beim Überfahren: Auf Tablets gibt es kein
   Überfahren, und ein Symbol ohne Text bleibt eine Vermutung.

   Getönte Fläche in der Akzentfarbe - dieselben Mischverhältnisse wie bei
   .user-filter-btn.is-active und den Statuspillen, damit "hier kann man
   etwas auslösen" im Backend überall gleich aussieht. Bewusst nicht in
   einer Ampelfarbe: hier wird nichts gespeichert, abgelehnt oder gewarnt,
   sondern navigiert. */
.konto-identity-action {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex-shrink: 0;
    padding: 0.35rem 0.7rem;
    border-radius: var(--squircle-sm);
    corner-shape: round;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
    color: var(--accent);
    font-size: 0.82rem;
    font-weight: 700;
    line-height: 1;
    transition: background 0.15s ease, border-color 0.15s ease;
}
/* Der ganze Block ist die Schaltfläche - die Tönung reagiert deshalb auf
   das Überfahren des BLOCKS, nicht nur der Pille. Sonst müsste man genau
   die Pille treffen, obwohl ringsum alles klickt. */
.konto-identity:hover .konto-identity-action,
.konto-identity:focus-visible .konto-identity-action {
    background: color-mix(in srgb, var(--accent) 22%, transparent);
    border-color: var(--accent);
}
/* Ist der Einstellungen-Tab offen, ist die Aufforderung erfüllt - dann
   deckt sie sich mit der Akzent-Unterlinie darunter und darf voll
   einfärben, statt weiter zum Klicken aufzufordern. */
.konto-identity.active .konto-identity-action {
    background: var(--accent-solid);
    border-color: var(--accent-solid);
    color: #fff;
}

@media (max-width: 940px) {
    /* Gleiche Schwelle wie bei den übrigen Tabs, die hier auf reine Symbole
       zurückgehen: Name und Adresse würden den Platz sprengen. Übrig bleibt
       der Avatar - das Kürzel des eigenen Namens - plus die Schaltfläche
       mit Zahnrad. Die Aufforderung selbst bleibt also erhalten, nur ihr
       Wort weicht dem Platz. */
    .konto-identity-text { display: none; }
    .konto-identity-action-label { display: none; }
    .konto-identity-action { padding: 0.35rem 0.5rem; }
}
@media (max-width: 780px) {
    /* Auf schmalen Displays Identität in eigener Zeile unter den Tabs -
       nebeneinander bliebe für beides zu wenig Platz. In der eigenen Zeile
       ist wieder Raum für alles, deshalb kommen Name, Adresse und das Wort
       hier zurück. */
    .konto-tabs { flex-wrap: wrap; }
    .konto-identity { flex: 1 0 100%; margin-left: 0; padding-bottom: 0.9rem; }
    .konto-identity-text { display: flex; }
    .konto-identity-action-label { display: inline; }
    /* Schaltfläche ans rechte Zeilenende, weg vom Namen daneben. */
    .konto-identity-action { margin-left: auto; padding: 0.35rem 0.7rem; }
}

/* Abstand zwischen den Akkordeons im Einstellungen-Tab - .tool-panel bringt
   das über ".tool-panel + .tool-panel" (tools.css) selbst mit, hier nur der
   Abschluss nach unten. */
.settings-stack > :last-child { margin-bottom: 0; }

/* Admin: "Offene Anfragen" sticht farblich hervor, solange tatsächlich
   welche offen sind (seit 2026-07-30, Nutzerwunsch: "damit gleich
   hervorsticht, dass dort Anfragen ausstehen") - dieselbe Orange-Ampelfarbe
   wie der Zähler-Badge daneben (--warning, wie .status-badge--pending).
   Bewusst deutlicher als .tool-panel--security oben (dort ging es um
   Zurückhaltung, hier explizit um Aufmerksamkeit) - kein Widerspruch, zwei
   unterschiedliche Zwecke. Klasse wird nur gesetzt, wenn $pending nicht leer
   ist, verschwindet also automatisch, sobald alles bearbeitet ist. */
.tool-panel--pending {
    background: color-mix(in srgb, var(--card-background) 90%, var(--warning) 10%);
    border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
}

/* Sicherheitsrelevante Panels (Passwort, Zwei-Faktor) heben sich auf
   konto.php seit 2026-07-29 vom "Freigegebene Bereiche"-Panel ab, indem sie
   als <details>-Akkordeon zugeklappt starten (Ausnahme: es gibt gerade
   etwas zu sehen - eigene Rückmeldung oder laufende/aktive 2FA-Einrichtung,
   siehe konto.php $passwordOpen/$twoFaOpen) statt permanent offen mit
   eigenem Hintergrundton dazustehen. **Ursprünglich (erste Fassung) ein
   dauerhaft eingefärbter Hintergrund (8% --ink-Beimischung) - auf
   Nutzerfeedback "Farbdarstellung ist zu dominant" durch das Zuklappen
   ersetzt, das die Abhebung dezenter UND funktional (weniger auf den ersten
   Blick sichtbare Formularfelder) löst.** "Freigegebene Bereiche" bleibt
   bewusst ein normales, immer offenes .tool-panel - soll laut Nutzerwunsch
   als Erstes und ohne Klick sichtbar sein. */
.tool-panel--security { padding: 1.4rem 2rem; }
.tool-panel--security summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-weight: 700;
    font-size: 1.15rem;
    color: var(--primary-color);
    padding: 0.6rem 0;
}
.tool-panel--security summary::-webkit-details-marker { display: none; }
.tool-panel--security summary i:first-child {
    margin-right: 0.5rem;
    color: var(--secondary-color);
    font-size: 0.85em;
}
.tool-panel--security summary .chevron {
    color: var(--secondary-color);
    font-size: 0.85em;
    transition: transform 0.2s ease;
}
.tool-panel--security[open] summary .chevron { transform: rotate(180deg); }
/* Eingeschalteter Schutz auf einen Blick (seit 2026-08-01): grünes Schild
   plus "Aktiv"-Pille in der Überschrift. Dadurch muss die Kachel nicht mehr
   dauerhaft offen stehen, nur um den Zustand zu zeigen (siehe $twoFaOpen in
   konto.php). */
.tool-panel--security.is-active summary i:first-child { color: var(--success); }
.tool-panel--security summary .status-badge { margin-left: 0.5rem; vertical-align: middle; }
.tool-panel--security summary:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 3px; border-radius: var(--squircle-sm); }
.tool-panel--security .tool-panel-body {
    padding-top: 1.2rem;
    margin-top: 0.6rem;
    border-top: 1px solid var(--line);
}
@media (prefers-reduced-motion: reduce) {
    .tool-panel--security summary .chevron { transition: none; }
}

/* Die Regel, die die Fußzeile auch auf kurzen Seiten unten hält, stand bis
   2026-08-08 hier - und wirkte damit nur im Portal, obwohl sie auf die
   Body-Klasse BEIDER Bereiche zielte. Sie liegt jetzt in css/footer.css,
   die Werkzeug- und Portalseiten gleichermaßen laden (Nutzerwunsch: "bei
   den Tool-Seiten soll die Fußzeile auch immer am Bottom sein"). */

/* ---- Seitenkopf im Backend: Überschrift, Beschreibung, Tabs ----------
   Verbindlicher Standard seit 2026-08-06 (Nutzervorgabe: "die Abstände im
   Kopfbereich mit Überschrift und Tabs in Mein Konto und Admin sind die
   Vorgabe für das Cockpit").

   Die Werte gab es vorher schon - aber als style-Attribut, ausgeschrieben in
   portal/konto.php UND portal/admin/index.php. Das Cockpit hatte sie
   folglich nicht: Überschrift, Beschreibung und Tabs klebten dort ohne jeden
   Abstand aneinander (gemessen 0px statt 5px und 26px), und die Beschreibung
   stand in voller Textfarbe statt im gedämpften Ton. Genau der Fehler, den
   eine zweifach ausgeschriebene Regel früher oder später produziert: Die
   dritte Seite erbt nichts, weil es nichts zu erben gab.

   Trifft ausschließlich den Seitenkopf: Alle übrigen Überschriften im Portal
   stecken in einer .tool-panel/.auth-card und sind damit keine direkten
   Kinder von .tool-main. */
.tool-main > h1 { margin: 0 0 0.3rem; }
.tool-main > h1 + .lede {
    /* Mehr Luft zur Tab-Leiste als zuvor (1.6rem/25,6px), seit 2026-08-06:
       Überschrift und Beschreibung gehören zusammen - dazwischen stehen
       bewusst nur 5px. Zu den Tabs beginnt dagegen etwas Neues, nämlich die
       Navigation. Dieser Schnitt darf man sehen.

       Der Platz dafür kommt aus dem Außenabstand von .tool-main, der
       gleichzeitig kleiner geworden ist (siehe tools/tools.css) - die Seite
       wird also insgesamt kürzer, nicht länger.

       clamp aus demselben Grund wie dort: Auf schmalen Geräten zählt jeder
       Pixel Höhe, auf dem Desktop darf die Gliederung deutlicher sein.

       Hier steht nur noch der EIGENE Abstand des Absatzes, nicht mehr der
       zur Tab-Leiste - den setzt seit 2026-08-06 die Leiste selbst
       (.admin-tabs { margin-top }, siehe dort samt Begründung). 1.5rem ist
       der Rückfallwert für Seiten ohne Tabs; steht eine Tab-Leiste darunter,
       gewinnt deren größerer Außenabstand durch das Zusammenfallen
       benachbarter Ränder.

       ---- Farbe ----
       --ink-faint statt --secondary-color (= --ink-soft), ebenfalls auf
       Nutzerwunsch "ein wenig dezenter". Das ist der Ton, der im Farbsatz
       ausdrücklich für zurückgenommenen Text vorgesehen ist.

       Kontrast nachgerechnet (WCAG 1.4.3, Schwelle 4,5:1 für normalen Text
       bei 16px): hell 4,51:1, dunkel 5,16:1 - es passt, aber im Hellmodus
       ohne nennenswerten Puffer. NOCH heller geht deshalb nicht mehr, ohne
       die Zugänglichkeit zu verlieren; wer hier weiter dämpfen will, muss
       stattdessen die Schriftgröße erhöhen (ab 18,66px Fettschrift bzw.
       24px gilt die mildere Schwelle von 3:1). */
    margin: 0 0 1.5rem;
    /* Neutrales Grau statt des blaustichigen --ink-faint (Nutzerwunsch
       2026-08-06). Ohne Farbstich tritt der Absatz zurück, ohne sich in die
       Nähe der Akzentfarbe zu stellen - und der Ton hat mit 4,82:1 (hell)
       bzw. 5,35:1 (dunkel) wieder Luft zur WCAG-Schwelle von 4,5:1, statt
       wie --ink-faint mit 4,51:1 darauf zu liegen. Werte und Begründung
       stehen beim Token in css/tokens.css. */
    color: var(--ink-neutral);
    /* Zusätzlich eine Spur kleiner als der Fließtext (16px): Der Farbschritt
       allein war im Alltag nicht aufgefallen. 15px lesen sich als Beiwerk
       zur Überschrift, ohne dass am Kontrast gedreht werden muss.

       Das Gewicht bleibt bei 400. Quicksand hätte 300 im Haus, aber dünne
       Striche bei gerade noch zulässigem Kontrast sind genau die
       Kombination, an der Lesbarkeit kippt. */
    font-size: 0.94rem;
}

/* ---------- Akkordeon-Slide-Animation (seit 2026-08-01) ----------
   Gilt für ALLE Akkordeons im KundenPORTAL - und zwar seit 2026-08-02
   buchstäblich für alle: die Regel greift auf JEDES <details> in diesem
   Bereich, nicht mehr auf eine Liste einzelner Klassen.
   Vorher standen hier .tool-panel--security, .user-accordion details,
   .add-new-toggle und .section-card namentlich - wer ein neues Akkordeon
   baute, musste daran denken, es hier einzutragen, sonst klappte genau
   dieses eine ruckartig auf. Beim Umbau der Kürzel-Legende zum Akkordeon
   ist das prompt passiert. Ein Standard, den man an vier Stellen pflegen
   muss, ist keiner - deshalb der pauschale Selektor.
   Unbedenklich, weil css/portal.css AUSSCHLIESSLICH von
   portal/_header.php geladen wird und damit nur im Backend gilt; die
   Startseite und die Tool-Seiten sind nicht betroffen.

   Umsetzung über ::details-content, das Pseudoelement um den Inhalt eines
   <details> - der einzige Weg, das native Auf-/Zuklappen ohne JS und ohne
   Markup-Umbau zu animieren (der Browser setzt sonst schlicht
   display:none auf den Inhalt, was sich nicht übergangsfähig ist).
   Zwei Zutaten sind nötig:
   1) interpolate-size:allow-keywords - erlaubt überhaupt erst einen
      Übergang VON 0 ZU dem Keyword auto (die Zielhöhe steht ja vorher
      nicht als Zahl fest). Vererbte Eigenschaft, daher einmal auf :root.
   2) transition-behavior:allow-discrete für content-visibility - ohne das
      würde der Browser den Inhalt beim Schließen sofort ausblenden und
      die Höhen-Animation wäre unsichtbar.
   Progressive Enhancement wie beim Squircle (siehe _intern/STANDARD-Grundlagen.md):
   Browser ohne ::details-content/interpolate-size klappen weiterhin
   sofort auf/zu - funktional identisch, nur ohne Animation, es bricht
   nichts. */
:root { interpolate-size: allow-keywords; }

details::details-content {
    block-size: 0;
    overflow: hidden;
    /* overflow zusätzlich im Übergang, mit allow-discrete (seit
       2026-08-01) - ohne das blieb overflow:hidden auch im vollständig
       geöffneten Zustand bestehen (block-size:auto hebt das nicht von
       selbst auf) und schnitt schwebende Inhalte wie .icon-picker an der
       Kartenkante ab. allow-discrete verzögert den Wechsel zu "visible"
       bis ans Ende der block-size-Animation (wie bei content-visibility
       bereits gehandhabt) - während des Aufklappens bleibt weiterhin
       sauber zugeschnitten, erst im Ruhezustand darf Inhalt herausragen.
       Beim Zuklappen kippt overflow sofort zurück auf hidden (Start der
       Animation), der Inhalt bleibt also während des ganzen
       Zuklapp-Vorgangs sauber begrenzt. */
    transition: block-size 0.28s ease, content-visibility 0.28s, overflow 0.28s;
    transition-behavior: allow-discrete;
}
details[open]::details-content {
    block-size: auto;
    overflow: visible;
}
@media (prefers-reduced-motion: reduce) {
    details::details-content { transition: none; }
}

/* Buttons in Konto-/Admin-Formularen NICHT auf volle Breite (seit
   2026-07-30, Nutzerwunsch: "Hälfte der Breite und linksbündig") - tools.css
   setzt .tool-btn standardmäßig auf width:100% (dort für einzelne Tool-
   Formulare gedacht, wo der Button die einzige/letzte Aktion ist). Im
   KundenPORTAL wirkt das neben kurzen Formularen ungewohnt breit.
   min-width verhindert, dass sehr schmale Container (z. B. die 280px-Box
   beim 2FA-Bestätigungscode) den Button zu klein werden lassen - dort bleibt
   er dann einfach bei seiner Mindestbreite statt exakt 50%. */
/* EINHEITLICHE Schaltflächengröße (verbindlich, seit 2026-08-01):
   Alle Schaltflächen im KundenPORTAL sind exakt gleich breit - ein fester
   Wert, KEINE Prozentangabe. Vorher stand hier width:50%, das ergab je nach
   umgebendem Element unterschiedliche Breiten: "Deaktivieren" liegt in einem
   normalen Formular (50% der breiten Panel-Fläche), die 2FA-Einrichtung
   dagegen in Formularen mit max-width:280px (50% davon, gefangen von der
   min-width) - dadurch sahen die Schaltflächen sichtbar verschieden aus
   (vom Nutzer gemeldet). 280px passt exakt in die schmalste dieser
   Umgebungen, max-width:100% verhindert Überlaufen in noch engeren
   Containern. Diese Einheitlichkeit ist ausdrücklich beizubehalten. */
.tool-panel-body .tool-btn,
.add-new-toggle .tool-btn {
    width: 280px;
    max-width: 100%;
    min-width: 0;
    margin-top: 0.4rem;
}
/* ...und dieselbe HÖHE: tools.css gibt .tool-btn.secondary bewusst eine
   kleinere Polsterung und Schriftgröße (0.6rem/0.86rem statt 0.85rem/
   0.96rem) - auf den Tool-Seiten gewollt, im KundenPORTAL aber der Grund,
   warum "Deaktivieren" flacher aussah als die übrigen Schaltflächen (39px
   statt 47px). Dass die "Abbrechen"-Schaltflächen trotzdem gleich hoch
   wirkten, lag nur daran, dass sie als Flex-Kinder in .row-actions auf die
   Höhe der primären Schaltfläche daneben gestreckt wurden - allein stehend
   kam der Unterschied sofort zum Vorschein. Hier deshalb auf die Basiswerte
   zurückgesetzt, damit jede Schaltfläche in jeder Umgebung gleich groß ist. */
.tool-panel-body .tool-btn.secondary,
.add-new-toggle .tool-btn.secondary {
    padding: 0.85rem 1.6rem;
    font-size: 0.96rem;
}
.tool-panel-body .totp-setup .tool-btn { margin-top: 0; }

/* Auf Mobilgeräten gilt die 50%-Regel oben NICHT (seit 2026-08-01,
   Nutzerwunsch: "hier werden die Buttons untereinander angezeigt und passen
   sich auf den zur Verfügung stehenden Content an"). Grund: 50% + 200px
   min-width sprengt auf schmalen Displays den Container - zwei solche
   Buttons nebeneinander in einer .row-actions-Zeile (z. B. "Passwort
   ändern" + "Abbrechen") brauchten allein schon über 400px. Deshalb hier
   volle Breite, min-width zurückgesetzt, und .row-actions innerhalb der
   Akkordeon-Bodies gestapelt statt nebeneinander. Bewusst nur für
   .tool-panel-body/.add-new-toggle - die .row-actions in den Admin-Tabellen
   bleiben unangetastet, die liegen in ihrem eigenen horizontalen
   Scroll-Container (.table-scroll, siehe dort). */
@media (max-width: 600px) {
    .tool-panel-body .tool-btn,
    .add-new-toggle .tool-btn {
        width: 100%;
        min-width: 0;
    }
    .tool-panel-body .row-actions {
        flex-direction: column;
        align-items: stretch;
    }
}

/* Registrierung: schmalere, zentrierte Karte statt der vollen
   .tool-panel-Breite - ein Formular mit wenigen Feldern wirkt in voller
   Breite verloren. Bewusst NICHT Teil des Backend-Layouts oben (siehe
   Kommentar dort) - eine öffentliche Seite vor jedem Login, kein Konto-/
   Admin-Bereich. Login selbst nutzt seit 2026-07-29 das breitere
   .auth-split-Layout weiter unten. */
.auth-card {
    max-width: 420px;
    margin: 2rem auto;
}
.auth-card h1 {
    font-size: 1.6rem;
    margin: 0 0 0.4rem;
    color: var(--primary-color);
}
.auth-card .lede {
    color: var(--secondary-color);
    font-size: 0.92rem;
    margin: 0 0 1.6rem;
}
.auth-card .switch-link {
    margin-top: 1.4rem;
    padding-top: 1.2rem;
    border-top: 1px solid var(--line);
    font-size: 0.88rem;
    color: var(--secondary-color);
    text-align: center;
}
.auth-card .switch-link a { color: var(--accent-color); font-weight: 700; }

/* Login: volle .tool-panel-Breite, Formular links + per Haarlinie
   abgetrennte Info-Spalte rechts (seit 2026-07-29, siehe _intern/STANDARD-Grundlagen.md).
   Registrierung bleibt bei der schmalen .auth-card oben - dort gibt es
   mehr Felder, eine zweite Spalte würde die Seite nur unnötig strecken. */
.auth-split {
    display: grid;
    grid-template-columns: minmax(0, 380px) 1fr;
    gap: clamp(2rem, 5vw, 4rem);
    /* Bewusst KEIN align-items:start (mehr) - seit 2026-07-30 soll sich die
       rechte Infotext-Spalte auf die tatsächliche Höhe der linken
       Formular-Spalte strecken (Grid-Default "stretch"), statt nur ihre
       eigene Inhaltshöhe einzunehmen - die Trennlinie (border-left) reicht
       dadurch immer bis zur vollen Höhe des Formulars daneben. */
}
.auth-split-form h1 {
    font-size: 1.6rem;
    margin: 0 0 0.4rem;
    color: var(--primary-color);
}
.auth-split-form .lede {
    color: var(--secondary-color);
    font-size: 0.92rem;
    margin: 0 0 1.6rem;
}
.auth-split-form .switch-link {
    margin-top: 1.4rem;
    padding-top: 1.2rem;
    border-top: 1px solid var(--line);
    font-size: 0.88rem;
    color: var(--secondary-color);
}
.auth-split-form .switch-link a { color: var(--accent-color); font-weight: 700; }

/* Köderfeld des Formularschutzes (siehe inc/formschutz.php).

   Bewusst NICHT display:none und nicht visibility:hidden: Beides ist der
   erste Test, den ein sorgfältig gebauter Absender macht, bevor er ein Feld
   ausfüllt. Aus dem Fluss geschoben sieht das Feld im Quelltext aus wie
   jedes andere.

   Die Höhe muss dabei mit weg - ein Element mit Ausdehnung außerhalb des
   Sichtbereichs kann die Seite trotzdem breiter machen und auf dem Telefon
   eine waagerechte Bildlaufleiste erzeugen. */
.formschutz-feld {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.auth-split-info {
    padding-left: clamp(1.5rem, 3vw, 2.5rem);
    border-left: 1px solid var(--line);
}
.auth-split-info h2 {
    font-size: 1.15rem;
    margin: 0 0 0.6rem;
    color: var(--primary-color);
}
.auth-split-info > p {
    color: var(--secondary-color);
    font-size: 0.92rem;
    margin: 0 0 1rem;
}
.auth-split-info .section-list { margin-bottom: 1.2rem; }
.auth-split-info .fine-print {
    color: var(--secondary-color);
    font-size: 0.84rem;
    margin: 0;
}
.auth-split-info .fine-print a { color: var(--accent-color); font-weight: 700; }

@media (max-width: 780px) {
    .auth-split { grid-template-columns: 1fr; }
    .auth-split-info {
        padding-left: 0;
        padding-top: 1.6rem;
        border-left: none;
        border-top: 1px solid var(--line);
    }
}

/* ---- 404-Fehlerseite (seit 2026-08-02) --------------------------------
   Nutzt seit 2026-08-02 denselben .auth-split-Rahmen wie die Login-Seite
   (Nutzerwunsch) - hier stehen nur die beiden Bauteile, die es dort nicht
   gibt. Vorher lagen sie als <style>-Block IN 404.php; das ging, solange die
   Seite eigenständig war, wäre jetzt aber ein zweiter Ort für Gestaltung
   neben dieser Datei.

   Die große Zahl sitzt an der Stelle, an der beim Login das Formular
   beginnt: sie ist die eigentliche Auskunft der Seite, nicht Dekoration.
   Deshalb in der Akzentfarbe statt in --danger - die Seite meldet keinen
   Fehler des Besuchers, sondern einen fehlenden Inhalt.                  */
.error-code {
    font-family: var(--font-family);
    font-weight: 800;
    font-size: clamp(3.4rem, 12vw, 5rem);
    line-height: 1;
    color: var(--accent-color);
    margin: 0 0 1.2rem;
}
.error-countdown {
    font-size: 0.86rem;
    color: var(--ink-faint);
    margin: 0 0 1.2rem;
    display: flex;
    align-items: center;
    gap: 0.45rem;
}
/* Kein eigener Wert für .tool-btn hier: der Knopf ist über tools.css ohnehin
   100% breit und füllt damit die Formularspalte genau wie "Anmelden" auf der
   Login-Seite. Die alte 404-Seite überschrieb das auf feste 280px - das war
   der einzige Grund, warum sie schmaler wirkte. */

/* Feld-Validierung: farbige Kontur + Ampel-Hinweis (seit 2026-07-29).
   Gate über ".was-validated" am <form> (siehe _footer.php) statt
   :user-invalid/:user-valid - mehrere Formulare hier tragen "novalidate"
   (Server prüft final), der Browser führt dadurch nie den automatischen
   Sende-Blockierversuch aus, der :user-invalid erst auslösen würde (live
   getestet, auch ohne "novalidate" blieb es unzuverlässig). Erst nach einem
   echten Sendeversuch gesetzt, :invalid/:valid selbst bleiben live reaktiv -
   ein leeres Pflichtfeld ist beim ersten Laden der Seite also nicht schon
   rot. Gilt für alle Formulare im KundenPORTAL. */
.was-validated .tool-input:invalid,
.was-validated .tool-select:invalid {
    border-color: var(--danger);
}
.was-validated .tool-input:valid,
.was-validated .tool-select:valid {
    border-color: var(--success);
}
.field-hint { transition: color 0.15s ease; }
.field-hint a { color: var(--accent-color); font-weight: 600; }
.was-validated .field:has(.tool-input:invalid) > .field-hint,
.was-validated .field:has(.tool-select:invalid) > .field-hint {
    color: var(--danger);
}
.was-validated .field:has(.tool-input:valid) > .field-hint,
.was-validated .field:has(.tool-select:valid) > .field-hint {
    color: var(--success);
}
/* Die Meldung steht seit 2026-08-02 IM Feld statt darunter (Nutzerwunsch):
   portal/_footer.php setzt bei einem leeren Pflichtfeld den Platzhaltertext
   auf "Bitte ausfüllen" und markiert das Feld mit .has-error; beim Anklicken
   oder Tippen wird beides zurückgenommen. Vorteil gegenüber dem früheren
   Hinweis unter dem Feld: das Formular ändert seine Höhe nicht, es rutscht
   also nichts, und die Meldung steht genau dort, wo die Eingabe hingehört.
   Der Platzhalter ist standardmäßig blass - hier bewusst voll deckend, sonst
   wäre die Warnfarbe kaum zu erkennen. */
.tool-input.has-error::placeholder,
.tool-select.has-error::placeholder {
    color: var(--danger);
    opacity: 1;
}

/* Flash-Meldungen (Erfolg/Fehler) - eigenständig statt .tool-result, da hier
   auch VOR jeder Interaktion (z. B. nach Redirect) etwas stehen kann. */
.flash {
    padding: 0.85rem 1.1rem;
    border-radius: var(--squircle-sm);
    font-size: 0.9rem;
    margin-bottom: 1.2rem;
    border: 1px solid transparent;
    box-shadow: var(--shadow-tight);
    /* Ausblenden nach 7 Sekunden (siehe portal/_footer.php): Höhe, Abstand
       und Transparenz laufen gemeinsam auf 0, damit der Inhalt darunter
       sanft nachrückt statt zu springen. */
    transition: opacity 0.4s ease, height 0.4s ease, margin 0.4s ease, padding 0.4s ease;
}
.flash--error {
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    border-color: color-mix(in srgb, var(--danger) 35%, transparent);
    color: var(--danger);
}
.flash--success {
    background: color-mix(in srgb, var(--success) 12%, transparent);
    border-color: color-mix(in srgb, var(--success) 35%, transparent);
    color: var(--success);
}
/* Zwischenstatus (z. B. "Anfrage wartet auf Freischaltung") - dieselbe
   Ampel-Logik wie .status-badge--pending: Grün = erledigt/ok, Gelb/Orange =
   noch offen/in Prüfung, Rot = Fehler. Seit 2026-07-29. */
.flash--warning {
    background: color-mix(in srgb, var(--warning) 14%, transparent);
    border-color: color-mix(in srgb, var(--warning) 40%, transparent);
    color: var(--warning);
}
/* Zielzustand des automatischen Ausblendens - die Starthöhe setzt das
   Skript vorher als konkreten Pixelwert (siehe portal/_footer.php). */
.flash--hiding {
    opacity: 0;
    height: 0 !important;
    margin-top: 0;
    margin-bottom: 0;
    padding-top: 0;
    padding-bottom: 0;
    border-width: 0;
}

/* Status-Badges (Registrierungs-/Kontostatus) - im Admin-Bereich und auf der
   Konto-Seite genutzt. */
.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.25rem 0.6rem;
    border-radius: 100px;
    corner-shape: round;
    /* Nie mitten im Status umbrechen (seit 2026-08-01) - "E-Mail offen"
       brach in der schmalen Tabellenspalte sonst in zwei Zeilen um und die
       Pille wirkte dadurch zerrissen. */
    white-space: nowrap;
}
.status-badge--pending { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); }
.status-badge--active { background: color-mix(in srgb, var(--success) 14%, transparent); color: var(--success); }
.status-badge--rejected, .status-badge--disabled { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }
/* Rein informativ, ohne Wertung (z. B. "Abgemeldet" im Login-Verlauf) -
   bewusst außerhalb der Ampel-Logik grün/orange/rot, damit ein neutraler
   Vorgang nicht wie ein Zustand aussieht, der Aufmerksamkeit braucht. */
.status-badge--neutral { background: color-mix(in srgb, var(--ink) 8%, transparent); color: var(--secondary-color); }

/* Checkbox mit Beschriftung in einer Zeile (seit 2026-08-01, "Angemeldet
   bleiben" auf der Login-Seite). Eigene Klasse statt .checkbox-row aus
   tools.css: dort sind Kästchen und <label> GESCHWISTER, hier liegt der
   Text IM <label>, damit auch ein Klick auf den Text die Checkbox schaltet
   (größere Trefferfläche, besonders auf Touchgeräten). */
.checkbox-line {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--primary-color);
}
.checkbox-line input {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    accent-color: var(--accent-color);
    cursor: pointer;
}

/* ---------- Schriftgröße für Hinweise und Eintragstexte (2026-08-02) ----
   Backend-Regel, global: Der Hinweistext unter einem Eingabefeld
   (.field-hint) hat IMMER dieselbe Größe wie der Text eines Eintrags
   (Rechte-Eintrag, Legendenzeile, Bereichs-Häkchen). Vorher lagen die
   Werte zwischen 0.8 und 0.9rem verstreut - der Hinweis war dadurch der
   kleinste Text im ganzen Backend und schlecht lesbar (Nutzerhinweis:
   "sonst ist die Darstellung zu klein").

   Als Variable und nicht als wiederholte Zahl: Wer die Größe künftig
   ändern will, ändert sie hier einmal, und alle betroffenen Stellen
   ziehen mit. Eine Regel, die man an sechs Stellen nachpflegen müsste,
   hielte keine zwei Wochen.

   Der Wert 0.9rem stammt von .permission-item strong - dem
   ausgeschriebenen Namen eines Rechte-Eintrags, dem deutlichsten
   "Eintragstext" im Backend. Bewusst NICHT betroffen: Tabellenzellen
   (.admin-table .muted) und Akkordeon-Kopfzeilen
   (.user-accordion summary .muted) - das sind Nebenangaben in dichten
   Listen, keine Hinweise und keine Eintragstexte. */
:root { --backend-text: 0.9rem; }

.field-hint,
p.field-hint,
.legend-item,
.section-grant,
.permission-item strong,
.permission-item .muted {
    font-size: var(--backend-text);
}

/* Einleitungstexte über Formularen/Tabellen (seit 2026-08-01) -
   ".field-hint" stammt aus tools.css und ist dort als KLEINER Zusatz DIREKT
   unter einem Eingabefeld gedacht (margin-top:0.35rem, kein
   margin-bottom). Im Portal wird dieselbe Klasse zusätzlich für ganze
   Absätze über Formularen und Tabellen genutzt. Gilt bewusst nur für
   <p>-Elemente, damit der ursprüngliche Einsatz als <span> unter einem Feld
   unberührt bleibt. Nutzt die volle Breite des Bereichs (kein max-width) und
   bekommt großzügigen Abstand nach oben und unten, sobald der Text zwischen
   anderen Elementen steht - steht er ganz oben im Bereich, übernimmt bereits
   dessen Innenpolster den Abstand zur Kante, ein zusätzlicher wäre doppelt. */
p.field-hint {
    line-height: 1.6;
    margin: 1.5rem 0;
}
p.field-hint:first-child {
    margin-top: 0;
}

/* ---------- Hinweistexte im Adminbereich: gelbes Info-Symbol (2026-08-02) --
   Nutzerwunsch: "mach bei allen hints in diesem bereich eine art Info
   symbol in gelb ... oben links davor". Die Erklärtexte über den Listen
   sahen bis dahin aus wie gewöhnlicher Fließtext und wurden entsprechend
   überlesen - genau von denen, für die sie gedacht sind.

   Gilt seit 2026-08-02 im GESAMTEN Portal, nicht nur im Adminbereich
   (Nutzerwunsch: "alle hint texte sollen immer das info symbol bekommen.
   auch in mein konto und global sichtbar"). Zunächst war es auf .admin-page
   begrenzt - das erzeugte aber genau die Uneinheitlichkeit, die im Backend
   sonst überall vermieden wird: derselbe Hinweistext sah in "Mein Konto"
   anders aus als im Adminbereich.

   Bewusst nur p.field-hint, nicht span.field-hint: als <span> steht die
   Klasse für den kleinen Zusatz DIREKT unter einem Eingabefeld (etwa der
   "Passwort vergessen?"-Link oder die Notiz zu "Angemeldet bleiben"). Das
   sind Beschriftungen am Feld, keine Hinweise über einem Abschnitt - ein
   Symbol vor jeder dieser Zeilen wäre Lärm.

   ---- Warum absolut positioniert und nicht per Flexbox ----
   display:flex am <p> hätte jedes Kind zu einem eigenen Flex-Element
   gemacht: ein "<strong>Erster Satz.</strong> Zweiter Satz." stünde dann
   NEBENEINANDER statt als ein Absatz zu fließen. Mit padding-left plus
   absolutem ::before bleibt der Absatz ein Absatz - und mehrzeiliger Text
   rückt sauber unter sich selbst ein statt unter das Symbol.

   top:0 setzt das Symbol auf die erste Zeile; line-height geerbt (1.6),
   damit es auf derselben Grundlinie wie der Text sitzt und nicht darüber
   schwebt.

   Farbe --warning: der CI-eigene Gelbton, der im Hell- und Dunkelmodus
   bereits unterschiedlich hinterlegt ist (#f9a825 bzw. #ffca28). Ein fester
   Gelbwert wäre in einem der beiden Modi zwangsläufig zu blass - genau die
   vom Nutzer genannte Bedingung. */
/* ---- Getönte Fläche (2026-08-02, Nutzerwunsch: "einen Hauch von gelben
   hintergrund") ----
   Macht aus dem Hinweis einen sichtbar eigenen Block statt eines Absatzes,
   der zufällig ein Symbol vor sich hat. Das Symbol allein trug die
   Unterscheidung bisher fast im Alleingang.

   Mischpartner ist bewusst "transparent" und nicht --card-background: der
   Hinweis steht mal auf einer Karte, mal in einem aufgeklappten Akkordeon
   mit eigener Fläche. Als durchscheinender Schleier stimmt er über jedem
   Untergrund und in beiden Farbschemata - bei einem festen Mischpartner
   säße er auf der falschen Fläche wie ein aufgeklebter Zettel.

   14 % im Dunkelmodus statt 9 %: auf dunklem Grund verschluckt sich eine
   getönte Fläche schneller, weil der Abstand zum Untergrund kleiner ist.
   Beides live nachgemessen.

   Die Polsterung muss beim Symbol mitwandern - left/top richten sich
   deshalb nach denselben Werten, damit es innerhalb der Fläche sitzt und
   nicht an ihrem Rand klebt. */
p.field-hint:not(.field-hint--zaehler):not(.field-hint--fussnote):not(.field-hint--leer) {
    position: relative;
    padding: 0.7rem 0.95rem 0.7rem 2.45rem;
    background: color-mix(in srgb, var(--warning) 9%, transparent);
    border-radius: var(--squircle-sm);
    corner-shape: round;
}
/* Selektor exakt wie in css/tokens.css: das Farbschema hängt dort
   ausschließlich an :root[data-theme=...], nie an prefers-color-scheme. */
:root[data-theme="dark"] p.field-hint:not(.field-hint--zaehler):not(.field-hint--fussnote):not(.field-hint--leer) {
    background: color-mix(in srgb, var(--warning) 14%, transparent);
}
/* Durchgehend normale Strichstärke (2026-08-02, Nutzerwunsch: "alle texte
   durchgehend normal bitte nicht bold"). Viele dieser Hinweise beginnen mit
   einem <strong>-Satz, der vor der getönten Fläche nun doppelt betont wirkte
   - Fläche UND Fettung sagen dasselbe. Die Auszeichnung bleibt im Markup
   stehen: Screenreader kündigen sie weiterhin an, sichtbar tritt sie
   zurück. */
p.field-hint:not(.field-hint--zaehler):not(.field-hint--fussnote):not(.field-hint--leer) strong,
p.field-hint:not(.field-hint--zaehler):not(.field-hint--fussnote):not(.field-hint--leer) b {
    font-weight: inherit;
}
p.field-hint:not(.field-hint--zaehler):not(.field-hint--fussnote):not(.field-hint--leer)::before {
    content: "\f05a";
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    font-size: 0.95em;
    line-height: inherit;
    position: absolute;
    left: 0.95rem;
    top: 0.7rem;
    color: var(--warning-text);
}
/* Zähler-/Statuszeilen ("3 von 12 Nutzern angezeigt", Trefferzahl der
   Symbolauswahl) tragen dieselbe Klasse, sind aber keine Hinweise, sondern
   Rückmeldungen auf eine gerade getätigte Eingabe. Ein Info-Symbol davor
   würde sie zu einer Belehrung machen. */

/* Vereinzelte, handgesetzte Info-Symbole INNERHALB von Karten (z. B. der
   Vermerk am Admin-Konto) sprechen dieselbe Sprache - sonst hieße Gelb an
   der einen Stelle "Hinweis" und Grau an der anderen dasselbe. */
.fa-circle-info { color: var(--warning-text); }

/* ---------- Login-Verlauf: Ereignis-Kürzel + Legende (seit 2026-08-01) ----
   Nutzerwunsch: in der Liste keine ausgeschriebenen Werte, sondern farbige
   Kürzel mit Icon, die ALLE GLEICH GROSS sind - deshalb feste min-width und
   nowrap statt einer am Text mitwachsenden Pille wie bei .status-badge.
   Die ausgeschriebene Bedeutung steht einmalig in der Legende darüber (und
   zusätzlich im title-Attribut jedes Kürzels). */
.event-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-width: 68px;
    padding: 0.28rem 0.5rem;
    border-radius: var(--squircle-sm);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    white-space: nowrap;
}
.event-badge i { font-size: 0.82em; }
/* Fläche aus der Signalfarbe, Schrift aus dem zugehörigen TEXT-Ton (seit
   2026-09.08.2026 für Warnung, 09.08.2026 für die übrigen zwei). Vorher
   stand in allen dreien dieselbe Farbe oben wie unten - Farbe auf Farbe.
   Gemessen: 1,77:1 für die orange Pille im Hellmodus, 4,26:1 für die grüne,
   4,43:1 für die rote im Dunkelmodus.

   Warum die orange so weit daneben lag und trotzdem so lange stand: Es gab
   --warning-text bereits, angelegt am 02.08.2026 für genau diesen Fall -
   nur war diese Zeile beim Umstellen übersehen worden. Eine Regel, die man
   an EINER Stelle einführt und an drei Stellen anwenden muss, wird an
   zweien vergessen. */
.event-badge--active   { background: color-mix(in srgb, var(--success) 14%, var(--paper-raised)); color: var(--success-text); }
.event-badge--pending  { background: color-mix(in srgb, var(--warning) 16%, var(--paper-raised)); color: var(--warning-text); }
.event-badge--rejected { background: color-mix(in srgb, var(--danger) 12%, var(--paper-raised)); color: var(--danger-text); }
.event-badge--neutral  { background: color-mix(in srgb, var(--ink) 8%, var(--paper-raised)); color: var(--secondary-color); }

.legend {
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-tight);
    background: var(--paper-raised);
    padding: 1rem 1.1rem;
    margin: 1.2rem 0;
}
/* Die Legende ist seit 2026-08-02 ein <details> und startet zugeklappt.
   Die Überschrift behält ihre bisherige Optik (klein, versal, gesperrt),
   wird aber zur Klickfläche über die volle Breite - mit Chevron rechts,
   derselben Drehung und demselben Fokusrahmen wie bei den übrigen
   Akkordeons (.tool-panel--security summary). */
.legend-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    font-size: 0.76rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--secondary-color);
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.legend-title::-webkit-details-marker { display: none; }
.legend-title .chevron {
    font-size: 0.8rem;
    transition: transform 0.25s ease;
}
.legend[open] .legend-title .chevron { transform: rotate(180deg); }
.legend-title:hover { color: var(--accent); }
.legend-title:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 3px;
    border-radius: var(--squircle-sm);
}
/* Abstand zur Überschrift erst im geöffneten Zustand - als margin am
   Titel selbst bliebe er auch zugeklappt stehen und risse eine Lücke. */
.legend .legend-items { margin-top: 0.75rem; }
@media (prefers-reduced-motion: reduce) {
    .legend-title .chevron { transition: none; }
}
/* Zwei Spalten auf breiten Schirmen, eine auf schmalen - die Bedeutungen
   sind unterschiedlich lang, ein starres Raster würde Lücken reißen. */
.legend-items {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.55rem 1.4rem;
}
@media (max-width: 780px) {
    .legend-items { grid-template-columns: 1fr; }
}
.legend-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--secondary-color);
    line-height: 1.4;
}

/* ---------- Downloadliste (seit 2026-08-02) ------------------------------
   Zeilen statt Kacheln: bei Dateien zählen Name, Typ und Größe - eine
   Kachel würde für drei kurze Angaben zu viel Fläche beanspruchen und die
   Liste unruhig machen. Aufbau bewusst wie .section-tile in Farbe und
   Radius, damit beide Ansichten im selben Portal zusammengehören. */
.download-liste { display: flex; flex-direction: column; gap: 0.45rem; }
.download-zeile {
    display: grid;
    grid-template-columns: 54px 1fr auto 18px;
    align-items: center;
    gap: 0.9rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
    text-decoration: none;
    color: var(--primary-color);
    transition: border-color 0.15s ease, background 0.15s ease;
}
.download-zeile:hover {
    border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
    background: color-mix(in srgb, var(--accent) 6%, var(--paper-raised));
}
.download-zeile:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
/* Feste Breite für das Typ-Kürzel, damit die Dateinamen über alle Zeilen
   hinweg an derselben Kante beginnen - dieselbe Überlegung wie bei den
   Ereignis-Kürzeln im Login-Verlauf. */
.download-typ {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    padding: 0.2rem 0;
    border-radius: var(--squircle-sm);
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    color: var(--secondary-color);
}
.download-name { font-size: var(--backend-text); font-weight: 600; word-break: break-word; }
/* Größe und Stand teilen sich EINE Rasterspalte und stehen untereinander
   (seit 2026-08-21). Eine eigene Spalte für den Stand hätte die Zeile bei
   Dateien ohne Stand ins Leere laufen lassen - Projektdateien haben keinen
   (siehe inc/datei-stand.php). So bleibt das Raster viergliedrig, egal was
   in der Zelle steht. Rechtsbündig, damit die Zahlen an der Kante zum
   Download-Symbol eine Flucht bilden. */
.download-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.1rem;
    line-height: 1.25;
}
.download-groesse { font-size: 0.8rem; color: var(--secondary-color); white-space: nowrap; }
.download-stand { font-size: 0.72rem; color: var(--ink-faint); white-space: nowrap; }
.download-zeile i { color: var(--secondary-color); font-size: 0.85rem; }
/* ---- Schmale Geräte: zwei Zeilen statt vier Spalten (seit 2026-08-21) ----
   Vorher standen Name und Angaben nebeneinander. Auf dem Telefon blieben dem
   Dateinamen dadurch kaum 150 px, und "gravid-projekt-briefing-vorlage.pdf"
   wurde zu einem schmalen Stapel aus Wortresten gequetscht (vom Nutzer
   gemeldet, 21.08.2026).

   Jetzt bekommt der Name die volle Breite, Größe und Stand rücken darunter -
   also nebeneinander, wo sie auf dem Desktop übereinander stehen. Kürzel und
   Download-Symbol stehen weiterhin links und rechts und ziehen sich über
   BEIDE Zeilen; deshalb Rasterbereiche (grid-template-areas) statt einer
   zweiten Zeile aus eigenen Zellen: Nur so bleibt das Kürzel senkrecht
   mittig zu beidem, ohne dass man ihm eine Höhe vorschreiben muss.

   Die Größe kommt hier wieder zum Vorschein - sie war weggelassen worden,
   WEIL der Platz fehlte. Der Grund ist mit der zweiten Zeile weg. */
@media (max-width: 560px) {
    .download-zeile {
        grid-template-columns: 48px 1fr 18px;
        grid-template-areas:
            "typ name pfeil"
            "typ meta pfeil";
        column-gap: 0.7rem;
        row-gap: 0.15rem;
    }
    .download-typ  { grid-area: typ; }
    .download-name { grid-area: name; }
    .download-meta { grid-area: meta; }
    .download-zeile > i { grid-area: pfeil; }

    /* Untereinander wäre hier verschenkte Breite - nebeneinander, links
       an der Kante des Namens darüber. */
    .download-meta {
        flex-direction: row;
        align-items: baseline;
        gap: 0.45rem;
    }
    /* Trenner nur hier: Auf dem Desktop stehen die beiden Angaben
       untereinander und brauchen keinen. Als ::before am zweiten Element,
       damit er verschwindet, wenn es kein zweites gibt. */
    .download-stand::before {
        content: '·';
        margin-right: 0.45rem;
        /* Bewusst NICHT var(--line): Das ist ein Wert für Haarlinien und
           steht bei 11 % Deckung - als Schriftzeichen wäre er kaum zu
           sehen. Ein Trenner darf leiser sein als beide Angaben, die er
           trennt, aber er muss da sein. */
        color: color-mix(in srgb, var(--ink-faint) 55%, transparent);
    }
}

/* Sortierbare Spaltenköpfe: der <th>-Inhalt ist ein echter <button> (per
   Tastatur bedienbar), sieht aber aus wie die übrige Kopfzeile. */
.admin-table--sortable th { padding: 0; }
.th-sort {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    background: none;
    border: none;
    padding: 0 0.8rem 0.6rem;
    font-family: var(--font-family);
    font-size: inherit;
    font-weight: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.th-sort:hover { color: var(--accent-color); }
.th-sort i { opacity: 0.45; font-size: 0.9em; }
.admin-table--sortable th[data-sort-dir] .th-sort { color: var(--accent-color); }
.admin-table--sortable th[data-sort-dir] .th-sort i { opacity: 1; }

/* Umbruch-Hilfen für Tabellen (seit 2026-08-01): lange E-Mail-Adressen
   dürfen umbrechen, damit sie die Spalte nicht sprengen; Zeitstempel, IPs
   und Gerätenamen sollen dagegen NIE mitten im Wert umbrechen. */
.break-anywhere { overflow-wrap: anywhere; }
.admin-table td.nowrap, .admin-table th.nowrap { white-space: nowrap; }

/* Admin: Tabellen für Freischaltungen/Nutzerliste - schlicht, gut scanbar. */
/* Scroll-Container statt .admin-table selbst überlaufen zu lassen (seit
   2026-07-30, per Nutzer-Feedback zur mobilen Darstellung): auf schmalen
   Bildschirmen reicht der Platz für Name/E-Mail/Status/Datum/Aktionen
   nebeneinander nicht - ohne diesen Wrapper zog die Tabelle die GANZE Seite
   horizontal auf (siehe auch overflow-x:hidden auf html/body, css/shared.css),
   Status/Aktionen waren dadurch gar nicht mehr erreichbar. Jetzt scrollt nur
   die Tabelle selbst innerhalb ihrer eigenen Box. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
@media (max-width: 700px) {
    .admin-table { min-width: 640px; }
}
.admin-table th {
    text-align: left;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--secondary-color);
    padding: 0 0.8rem 0.6rem;
    border-bottom: 1px solid var(--line);
}
.admin-table td {
    padding: 0.85rem 0.8rem;
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
    color: var(--primary-color);
}
.admin-table tr:last-child td { border-bottom: none; }
.admin-table .muted { color: var(--secondary-color); font-size: 0.82rem; }

/* Login-Verlauf: nur ~10 Zeilen auf einen Blick, der Rest scrollt innerhalb
   der eigenen Box statt die Seite in die Länge zu ziehen (seit 2026-08-01).
   Der Kopf bleibt beim Scrollen sichtbar (sticky), damit die Spalten
   zuordenbar bleiben. */
.table-scroll--capped {
    max-height: 46.5rem;
    overflow-y: auto;
}
.table-scroll--capped thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    /* Abgesetzte Kopfzeile (seit 2026-08-02, Nutzerwunsch: "soll sich etwas
       abheben"). Vorher lag sie farblich auf der Karte und war beim
       Scrollen kaum von der ersten Datenzeile zu unterscheiden - gerade
       bei einer festgehefteten Kopfzeile aber der entscheidende Punkt.
       Eigene Fläche, kräftigere Schrift und eine deutlichere Unterkante;
       alles aus bestehenden Token, keine neuen Farben. */
    background: color-mix(in srgb, var(--ink) 6%, var(--card-background));
    color: var(--primary-color);
    font-weight: 700;
    border-bottom: 2px solid color-mix(in srgb, var(--accent-solid) 35%, var(--line));
    padding-top: 0.6rem;
}

/* ---- Fußnoten (.field-hint--fussnote) --------------------------------
   Erklärungen NACH einem Inhalt, die man beim Bedienen nicht braucht -
   aktuell der DSGVO-Vermerk unter der Login-Liste (seit 2026-08-01).
   Abgesetzt durch Trennlinie und gedämpfte Farbe, statt wie ein
   Bedienhinweis über der Liste auszusehen.

   KEIN gelbes Info-Symbol (Nutzervorgabe 2026-08-02: "fussnoten fallen da
   raus"). Das Symbol markiert Hinweise, die man VORHER lesen soll; eine
   Fußnote ist Nachschlagewerk und braucht diese Aufmerksamkeit nicht.

   Schriftgröße aber wie bei den Hinweisen (2026-08-02, Nutzerwunsch:
   "trotzdem noch eine größere schriftart... wie die hints") - vorher 0.78rem
   und damit spürbar kleiner als --backend-text. Genau das war der Grund für
   die globale Schriftgrößen-Regel weiter oben: zu kleine Backend-Texte sind
   nicht mehr angenehm lesbar. Abgesetzt bleibt die Fußnote über Linie und
   Farbe, nicht über Winzigkeit. */
p.field-hint--fussnote {
    margin-top: 1.3rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--line);
    color: var(--secondary-color);
}

/* Klickbare Zellen im Login-Verlauf: Ereignis/Nutzer/IP filtern die Liste
   auf gleichartige Einträge (seit 2026-08-01), siehe Skript weiter unten.
   Erneuter Klick auf denselben Wert hebt den Filter wieder auf. */
.log-filter {
    cursor: pointer;
    border-radius: var(--squircle-sm);
    transition: background-color 0.15s ease;
}
.log-filter:hover { background: var(--paper-raised); }
.log-filter:focus-visible { outline: 2px solid var(--accent-color); outline-offset: -2px; }
.log-filter.is-filter-active { background: color-mix(in srgb, var(--accent-color) 12%, var(--paper-raised)); }
.log-filter-status {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: color-mix(in srgb, var(--accent-color) 8%, var(--paper-raised));
    padding: 0.7rem 1rem;
    margin-bottom: 1rem;
    font-size: 0.88rem;
    color: var(--primary-color);
}
.log-filter-status[data-active="true"] { display: flex; }

/* .section-grants (die Reihe aus Bereichs-Kaestchen je Nutzer) ist am
   13.08.2026 mit der alten Zuordnungsliste entfallen - dort steht jetzt die
   Zuordnungs-Matrix. Das einzelne .section-grant lebt weiter: Die
   Nutzer-Verwaltung baut ihre Rechte-Kaestchen damit. */
.section-grant {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.65rem 0.3rem 0.5rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
    cursor: pointer;
}
.section-grant input { accent-color: var(--accent-color); }

/* Reine Anzeige statt Häkchen (seit 2026-08-02): unter "Aktive Nutzer"
   bekommt ein Admin-Konto die Bereiche nur aufgelistet - es sieht ohnehin
   alle, einzelne Freigaben wären wirkungslos. Optik bleibt die der
   Häkchen-Pillen daneben, damit die Liste nicht aus dem Rahmen fällt. */
.section-grant.is-static {
    cursor: default;
    color: var(--secondary-color);
    background: color-mix(in srgb, var(--ink) 4%, var(--paper-raised));
}
.section-grant.is-static i { color: var(--success); font-size: 0.75rem; }



/* Rechte-Raster eines Admin-Kontos: alle Häkchen gesetzt und gesperrt,
   reine Auskunft über den tatsächlichen Zustand. Leicht gedämpft, damit
   niemand versucht, dort etwas umzustellen. */
.permission-grid.is-locked .permission-item {
    cursor: default;
    opacity: 0.75;
    background: color-mix(in srgb, var(--ink) 4%, var(--paper-raised));
}

/* ---------- Admin: Berechtigungen / Rechtestufe "Verwalter" (seit 2026-08-01) ---------- */
.permission-role-choice { display: flex; gap: 0.8rem; margin-bottom: 1rem; }
.permission-grid { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }
.permission-item {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
    cursor: pointer;
}
.permission-item input { accent-color: var(--accent-color); margin-top: 0.2rem; flex-shrink: 0; }
.permission-item strong { display: block; color: var(--primary-color); }
.permission-item .muted { display: block; margin-top: 0.15rem; }

/* Abschlusszeile einer Nutzerkarte unter "Nutzer-Verwaltung" (seit
   2026-08-02, Nutzerwunsch): "Speichern" links, "Deaktivieren"/"Löschen"
   rechts abgesetzt.

   margin-left:auto an der rechten Gruppe statt space-between am Container:
   die linke Seite fehlt je nach Rechten (ein Verwalter sieht kein
   "Speichern"). Mit space-between rutschten die beiden roten Knöpfe dann
   nach LINKS an genau die Stelle, an der sonst der Sicherungsknopf sitzt -
   also dorthin, wo die Hand ohnehin hinzielt. Mit auto bleiben sie rechts,
   ganz gleich, was links steht.

   flex-wrap: auf schmalen Fenstern fällt die rechte Gruppe als GANZES in
   eine zweite Zeile, statt dass sich "Löschen" allein absetzt und plötzlich
   unter "Speichern" steht. */
.permission-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-top: 0.2rem;
}
.permission-actions-eingriff {
    display: flex;
    gap: 0.4rem;
    margin-left: auto;
}

/* Admin-Aktionen (Freigeben/Ablehnen) als kleine, inline nebeneinander
   stehende Buttons statt der vollbreiten .tool-btn. */
/* Bewusst NICHT umbrechend (seit 2026-07-30, Nutzerwunsch: "alle
   hintereinander horizontal angeordnet") - bei zu wenig Platz übernimmt der
   umgebende .table-scroll-Container das Scrollen (siehe dort), statt dass
   die Buttons selbst in der Zelle in eine zweite Zeile fallen. */
.row-actions { display: flex; gap: 0.4rem; flex-wrap: nowrap; }
/* Einheitliche Breite/Größe für kurze bis mittellange Labels (seit
   2026-07-30, Nutzerwunsch: "Buttons, die ähnlich groß sind, sollen immer
   gleich groß sein") - Freigeben/Ablehnen/Speichern/Reaktivieren/Sofort
   löschen passen alle darunter und stehen dadurch nebeneinander exakt
   gleich breit da, statt sich einzeln an den eigenen Text anzupassen.
   Bewusst KEIN fester width-Wert (würde sehr kurze Labels beschneiden oder
   sehr lange Labels umbrechen lassen) - min-width plus justify-content
   zentriert stattdessen den Inhalt in der gemeinsamen Mindestbreite. Echt
   lange Labels (z. B. "Konto deaktivieren", "Endgültig löschen") wachsen
   organisch darüber hinaus - genau die "nächste Stufe", die für sich
   genommen ebenfalls untereinander/nebeneinander gleich breit ausfällt,
   ohne dass dafür eine zweite, separat gepflegte Klasse nötig wäre.

   Mindestbreite am 2026-08-02 von 150px auf 112px gesenkt (Nutzerwunsch:
   "damit kein field overflow entsteht und ein horizontaler Scrollbalken
   auftaucht"). Drei Knöpfe nebeneinander - "Freigeben | Ablehnen |
   Löschen" unter Offene Anfragen - beanspruchten vorher allein 450px zzgl.
   Abständen und sprengten damit die Tabellenzelle. 112px ist bewusst NICHT
   knapp gerechnet: das längste Label dieser Gruppe ("Freigeben",
   "Speichern") misst mit Symbol, Abstand und Polsterung rund 111px. Die
   118px lassen bewusst Luft nach oben - die Textbreite lässt sich ohne
   Browser nur schätzen, und läge die Schätzung 5% daneben, würde
   ausgerechnet "Freigeben" über die gemeinsame Breite hinauswachsen und
   neben seinen Nachbarn ungleich aussehen. Lieber 6px verschenken als die
   Gleichbreite verlieren, um die es hier gerade geht. Die Gruppe steht dadurch weiterhin exakt gleich
   breit da, nur eben schmaler. Zusammen mit der schmaleren Seitenpolsterung
   (0.7 statt 0.85rem) und dem kleineren Abstand spart eine dreiteilige
   Reihe rund 120px.

   Die HÖHE bleibt ausdrücklich unverändert (Polsterung oben/unten
   weiterhin 0.45rem) - daran hängen mehrere andere Bauteile, unter
   anderem .add-new-toggle summary, .icon-picker-head .btn-sm und die
   Werkzeugzeile über der Nutzerliste. */
.btn-sm {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-width: 118px;
    font-family: var(--font-family);
    font-weight: 700;
    font-size: 0.8rem;
    /* Explizit statt der Browser-Vorgabe "normal" (seit 2026-08-01) - die
       weicht zwischen <button> und anderen Elementen (z. B. <summary>, wenn
       diese wie ein .btn-sm aussehen sollen) spürbar voneinander ab und
       machte sonst "Neuen Bereich anlegen" ca. 2,5px höher als
       Speichern/Löschen, obwohl Polsterung und Schriftgröße identisch
       waren. */
    line-height: 1;
    /* Seitenpolsterung 0.7rem statt 0.85rem (2026-08-02) - spart je Knopf
       rund 5px, ohne dass Text und Symbol gedrängt wirken. Oben/unten
       bewusst unverändert, siehe Begründung oben. */
    padding: 0.45rem 0.7rem;
    border-radius: var(--squircle-sm);
    cursor: pointer;
    border: 1px solid var(--line);
    /* ---- Neutrale Fläche als GRUNDZUSTAND (seit 2026-08-02) ----
       Vorher stand hier nur "border: 1px solid transparent" und gar kein
       Hintergrund: ein .btn-sm ohne Ampel-Klasse bekam damit die
       Standardoptik des Systems (grauer Verlauf, je nach Betriebssystem
       anders), die neben Speichern/Löschen sichtbar fremd wirkte.

       Repariert wurde das bisher zweimal von außen - erst über eine
       ID-Liste, dann über .section-list-toolbar .btn-sm. Beide Wege waren
       Aufzählungen, und beide sind genau daran gescheitert: erst fehlte der
       dritte Aufklapp-Knopf, dann traf die Zeilen-Regel plötzlich auch die
       Formularknöpfe des Akkordeons "Neuen Bereich anlegen" - und
       überstimmte dort mit ihrer höheren Spezifität sogar deren Ampelfarbe,
       weshalb "Anlegen" trotz .btn-sm--approve grau blieb.

       Jetzt trägt die Basis selbst die neutrale Fläche, und die Ampel-
       Klassen darunter überschreiben sie. Gleiche Spezifität, spätere
       Position - deshalb gewinnen sie zuverlässig, ohne dass irgendwo eine
       Liste gepflegt werden muss. Ein neuer Knopf sieht damit von allein
       richtig aus, egal wo er steht. */
    background: var(--paper-raised);
    color: var(--primary-color);
}
.btn-sm:hover { border-color: var(--accent-color); color: var(--accent-color); }
.btn-sm:disabled:hover { border-color: var(--line); color: var(--primary-color); }
@media (max-width: 480px) {
    .btn-sm { min-width: 0; flex: 1; }
}
/* Ampel-Klassen setzen ihre Hover-Farbe seit 2026-08-02 AUSDRUECKLICH mit.
   Die neue Basisregel .btn-sm:hover faerbt die Schrift in die Akzentfarbe
   (richtig fuer neutrale Knoepfe) und hat mit 0,1,1 dieselbe Spezifitaet wie
   diese Regeln hier - ohne eigenen color-Wert wuerde ein gruener Knopf beim
   Ueberfahren also blaue Schrift bekommen. */
/* --success-solid, NICHT --success: Die Fläche trägt weiße Schrift, und die
   dreht sich nicht mit dem Thema - der Untergrund darf es dann auch nicht.
   Mit --success kam der Knopf im Dunkelmodus auf 2,36:1 (vom Nutzer
   gemeldet 09.08.2026), jetzt 5,13:1 in beiden Themen. Begründung bei
   --success-solid in css/tokens.css. */
.btn-sm--approve { background: var(--success-solid); color: #fff; border-color: transparent; }
.btn-sm--approve:hover { filter: brightness(1.08); color: #fff; border-color: transparent; }
/* Vorstufe zu --approve (seit 2026-08-02, Nutzerwunsch für "Anlegen":
   "ein leichtes grün, quasi die vorstufe von Speichern"). Gleiche
   Farbfamilie - grün heißt im Backend durchgehend "es entsteht etwas bzw.
   bleibt bestehen" -, nur leiser: getönte Fläche statt Vollton, Schrift und
   Rahmen in Grün statt Weiß auf Grün.

   Bewusst über color-mix aus --success statt eines eigenen Farbwerts: die
   Abstufung bleibt dadurch an die CI-Farbe gekoppelt und stimmt in Hell-
   UND Dunkelmodus, weil --paper-raised sich mitdreht. Ein fester Hellgrünton
   wäre im Dunkelmodus ein leuchtender Fleck.

   12 % Fläche, 55 % Rahmen: dieselbe Staffelung wie bei .status-badge und
   .user-filter-btn.is-active, damit das Backend eine einzige Sprache für
   "getönt" spricht. Die Schrift bleibt der volle --success-Ton - gemischt
   wäre der Kontrast auf der getönten Fläche zu schwach. */
/* Schrift aus --success-text, Fläche und Rahmen weiter aus --success:
   Die Beschriftung stand auf ihrer eigenen Tönung und kam auf 4,36:1, beim
   Überfahren sogar nur auf 3,91:1 - je kräftiger die Tönung, desto enger
   wird es, weil sich Schrift und Fläche aufeinander zubewegen. */
.btn-sm--vorstufe {
    background: color-mix(in srgb, var(--success) 12%, var(--paper-raised));
    border-color: color-mix(in srgb, var(--success) 55%, transparent);
    color: var(--success-text);
}
.btn-sm--vorstufe:hover {
    background: color-mix(in srgb, var(--success) 20%, var(--paper-raised));
    border-color: var(--success);
    color: var(--success-text);
}
.btn-sm:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-sm:disabled:hover { filter: none; }
.btn-sm--reject { background: none; border-color: var(--danger); color: var(--danger); }
.btn-sm--reject:hover { background: color-mix(in srgb, var(--danger) 10%, transparent); color: var(--danger); border-color: var(--danger); }

/* Für zerstörerische Aktionen mit voller .tool-btn-Breite (Konto löschen) -
   .tool-btn.secondary reicht optisch nicht als Warnsignal. */
/* --danger-solid, nicht --danger: Die weiße Schrift kommt aus .tool-btn und
   dreht sich nicht mit dem Thema - die Fläche darunter darf es dann auch
   nicht. Mit --danger kam "Konto löschen" im Dunkelmodus auf 3,49:1 (vom
   Nutzer gemeldet 09.08.2026), jetzt 5,62:1 in beiden Themen. */
.tool-btn.danger { background: var(--danger-solid); }
.tool-btn.danger:hover { filter: brightness(1.08); }

/* 2FA-Einrichtung: QR-Code (per tools/qrcode-lib.js erzeugt, selbst
   gehostet) + Secret als Fallback für manuelle Eingabe. */
/* Abstand erhöht (seit 2026-07-30, Nutzerwunsch: "nicht zugequetscht") -
   war 1rem, wirkte zwischen Erklärtext/QR-Code/Secret/Eingabefeld/Buttons
   zu dicht gedrängt. */
.totp-setup { display: flex; flex-direction: column; align-items: center; gap: 1.6rem; text-align: center; }
.totp-setup canvas { border-radius: var(--squircle-sm); }
/* Jetzt ein <button> statt <div> (seit 2026-07-30, klickbar zum Kopieren
   in die Zwischenablage, siehe gravidCopyText() in _footer.php) - Reset der
   nativen Button-Chrome (Cursor/Outline/Textausrichtung/Breite), damit es
   optisch identisch zur vorherigen reinen Textbox bleibt. */
.totp-secret {
    display: block;
    width: 100%;
    font-family: var(--font-mono, monospace);
    font-size: 0.9rem;
    letter-spacing: 0.06em;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-tight);
    padding: 0.6rem 0.9rem;
    word-break: break-all;
    cursor: pointer;
    text-align: center;
    color: var(--primary-color);
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.totp-secret:hover { border-color: var(--accent-color); }
.totp-secret:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
.totp-secret.copied {
    background: color-mix(in srgb, var(--success) 14%, transparent);
    border-color: color-mix(in srgb, var(--success) 40%, transparent);
    color: var(--success);
    font-family: var(--font-family);
    letter-spacing: normal;
}
.recovery-codes {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
    font-family: var(--font-mono, monospace);
    font-size: 0.9rem;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-tight);
    padding: 1rem;
    width: 100%;
}

.section-list { display: flex; flex-direction: column; gap: 0.5rem; margin: 0; padding: 0; list-style: none; }
.section-list li {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-tight);
    background: var(--paper-raised);
}
.section-list li i { color: var(--success); }

/* ---------- Bereichs-Kacheln (seit 2026-07-30) ----------
   Gleiche Optik wie die Tool-Zeilen auf der Startseite (.tool-row in
   css/index.css), aber unter eigenem Klassennamen: tools/tools.css
   definiert bereits eine GANZ ANDERE .tool-row (generische 2-Spalten-Grid-
   Utility für Formularfeld-Paare, siehe dort) - dieselbe Klasse hier zu
   verwenden hätte auf Portal-Seiten mit der falschen Regel kollidiert
   (tools.css lädt dort ebenfalls, siehe _header.php). */
/* Drei Kacheln pro Zeile (~ein Drittel der Contentfläche je Kachel, seit
   2026-07-30 auf Nutzerwunsch) statt einer vollbreiten Liste - dafür
   .section-tile von einer horizontalen Zeile (Icon/Text/Pfeil nebeneinander,
   passend für volle Breite) auf eine vertikal gestapelte Karte umgestellt,
   der Pfeil sitzt jetzt als kleines Chevron oben rechts in der Karte statt
   als eigene Spalte - bei ~1/3 Breite wäre für die vorherige Zeilen-Optik
   nicht genug Platz für den Beschreibungstext gewesen. */
/* ---- Abschnittsüberschrift in einer Karte (seit 2026-08-02) -----------
   Nutzerhinweis: "die abstände der kacheln zu den überschriften sind nicht
   einheitlich". Die Ursache stand im Markup: jede dieser Überschriften trug
   ihre Abstände als style-Attribut, und die Werte waren über die Zeit
   auseinandergelaufen - "Intern" ließ den unteren Abstand auf dem
   h2-Standard stehen, "Kundenbereiche" setzte 0.9rem. Zwischen Überschrift
   und Kachelreihe klaffte darunter also einmal mehr, einmal weniger.

   Inline-Styles sind für so etwas die falsche Stelle: sie stehen an sechs
   Orten und niemand vergleicht sie. Jetzt EIN Bauteil - wer eine neue
   Abschnittsüberschrift setzt, bekommt die Abstände geschenkt. */
.panel-titel {
    margin: 0 0 0.9rem;
    font-size: 1.15rem;
}
/* Folgt eine Überschrift auf einen vorherigen Abschnitt, braucht sie Luft
   nach oben. Über den Nachbar-Selektor statt über margin-top an der
   Überschrift selbst: so bleibt die ERSTE Überschrift einer Karte ohne
   Vorspann bündig am Kartenrand, ohne Sonderfall im Markup. */
.section-tiles + .panel-titel,
.download-liste + .panel-titel { margin-top: 1.8rem; }

.section-tiles {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
}
@media (max-width: 860px) {
    .section-tiles { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
    .section-tiles { grid-template-columns: 1fr; }
}
/* Stil an .kontakt-card der Hauptseite angeglichen (seit 2026-08-01,
   Nutzerwunsch) - Kachelgröße und die Position des Aktions-Icons oben
   rechts bleiben bewusst unverändert, nur Rahmen-/Hover-Optik und das
   Icon selbst (Kreis-Button -> bloßes Glyph, arrow-up-right-from-square
   statt arrow-right, siehe konto.php) ziehen nach. */
.section-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 18px 20px;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--squircle-lg);
    box-shadow: var(--shadow-tight);
    text-decoration: none;
    color: inherit;
    transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
.section-tile:hover { background: var(--accent-tint); border-color: var(--accent-color); transform: translateY(-2px); }
.section-tile:hover .section-tile-action { transform: translate(3px, -3px); color: var(--accent-color); }
.section-tile-icon {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--squircle-sm);
    background: var(--accent-tint);
    color: var(--accent-color);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
}
.section-tile-body { width: 100%; min-width: 0; padding-right: 26px; }
.section-tile-body h3 { font-size: 0.98rem; font-weight: 700; margin: 0; color: var(--primary-color); }
.section-tile-body p { color: var(--secondary-color); font-size: 0.85rem; margin: 3px 0 0; }
.section-tile-action {
    position: absolute;
    top: 18px;
    right: 20px;
    flex-shrink: 0;
    color: var(--secondary-color);
    font-size: 0.85rem;
    transition: transform 0.2s ease, color 0.2s ease;
}

/* ---------- Bereiche: Symbol- und Ordner-Auswahl (seit 2026-08-01) ----
   Beide Felder bleiben frei tippbar - die Auswahlhilfe ergänzt das Feld,
   ersetzt es nicht. So lassen sich neben Ordnern weiterhin einzelne Seiten
   oder externe Adressen hinterlegen. */
.picker {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.picker .tool-input,
.picker .tool-select {
    flex: 1;
    min-width: 0;
    height: var(--picker-h);
    padding-top: 0;
    padding-bottom: 0;
}
.picker-preview {
    flex-shrink: 0;
    width: var(--picker-h);
    height: var(--picker-h);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
    color: var(--accent-color);
}
.picker-btn {
    flex-shrink: 0;
    width: var(--picker-h);
    height: var(--picker-h);
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
    color: var(--secondary-color);
    cursor: pointer;
    transition: color 0.2s ease, border-color 0.2s ease;
}
.picker-btn:hover { color: var(--accent-color); border-color: var(--accent-color); }
.picker-select { flex-shrink: 0; max-width: 46%; }
@media (max-width: 600px) {
    /* Auf schmalen Displays untereinander - nebeneinander bliebe für Liste
       UND Textfeld zu wenig Platz zum Lesen und Tippen. */
    .picker { flex-wrap: wrap; }
    .picker-select { max-width: none; width: 100%; }
    .picker .tool-input { flex: 1 1 100%; }
}

/* Schwebt über dem restlichen Formular statt es nach unten zu verschieben
   (seit 2026-08-01) - wird per JS als Kind des jeweiligen .field angehängt
   (siehe render_icon_picker()-Skript), :has() macht genau dieses .field zum
   Anker, ohne dass .field generell position:relative bräuchte. */
.field:has(> .icon-picker) {
    position: relative;
}
.icon-picker {
    position: absolute;
    top: calc(100% + 0.4rem);
    left: 0;
    z-index: 40;
    /* Deutlich breiter als das Feld darunter (seit 2026-08-01,
       Nutzerwunsch: "mehr Symbole auf einen Blick"): bei 400px passten drei
       Symbole nebeneinander, das Raster wurde dadurch sehr lang. Jetzt rund
       das Doppelte, auf schmalen Fenstern durch die Fensterbreite begrenzt.
       Das Panel ragt bewusst über die Feldbreite hinaus - es schwebt
       ohnehin über dem Inhalt. */
    width: min(720px, calc(100vw - 3rem));
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-popover);
    background: var(--card-background);
    padding: 0.9rem;
}
/* Einheitliche Höhe für alles, was in einer Auswahl-Zeile nebeneinander
   steht (seit 2026-08-01, Nutzerwunsch) - Suchfeld, Knöpfe, Vorschau und
   Klappliste liefen vorher auseinander: .tool-input kommt auf rund 44px,
   .btn-sm auf rund 29px, die Icon-Knöpfe auf 38px. Ein gemeinsamer Wert
   beruhigt das Bild deutlich. */
:root { --picker-h: 38px; }
.icon-picker-head {
    display: flex;
    gap: 0.6rem;
    align-items: center;
    margin-bottom: 0.6rem;
}
.icon-picker-head .tool-input {
    flex: 1;
    min-width: 0;
    height: var(--picker-h);
    padding-top: 0;
    padding-bottom: 0;
}
.icon-picker-head .btn-sm {
    height: var(--picker-h);
    flex-shrink: 0;
}
.icon-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
    gap: 0.4rem;
    max-height: 340px;
    overflow-y: auto;
    /* Verhindert, dass beim Nachladen die ganze Seite mitscrollt, sobald
       das Raster unten ankommt. */
    overscroll-behavior: contain;
}
.icon-option {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    padding: 0.6rem 0.3rem;
    border: 1px solid transparent;
    border-radius: var(--squircle-sm);
    background: none;
    cursor: pointer;
    color: var(--primary-color);
    font-family: var(--font-family);
    font-size: 0.68rem;
    line-height: 1.2;
}
.icon-option i { font-size: 1.1rem; color: var(--accent-color); }
.icon-option span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--secondary-color);
}
.icon-option:hover { border-color: var(--accent-color); background: var(--accent-tint); }
/* Bereits gewähltes Symbol (seit 2026-08-01): beim Öffnen springt die Liste
   dorthin, damit man nicht erneut danach suchen muss - dann muss es auch
   erkennbar sein. */
.icon-option.is-selected {
    border-color: var(--accent-color);
    background: var(--accent-tint);
}
.icon-option.is-selected span { color: var(--accent-color); font-weight: 700; }

/* Aktionszeile unter der Kurzbeschreibung: Checkbox + alle Buttons in EINER
   Reihe (seit 2026-08-01, Nutzerwunsch). Die Buttons gehören zu zwei
   verschiedenen Formularen und stehen deshalb über das form-Attribut
   außerhalb davon - siehe Kommentar im Markup. */
.section-edit-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin: 0 0 1.6rem;
    padding-bottom: 1.6rem;
    border-bottom: 1px solid var(--line);
}
.section-edit-actions .checkbox-line { margin-right: 0.4rem; }
@media (max-width: 600px) {
    /* Mobil untereinander und über die volle Breite - nebeneinander wären
       die Buttons zu schmal zum sicheren Treffen. */
    .section-edit-actions { flex-direction: column; align-items: stretch; }
    .section-edit-actions .btn-sm { width: 100%; min-width: 0; }
    .section-edit-actions .checkbox-line { margin: 0 0 0.2rem; }
}

/* ---------- Admin: Bereiche verwalten + Nutzer-Akkordeon (seit 2026-07-30) ---------- */
.section-edit-row { margin-bottom: 0.8rem; }
/* "Neuen Bereich anlegen" oben als echter Button statt als unauffälliger
   Text-Link (seit 2026-08-01, Nutzerwunsch) - bleibt technisch ein
   <details>/<summary> (siehe Akkordeon-Slide-Animation oben), sieht aber
   wie eine grüne .btn-sm--approve-Schaltfläche aus. inline-flex statt der
   vollen Blockbreite, damit sie in der .section-list-toolbar neben "Alle
   aufklappen" steht statt eine eigene Zeile zu beanspruchen.
   Polsterung/Schriftgröße bewusst IDENTISCH zu .btn-sm (0.45rem 0.7rem /
   0.8rem; Seitenwert und Mindestbreite am 2026-08-02 mitgesenkt) -
   Nutzervorgabe seit 2026-08-01: alle Funktionsbuttons unter
   "Bereiche" richten sich in der Höhe nach Speichern/Löschen
   (.section-edit-actions .btn-sm), die genau diese Basiswerte nutzen.
   Eigene, größere Werte hier hätten "Neuen Bereich anlegen" spürbar höher
   als die übrigen Buttons aussehen lassen. */
.add-new-toggle summary {
    cursor: pointer;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-width: 118px;
    justify-content: center;
    font-weight: 700;
    font-size: 0.8rem;
    /* line-height + Rahmen exakt wie .btn-sm (seit 2026-08-01) - ein
       <summary> hat ohne das einen anderen Zeilenabstand als ein <button>
       (erbt hier 1.6 statt der button-eigenen UA-Vorgabe "normal") und wäre
       sonst trotz identischer Polsterung/Schriftgröße spürbar höher. Der
       transparente Rahmen verbraucht denselben Platz wie bei .btn-sm, statt
       dass der fehlende Rahmen die Box wieder verkleinert. */
    line-height: 1;
    border: 1px solid transparent;
    color: #fff;
    /* Siehe .btn-sm--approve weiter oben: weiße Schrift verlangt eine
       Fläche, die sich nicht mit dem Thema dreht. */
    background: var(--success-solid);
    padding: 0.45rem 0.7rem;
    border-radius: var(--squircle-sm);
    transition: filter 0.2s ease;
}
.add-new-toggle summary:hover { filter: brightness(1.08); }
.add-new-toggle summary:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
.add-new-toggle summary::-webkit-details-marker { display: none; }

/* ---------- Nutzerliste: Filter nach Rechteebene + Suche (2026-08-02) ----
   Die Werkzeugzeile enthält hier drei verschiedene Bauteile (Knopf,
   Filterschalter, Suchfeld). Ohne gemeinsame Höhe stünden sie sichtbar
   versetzt nebeneinander - .btn-sm ist rund 29px hoch, ein .tool-input
   deutlich mehr. Deshalb eine feste gemeinsame Höhe, bewusst NUR in
   dieser Zeile (.user-toolbar) statt global an .btn-sm, damit die
   Knöpfe in den Tabellenzeilen unverändert bleiben. */
.user-toolbar { align-items: center; }
.user-toolbar .btn-sm,
.user-filter-btn,
.user-search .tool-input {
    height: 34px;
}
.user-search .tool-input { padding-top: 0; padding-bottom: 0; }

.user-filter { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; }
.user-filter-btn {
    font-family: var(--font-family);
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1;
    padding: 0 0.85rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    corner-shape: round;
    background: var(--paper-raised);
    color: var(--secondary-color);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.user-filter-btn:hover {
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
}
/* Gewählter Filter in der Akzentfarbe - bewusst nicht in Grün/Orange/Rot:
   die Ampelfarben stehen im Backend für Zustände (aktiv, offen, abgelehnt),
   nicht für "dieser Schalter ist gerade gewählt". */
.user-filter-btn.is-active {
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    border-color: color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--accent);
}
.user-filter-btn:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }

.user-search { position: relative; display: inline-flex; align-items: center; }
.user-search i {
    position: absolute;
    left: 0.75rem;
    font-size: 0.8rem;
    color: var(--ink-faint);
    pointer-events: none;
}
/* Das Suchfeld nimmt den Rest der Zeile (seit 2026-08-13, Nutzerwunsch:
   "auf die restlich zur Verfügung stehende Länge des Contentbereiches
   verlängern, wie bei der Suche von Security Briefing").

   Vorher stand hier eine feste min-width von 230px. Bei 1rem Schriftgröße
   plus 2,2rem Platz für die Lupe reichte das für "Bereich suchen", nicht
   aber für "Name oder E-Mail suchen" - die Beschriftung war abgeschnitten,
   also genau die Zeile, die dem Feld seinen Zweck erklärt.

   Eine größere feste Breite wäre nur die nächste Zahl gewesen, die beim
   nächsten längeren Text wieder nicht passt. Das Briefing macht es seit
   06.08. richtig herum: Das Feld bekommt, was übrig ist (.sec-suche weiter
   unten, dieselbe Mechanik).

   flex-basis 260px statt auto: In diesen drei Werkzeugzeilen stehen noch
   ein Klappen-Knopf und bis zu vier Filterschalter. Bleiben davon weniger
   als 260px übrig, rutscht das Feld auf eine eigene Zeile und nimmt dort
   die volle Breite - statt sich zwischen die Schalter zu quetschen. Damit
   ist auch die frühere 560px-Ausnahme für schmale Geräte überflüssig: Der
   Umbruch entsteht jetzt aus dem Platzbedarf selbst, nicht aus einer
   geratenen Bildschirmbreite. */
.user-search { flex: 1 1 260px; min-width: 0; }
.user-search .tool-input {
    padding-left: 2.2rem;
    width: 100%;
    min-width: 0;
}

/* ---- Der Klappen-Knopf: eine Beschriftung, eine Breite (2026-08-06) ---
   Nutzervorgabe: Der Knopf heißt "Alle auf"/"Alle zu" und ist "in beiden
   Ansichten einheitlich breit". ("Alle", weil alle Karten der Liste gemeint
   sind - "Leiste auf"/"Leiste zu" heißt ausschließlich der Knopf, der in
   der Bereichsansicht die Vorschau-Leiste ein- und ausblendet, siehe
   css/preview-bar.css.)

   Zwischenstand desselben Tages, der Nachvollziehbarkeit halber: Erst gab
   es zwei Beschriftungen im Markup ("Alle aufklappen" am Rechner, "Alles
   auf" am Telefon, umgeschaltet per Medienabfrage) und folglich auch zwei
   Breiten. Mit dem kurzen Namen lohnt beides nicht mehr - eine
   Beschriftung, eine Breite, kein Umschaltmechanismus.

   Warum die Breite überhaupt fest ist: "Alle auf" ist 88,3px breit,
   "Alle zu" 81,0px (Quicksand 0.8rem/700, gemessen). Diese gut 7px
   wanderten bei jedem Druck durch die ganze Zeile - der Knopf beschriftet
   sich ja bei jedem Klick um. 96px lassen rund 9% Luft über dem längeren
   der beiden Texte.

   width statt min-width, obwohl min-width gnädiger wäre (der Knopf dürfte
   wachsen, statt zu überlaufen): Genau dieses Wachsen darf hier nicht
   passieren. Der Anlegen-Knopf daneben wird an dieser Breite ausgerichtet
   (siehe .add-new-toggle weiter unten) - würde der Knopf wachsen, liefe er
   unter den Nachbarn. Die Schrift wird selbst ausgeliefert (css/fonts.css),
   ein abweichender Systemfont ist also nicht zu erwarten.

   flex: 0 0 auto hebt die Regel aus @media (max-width: 480px) auf, die
   .btn-sm dort auf flex: 1 setzt - die gilt den Formularknöpfen, die sich
   die Zeile teilen sollen, nicht diesem hier. */
.section-list-toolbar {
    --zeilen-knopf-breite: 96px;
    /* Breite des Anlegen-Knopfs, siehe .add-new-toggle weiter unten. */
    --anlegen-knopf-breite: 190px;
}
.section-list-toolbar > .btn-sm {
    width: var(--zeilen-knopf-breite);
    min-width: 0;
    flex: 0 0 auto;
    white-space: nowrap;
}

/* Button + Formular stehen zusammen in der Toolbar über der Liste;
   flex-start verhindert, dass "Alle auf" auf die volle Höhe des
   geöffneten Formulars gestreckt wird. */
.section-list-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.7rem;
    margin-bottom: 1.2rem;
}
/* ---- Anlege-Formular volle Breite, Knopf bleibt in der Zeile ----------
   Zwei Fehlerbilder nacheinander, beide gemeldet, beide hier verewigt:

   1. Beim Aufklappen von "Neuen Bereich anlegen" rutschte der Knopf in die
      zweite Zeile unter "Alle auf". Ursache: <details> ist ein
      Flex-Element, und seine Grundbreite kommt aus dem Inhalt - im
      geöffneten Zustand also aus dem ganzen Formular samt Ordner-Klappliste,
      deren längster Eintrag die Wunschbreite bestimmt. Passte das nicht mehr
      neben den Knopf, brach die Zeile um. Zugeklappt zählt der Inhalt nicht
      mit, deshalb sprang es genau beim Öffnen.

   2. Der erste Versuch (flex: 1 1 0, also "nimm den Rest der Zeile") hielt
      den Knopf zwar oben, schob aber das ganze Formular um die Knopfbreite
      nach rechts ein - es stand ja im rechten Rest der Zeile.

   Jetzt bekommt das <details> IMMER eine eigene volle Zeile, das Formular
   steht damit von allein auf voller Breite und bündig links. Nur der
   Summary-Knopf wird ab 721px absolut in die erste Zeile neben "Alle
   auf" gesetzt.

   Warum der Summary und nicht das Formular verschoben wird: Der Summary
   liegt AUSSERHALB von ::details-content, dem Pseudoelement, das die
   Aufklapp-Animation trägt. Verschöbe man stattdessen das Formular mit
   negativem Rand nach links, ragte es aus diesem Pseudoelement heraus - und
   das ist während der Animation overflow: hidden (siehe Akkordeon-Standard
   oben). Das Formular wäre also für die Dauer des Aufklappens links
   angeschnitten und spränge erst am Ende auf volle Breite.

   left rechnet mit derselben Variable, die dem Knopf oben seine feste
   Breite gibt, plus dem Zeilenabstand. Deshalb MUSS die Knopfbreite fest
   sein - mit einer mitwachsenden Breite säßen die beiden übereinander.

   row-gap: 0 nur hier: Die zweite Zeile ist zugeklappt null Pixel hoch,
   ein Zeilenabstand würde als unerklärliche Lücke unter der Werkzeugzeile
   stehen bleiben. Den Abstand zum Formular setzt das Formular selbst.
   Der doppelte :has()-Filter trifft ausschließlich diese Werkzeugzeile:
   ein .btn-sm als direktes Kind (fehlt, solange es noch keinen Bereich
   gibt - dann steht der Anlegen-Knopf allein und braucht keinen Versatz)
   UND das Anlege-Akkordeon (fehlt in "Bereiche zuordnen" und
   "Nutzer-Verwaltung", deren Filter- und Suchzeile den Zeilenabstand
   weiterhin braucht).

   Unter 721px bleibt alles im normalen Fluss: Der Knopf steht dann unter
   "Alle auf" - aber IMMER, nicht erst beim Öffnen. Neben dem Knopf
   wäre dort ohnehin zu wenig Platz, und bei genau 720px schaltet auch
   .backend-row--3 auf eine Spalte um (siehe ganz oben). */
.section-list-toolbar .add-new-toggle {
    flex: 0 0 100%;
    min-width: 0;
    /* Ganz ans Ende der Zeile (seit 2026-08-06): Ein Element mit voller
       Breite bricht die Zeile IMMER um - alles, was im Markup dahinter
       steht, landete sonst unter ihm statt neben dem Klapp-Knopf. Seit
       Sortierung und Suche dazugekommen sind, ist genau das der Fall. Mit
       order steht das <details> zuletzt, die Werkzeuge davor bleiben in der
       ersten Zeile, und das Formular öffnet unter allem. */
    order: 99;
}
/* Feste Breite auch hier - der Platz, den der absolut gesetzte Knopf in der
   ersten Zeile beansprucht, wird weiter unten mit derselben Zahl reserviert.
   Gemessen 183,5px (Quicksand 0.8rem/700 samt Symbol), 190px lassen Luft. */
.section-list-toolbar .add-new-toggle > summary { width: var(--anlegen-knopf-breite); }
@media (min-width: 721px) {
    .section-list-toolbar:has(> .btn-sm):has(> .add-new-toggle) { position: relative; }
    /* Zugeklappt ist die Zeile des <details> null Pixel hoch (der Knopf
       darin steht ja absolut) - der Zeilenabstand davor bleibt aber stehen
       und säße als unerklärliche Lücke unter der Werkzeugzeile. Er wird
       deshalb vom Außenabstand nach unten abgezogen, solange zugeklappt
       ist; aufgeklappt gilt wieder der volle Abstand zur Liste.

       Bewusst hier statt row-gap: 0 an der Zeile: Brechen Sortierung und
       Suche auf schmaleren Fenstern in eine zweite Zeile um, brauchen DIE
       ihren Abstand weiterhin. Und bewusst kein negativer margin-top am
       <details> - ein negativer Außenabstand macht eine Flex-Zeile nicht
       schmaler als null, die Lücke bliebe stehen (ausprobiert). */
    .section-list-toolbar:has(> .add-new-toggle:not([open])) {
        margin-bottom: calc(1.2rem - 0.7rem);
    }
    .section-list-toolbar:has(> .btn-sm) > .add-new-toggle > summary {
        position: absolute;
        top: 0;
        left: calc(var(--zeilen-knopf-breite) + 0.7rem);
    }
    /* Der absolut gesetzte Knopf beansprucht keinen Platz im Fluss - ohne
       diese Reserve läge das nächste Bauteil (die Sortierung) unter ihm. */
    .section-list-toolbar:has(> .btn-sm) > .add-new-toggle + * {
        margin-left: calc(var(--anlegen-knopf-breite) + 0.7rem);
    }
}

/* "Alle aufklappen"/"Alle zuklappen" braucht hier KEINE eigene Regel mehr
   (2026-08-02). Die neutrale Fläche steckt seit heute in .btn-sm selbst
   (siehe dort samt Begründung) - der Knopf trägt keine Ampel-Klasse und
   bekommt sie damit von allein. Vorher stand hier erst eine ID-Liste, dann
   ein Nachfahren-Selektor; beides hat je einmal den falschen Knopf getroffen
   bzw. einen vergessen. */

/* Jeder Bereich in einer eigenen Karte statt formlos untereinander (seit
   2026-08-01, Nutzerwunsch: "damit man sie besser auseinanderhalten kann") -
   optisch wie .user-accordion details, aber als eigene Klasse, damit die
   Kopfzeile (Symbol/Name/Öffentlich-Pille statt Name/E-Mail/Admin-Pille)
   unabhängig gestaltet werden kann. Bewusst KEIN gemeinsames name-Attribut
   im Markup - jede Karte klappt unabhängig von den anderen auf/zu. */
.section-card-list { display: flex; flex-direction: column; gap: 0.6rem; }
/* ---- Die Kopfzeile IST die Schaltfläche (seit 2026-08-06) --------------
   Gemeldet: "Bei den Details soll die ganze Fläche der Link sein, nicht nur
   die Zeile, wo der Inhalt steht. Die ganze Fläche reagiert auf den
   Hovereffekt, aber nicht auf den Klick."

   Genau so war es: Die Polsterung saß an der KARTE, das <summary> lag darin
   wie ein Textabsatz. Anklickbar ist aber nur das <summary> - die 0,9rem
   oben und unten und die 1,1rem links und rechts gehörten der Karte und
   schluckten den Klick. Getönt hat sich trotzdem alles, weil die
   Hover-Regel an der Karte hängt. Ein Ziel, das aussieht wie eine
   Schaltfläche, sich aber nur in seiner Mitte drücken lässt.

   Die Polsterung wandert deshalb an das <summary> (siehe unten). Damit füllt
   es die Karte vollständig aus, und die getönte Fläche und die klickbare
   Fläche sind wieder dasselbe. */
.section-card {
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-tight);
    background: var(--paper-raised);
    padding: 0;
}
.section-card summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    /* Füllt die Karte vollständig aus - Begründung siehe .section-card. */
    padding: 0.9rem 1.1rem;
    font-weight: 700;
    color: var(--primary-color);
}
.section-card summary::-webkit-details-marker { display: none; }
.section-card summary:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 3px; border-radius: var(--squircle-sm); }
.section-card-title { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.section-card-title i:first-child { color: var(--secondary-color); font-size: 0.9em; }
/* Rechte Gruppe der Kartenkopfzeile: Vorschau-Knopf + Chevron (seit
   2026-08-06). Nötig, weil das <summary> mit justify-content:space-between
   arbeitet - mit drei einzelnen Kindern stünde der Knopf in der MITTE der
   Zeile statt rechts. Als Gruppe bleiben es zwei Kinder: Titel links,
   Bedienung rechts. */
.section-card-actions {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    flex-shrink: 0;
}
/* Die Knöpfe als eigene Gruppe (seit 2026-08-08, mit dem "Clean"-Knopf
   dazugekommen). Nebeneinander, solange Platz ist. */
.section-card-links {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
/* Der Knopf trägt .btn-sm und damit dessen Mindestmaße - beide sind hier
   aufgehoben:

   Breite (118px): In der Kartenzeile steht er allein und muss sich mit
   niemandem auf eine gemeinsame Breite einigen; 118px wären für ein Wort nur
   unnötig viel Fläche.

   Höhe (34px, --backend-bauteil-hoehe): Sie gilt Bedienelementen, die in
   einer Reihe nebeneinander stehen. Hier machte sie die Karten in "Bereiche
   verwalten" 7px höher als die in den beiden Nachbartabs (65px gegen 58px) -
   gemeldet am 2026-08-06. Der Knopf richtet sich stattdessen nach der
   Kopfzeile, in der er sitzt, statt sie auseinanderzudrücken.

   Der Selektor nennt zusätzlich die Elterngruppe, damit er die gemeinsame
   Höhenregel weiter unten in der Datei sicher überstimmt - bei gleicher
   Spezifität gewänne sonst die spätere. */
.section-card-actions .section-card-vorschau {
    min-width: 0;
    min-height: 0;
    padding: 0.35rem 0.6rem;
    text-decoration: none;
    font-size: 0.78rem;
}
/* ---- Schmale Geräte: die Knöpfe untereinander (seit 2026-08-08) --------
   Nutzervorgabe: "Der neue Clean-Knopf soll bei Mobilgeräten unterhalb des
   Vorschau-Knopfes zu sehen sein. Beide sollen gleich lang sein, um ein
   einheitliches Bild zu bekommen."

   Nebeneinander bliebe neben dem Bereichsnamen zu wenig übrig; der Name
   umbräche auf drei Zeilen, um zwei Knöpfen Platz zu machen.

   Die gleiche Länge kommt dabei von selbst: In einer Spalte mit
   align-items: stretch nehmen beide die Breite des Behälters an, und die
   richtet sich nach dem breiteren der beiden ("Vorschau"). Bewusst KEIN
   fester Wert - der müsste bei jeder Beschriftungsänderung nachgezogen
   werden und säße bei einer anderen Schriftgröße daneben.

   justify-content: center, damit Symbol und Wort im breiteren Knopf mittig
   sitzen statt links zu kleben - sonst sähe die Spalte trotz gleicher
   Breite ungleich aus. */
@media (max-width: 700px) {
    .section-card-links {
        flex-direction: column;
        align-items: stretch;
    }
    .section-card-actions .section-card-vorschau { justify-content: center; }
}
.section-card summary .chevron { flex-shrink: 0; color: var(--secondary-color); font-size: 0.85em; transition: transform 0.2s ease; }
.section-card[open] summary .chevron { transform: rotate(180deg); }
/* Seitliche Einrückung jetzt über den Außenabstand statt über die
   Kartenpolsterung - so bleibt die Trennlinie so breit wie bisher, statt von
   Kante zu Kante zu laufen. Der Abstand nach oben kommt aus der Polsterung
   des <summary> darüber. */
.section-card-body { margin: 0 1.1rem 0.9rem; padding-top: 1rem; border-top: 1px solid var(--line); }
@media (prefers-reduced-motion: reduce) {
    .section-card summary .chevron { transition: none; }
}

/* ---- Karten reagieren auf Zeiger und bleiben beim Bearbeiten sichtbar
   (seit 2026-08-06) -------------------------------------------------------
   Nutzerwunsch: "Hover-Effekt wie bei den Section-Tiles, und wenn man es
   geklickt hat, soll der Bereich mit der Hoverfarbe dezent aktiv bleiben,
   damit es sich beim Bearbeiten besser abhebt."

   Gilt für alle drei Listen im Admin: .section-card ("Bereiche verwalten")
   und .user-accordion details ("Bereiche zuordnen", "Nutzer-Verwaltung").
   Sie sehen ohnehin gleich aus, also gehören sie in dieselbe Regel - eine
   eigene Fassung je Liste liefe früher oder später auseinander.

   Farben wie bei .section-tile:hover (--accent-tint plus Akzentrahmen), aber
   OHNE dessen translateY: Eine Kachel darf sich anheben, eine Zeile über die
   volle Breite wirkt dabei wackelig - und im geöffneten Zustand säße der
   angehobene Rahmen dauerhaft neben seinem Schatten.

   Der Zeiger-Zustand gilt nur ZUGEKLAPPT (:not([open])): Offen ist die Karte
   ohnehin getönt, und beim Ausfüllen des Formulars darüber zu fahren soll
   nicht zusätzlich aufleuchten.

   Der aktive Zustand ist bewusst schwächer als der Zeiger-Zustand - er steht
   dauerhaft da, solange man bearbeitet. Gemischt wird gegen die tatsächliche
   Kartenfläche (--paper-raised), damit er im Dunkelmodus genauso funktioniert.

   Als Beimischung dient --accent und NICHT --accent-tint: Letzteres ist im
   Dunkelmodus selbst halbdurchsichtig (rgba(...,0.14)), jede Mischung damit
   bliebe es auch - die Karte würde den Untergrund durchscheinen lassen und
   je nach Fläche darunter anders aussehen. Mit dem deckenden Akzent kommt in
   beiden Themen eine deckende Farbe heraus: hell rgb(239,244,248), dunkel
   rgb(24,36,48) - beides ein sanfter Zug ins Blaue gegenüber der ruhenden
   Karte, ohne den Text zu stören. */
.section-card,
.user-accordion details,
.sec-block,
.unbestaetigt {
    transition: background 0.2s ease, border-color 0.2s ease;
}
/* Gleiche Zeilenhöhe in allen drei Listen (seit 2026-08-06, gemeldet:
   "die geschlossenen Felder in Bereiche verwalten sind höher als die
   anderen"). 1.7rem ist die natürliche Höhe einer Kopfzeile mit
   Status-Pille - genau das Maß, das die Nutzerlisten von sich aus haben.
   Festgeschrieben, damit die Listen nicht wieder auseinanderlaufen, sobald
   in einer davon ein Bedienelement dazukommt: Alles, was in die Kopfzeile
   wandert, hat sich künftig nach dieser Höhe zu richten, statt sie zu
   dehnen. */
.section-card summary,
.user-accordion summary,
.sec-block > .sec-block-title,
.unbestaetigt > .sec-block-title { min-height: 1.7rem; }
.section-card:not([open]):hover,
.user-accordion details:not([open]):hover,
.sec-block:not([open]):hover,
.unbestaetigt:not([open]):hover {
    background: var(--accent-tint);
    border-color: var(--accent-color);
}
.section-card[open],
.user-accordion details[open],
.sec-block[open],
.unbestaetigt[open] {
    background: color-mix(in srgb, var(--accent) 7%, var(--paper-raised));
    border-color: color-mix(in srgb, var(--accent-color) 40%, var(--line));
}
@media (prefers-reduced-motion: reduce) {
    .section-card,
    .user-accordion details,
    .sec-block,
    .unbestaetigt { transition: none; }
}

.user-accordion { display: flex; flex-direction: column; gap: 0.6rem; }
.user-accordion details {
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    box-shadow: var(--shadow-tight);
    background: var(--paper-raised);
    /* Polsterung am <summary>, nicht hier - siehe .section-card oben. */
    padding: 0;
}
.user-accordion summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    /* Füllt die Karte vollständig aus - Begründung siehe .section-card. */
    padding: 0.9rem 1.1rem;
}
.user-accordion summary::-webkit-details-marker { display: none; }
.user-accordion summary .muted { color: var(--secondary-color); font-size: 0.88rem; }
.user-accordion summary .chevron { flex-shrink: 0; color: var(--secondary-color); font-size: 0.85em; transition: transform 0.2s ease; }
.user-accordion details[open] summary .chevron { transform: rotate(180deg); }
.user-accordion-body { margin: 0 1.1rem 0.9rem; padding-top: 1rem; border-top: 1px solid var(--line); }

/* Name/E-Mail/Rolle/2FA in festen Spalten statt frei fließendem Text
   (seit 2026-08-01, Nutzerwunsch: "die einzelnen Bereiche sollen
   übereinanderstehen") - feste px-Breiten für Rolle/2FA (kurzer, fast
   gleich langer Inhalt), die E-Mail-Spalte wächst mit dem verfügbaren
   Rest. Da jede Nutzer-Karte dieselbe Zeilenbreite hat, richten sich die
   Spalten über alle Karten hinweg wie in einer Tabelle aus. */
.user-summary-grid {
    display: grid;
    /* Rollen-Spalte auf 112px (seit 2026-08-01) - "VERWALTER" (dritte
       Rechtestufe) ist länger als "ADMIN"/"NUTZER" und wäre in den vorher
       84px sonst über die Spalte hinausgelaufen. */
    grid-template-columns: minmax(120px, 1fr) minmax(160px, 1.6fr) 112px 30px;
    align-items: center;
    gap: 0.3rem 1rem;
    flex: 1;
    min-width: 0;
    text-align: left;
}
.user-summary-name { font-size: 0.95rem; }
.user-summary-email { overflow-wrap: anywhere; }
.user-summary-role { display: flex; }
/* Schild immer sichtbar (auch ohne aktives 2FA), sonst würde die Spalte
   bei Nutzern ohne 2FA leer aussehen und die Ausrichtung wirkt zufällig
   statt bewusst gerastert. Grau = nicht eingerichtet, grün = aktiv -
   dieselbe Farbregel wie beim Sicherheits-Akkordeon auf konto.php. */
/* ---- Reminder: offene Entscheidungen/Merkposten (seit 2026-08-02) --------
   Jeder Punkt steht technisch in EINER Zeile (Nutzerwunsch), die Felder
   richten sich über feste Spalten wie eine Tabelle untereinander aus -
   dieselbe Rastersprache wie .user-summary-grid, damit die Admin-Oberfläche
   einheitlich bleibt. Datum/Art/Bereich sind feste Spalten (kurzer,
   gleichförmiger Inhalt), der eigentliche Text nimmt den Rest. */
.reminder-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.reminder-grid {
    display: grid;
    grid-template-columns: 58px 92px 148px 190px 1fr;
    align-items: baseline;
    gap: 0.3rem 1rem;
    text-align: left;
}
.reminder-grid--head {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-faint);
    padding: 0 0.9rem 0.35rem;
    border-bottom: 1px solid var(--line);
}
.reminder-item {
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
}
/* Feste Kennung je Eintrag (R-01, E-02 ...) - dient dazu, einen Punkt
   eindeutig benennen zu können, ohne ihn abzutippen. Bewusst dieselbe
   Darstellung in Reminder UND Empfehlungen. Nichtproportionale Schrift,
   damit die Kennungen in der Spalte exakt untereinander stehen und sich
   Ziffern nicht verschieben; user-select bewusst erlaubt (Kopieren ist
   genau der Zweck). */
.eintrag-id {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--accent-color);
    white-space: nowrap;
}
.reminder-date { font-size: 0.84rem; color: var(--ink-faint); }
.reminder-area { font-size: 0.88rem; font-weight: 700; color: var(--ink-soft); overflow-wrap: anywhere; }
.reminder-text { font-size: 0.92rem; line-height: 1.55; overflow-wrap: anywhere; }
.reminder-type .status-badge { white-space: nowrap; }
@media (max-width: 860px) {
    /* Nebeneinander bliebe zu wenig Platz zum Lesen - jedes Feld für sich,
       Reihenfolge bleibt Datum → Art → Bereich → Text. */
    .reminder-grid { grid-template-columns: 1fr; gap: 0.3rem; }
    .reminder-grid--head { display: none; }
}

.user-summary-2fa { display: flex; justify-content: center; }
/* Wappen in runder Fläche wie ein .status-badge (seit 2026-08-02,
   Nutzerwunsch): hellgrün wenn 2FA aktiv, hellrot wenn nicht. Bewusst
   exakt dieselben Farben und Mischverhältnisse wie
   .status-badge--active / --rejected - die Ampel soll im ganzen Backend
   dieselbe Sprache sprechen, statt hier eigene Grün-/Rottöne zu erfinden.
   Ersetzt die frühere Lösung (graues bzw. grünes Schild ohne Fläche), bei
   der "nicht eingerichtet" nur durch Blässe erkennbar war und dadurch
   leicht übersehen wurde. */
.tfa-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 100px;
    corner-shape: round;
    font-size: 0.78rem;
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
}
/* Der unsichtbare Zwilling .tfa-dot--platzhalter ist am 13.08.2026
   entfallen. Er hielt in "Bereiche zuordnen" den Platz eines 2FA-Schildes
   frei, damit beide Nutzerlisten gleich breite Raster hatten und beim
   Tabwechsel nichts seitlich sprang. Seit dort die Zuordnungs-Matrix steht,
   gibt es kein zweites Raster mehr, das sich angleichen muesste. */
.tfa-dot.is-active {
    background: color-mix(in srgb, var(--success) 14%, transparent);
    color: var(--success);
}

/* ---- Mobilansicht der Nutzerkarten (überarbeitet 2026-08-02) -----------
   Nutzerwunsch: "die Rechte-Pillen und 2FA noch mal mit dem Namen auf eine
   Reihe setzen, aber so dass es noch optisch rein passt" - und beide Tabs
   sollen dabei gleich aussehen.

   Vorher stand hier "alles untereinander" (eine Spalte). Das war zwar
   lesbar, verschenkte aber Höhe: Name, Adresse, Rolle und Schild belegten
   vier Zeilen je Karte, obwohl Rolle und Schild kaum Platz brauchen. Jetzt
   zwei Zeilen:

       Name .................... [Rolle] [2FA]
       adresse@beispiel.de

   Der Name bekommt den Rest der ersten Zeile (minmax(0,1fr) statt 1fr -
   ohne die 0 hätte er eine Mindestbreite nach seinem Inhalt und würde die
   Pillen bei langen Namen wieder über den Rand schieben). Die
   E-Mail-Adresse liegt darunter über die volle Breite, weil sie als
   Einzige tatsächlich lang werden kann.

   Umgesetzt über benannte Bereiche statt über die Reihenfolge im Markup:
   Die Felder stehen dort als Name, Adresse, Rolle, Schild - ein reines
   Spaltenraster würde die Adresse also zwangsläufig in die erste Zeile
   ziehen. Mit grid-template-areas bleibt das Markup unangetastet.       */
@media (max-width: 700px) {
    .user-summary-grid {
        grid-template-columns: minmax(0, 1fr) auto auto;
        grid-template-areas:
            "name rolle tfa"
            "mail mail  mail";
        gap: 0.15rem 0.5rem;
    }
    .user-summary-name  { grid-area: name; min-width: 0; overflow-wrap: anywhere; }
    .user-summary-email { grid-area: mail; }
    .user-summary-role  { grid-area: rolle; justify-content: flex-end; }
    .user-summary-2fa   { grid-area: tfa; justify-content: flex-end; }
    /* Pille etwas schmaler: "VERWALTER" ist das längste Wort und würde die
       erste Zeile sonst auf sehr schmalen Geräten dominieren. */
    .user-summary-role .status-badge { padding: 0.2rem 0.5rem; font-size: 0.66rem; }
}
@media (prefers-reduced-motion: reduce) {
    .section-tile-action, .user-accordion summary .chevron { transition: none; }
}

/* ---------- Kopfzeile KundenPORTAL (seit 2026-07-29) ----------
   .tool-header-right aus tools.css reserviert per padding-right:168px
   Platz für DREI absolut positionierte Icon-Buttons (KundenPORTAL +
   Sprache + Theme, siehe css/shared.css) - im KundenPORTAL gibt es
   aber nur den Theme-Toggle (kein Login-Button/Sprachumschalter, siehe
   Kopfkommentar _header.php). Ein fixer Wert (erst 78px probiert, seit
   2026-07-30 korrigiert) blieb selbst am unteren Rand des Bereichs
   861-1180px deutlich zu großzügig (live gemessen: 53-66px Lücke zum
   Theme-Toggle statt der angepeilten ~15-20px) UND wuchs auf breiten
   Bildschirmen unnötig weiter mit ("Zur Startseite" hing weit VOR der
   Content-Kante in der Luft statt sauber daran auszurichten - genau das
   vom Nutzer gemeldete Problem). Grund: .container (Klasse auf
   .tool-header-inner) hat selbst schon responsives Padding
   (clamp(20px,5vw,56px)), das jede fixe Reservierung hier oben drauf
   addiert - nicht mit eingerechnet gewesen. Jetzt per calc() dynamisch:
   40px reichen am unteren Rand (861px, live verifiziert), darüber
   schrumpft die Reservierung um genau den Betrag, um den der natürliche
   Container-Rand-Abstand zur echten Seitenkante wächst
   ((100vw-1180px)/2) - erreicht 0, sobald dieser Abstand allein schon
   ausreicht. portal.css lädt nach tools.css (siehe _header.php-Kopf),
   gewinnt daher bei gleicher Spezifität automatisch. Rein
   KundenPORTAL-spezifisch (Icon-Anzahl unterscheidet sich von Startseite/
   Tool-Seiten), daher hier und nicht im geteilten Mobilmenü-Bauteil. */
/* 136px, seit neben dem Theme-Umschalter ZWEI weitere Icon-Knöpfe stehen
   ("Abmelden" und "Zurück zu GRAVID", seit 2026-08-01): 40px Grundreserve
   + zweimal (38px Knopfbreite + 10px Lücke). Kommt ein weiterer dazu, hier
   um 48px erhöhen. */
.tool-header-right { padding-right: max(0px, 136px - max(0px, 100vw - 1180px) / 2); }

/* ---- Bereichsbezeichnung neben dem Logo (seit 2026-08-02) ---------------
   "KundenPORTAL"/"AdminPORTAL" als dezente Überschrift in der Kopfzeile,
   senkrecht mittig auf einer Linie mit dem Logo (Nutzerwunsch).

   Größe: das Logo ist 34px hoch, die Schrift bewusst kleiner (1.35rem
   ≈ 21,6px) - sie soll das Logo begleiten, nicht mit ihm konkurrieren.
   Zurückgenommen wird sie seit 2026-08-02 weniger über die Größe als über
   die Farbe (Nutzerwunsch "etwas größer, dafür heller"): --ink-faint mit
   --paper aufgehellt, damit sie trotz der Größe leise bleibt. Bewusst per
   color-mix statt eines festen Grautons - so stimmt das Ergebnis in
   Hell- UND Dunkelmodus.

   Die Haarlinie links macht aus Logo + Wort optisch EINE Einheit statt
   zweier zufällig nebeneinanderstehender Elemente. margin-right:auto
   schiebt die Navigation weiterhin an den rechten Rand (.tool-header-inner
   ist ein Flex-Container mit space-between).                              */
.portal-title {
    margin-left: 0.9rem;
    margin-right: auto;
    padding-left: 0.9rem;
    border-left: 1px solid var(--line);
    font-family: var(--font-family);
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1;
    /* Bis 09.08.2026 zusätzlich mit --paper aufgehellt (68 %). Gemessen
       ergab das 2,56:1 hell und 3,01:1 dunkel - unter den 4,5:1, und zwar
       für echten Text: "KundenPORTAL" ist keine Zierde, sondern sagt, wo man
       ist. 1,35rem bei Schriftstärke 600 zählt dabei NICHT als große Schrift
       (dafür bräuchte es 700), die 3:1-Ausnahme greift also nicht.

       --ink-faint pur ist weiterhin der leiseste Textton, den es gibt - die
       Bezeichnung bleibt zurückhaltend, ist aber lesbar: 4,51:1 hell,
       5,16:1 dunkel. */
    color: var(--ink-faint);
    white-space: nowrap;
}


/* Mobil wird der Platz knapp: links Logo, rechts Burger. Die Bezeichnung
   wird deshalb stufenweise kleiner, statt ausgeblendet zu werden - man soll
   auch auf dem Handy sehen, in welchem Bereich man ist.

   Am 2026-08-01 kurzzeitig auf durchgehend gleiche Schriftgröße umgestellt
   und auf Nutzerwunsch wieder zurückgenommen: bei 375px lagen Logo (134px)
   + Abstand + Bezeichnung (161px) zusammen 12px über dem bis zum
   Burger-Menü verfügbaren Platz, die Bezeichnung wäre also unter den Burger
   gelaufen. Die Alternative wäre ein kleineres Logo gewesen - der Nutzer
   hat sich bewusst für die kleinere Bezeichnung entschieden. */
@media (max-width: 940px) {
    .portal-title {
        margin-left: 0.6rem;
        padding-left: 0.6rem;
        font-size: 1.05rem;
    }
}
@media (max-width: 560px) {
    /* Ganz schmale Geräte: Haarlinie entfällt, damit die verbleibende
       Breite dem Wort selbst zugutekommt. */
    .portal-title {
        margin-left: 0.5rem;
        padding-left: 0;
        border-left: none;
        font-size: 0.9rem;
    }
}

/* Beide Knöpfe nutzen dasselbe Bauteil wie auf der Startseite (.user-toggle
   in css/shared.css), sitzen hier aber enger: den Sprachumschalter, der dort
   zwischen den Knöpfen liegt, gibt es im Portal nicht (Deutsch-only).
   Reihenfolge von links nach rechts: "Zurück zu GRAVID", "Abmelden",
   Hell-/Dunkel-Umschalter - Abmelden reiht sich also rechts an den
   Home-Knopf an (Nutzerwunsch 2026-08-01).
   78px = 30px Theme-Position + 38px Breite + 10px Lücke, 126px entsprechend
   eine Stufe weiter; auf Mobilgeräten mit 34px Knopfbreite 72px bzw. 114px. */
/* NUR oberhalb der Mobilmenü-Schwelle positionieren. Darunter wandern beide
   Knöpfe ins aufgeklappte Menü und werden dort zu vollbreiten Zeilen im
   normalen Fluss (position:relative, right:auto - siehe css/mobile-menu.css).
   Ohne diese Eingrenzung galt das "right" auch dort weiter: css/portal.css
   lädt NACH css/mobile-menu.css und gewinnt bei gleicher Spezifität, wodurch
   die Zeilen um über 90px nach links aus dem Bild geschoben wurden
   (am 2026-08-01 vom Nutzer gemeldet und nachgemessen). */
@media (min-width: 941px) {
    .portal-header .portal-icon-logout { right: 78px; }
    .portal-header .portal-icon-home { right: 126px; }
}

/* Abmelden behält seine Warnfarbe aus der früheren Textknopf-Fassung -
   Orange, bewusst nicht Rot: Rot ist im Backend für tatsächlich destruktive
   Aktionen reserviert, Abmelden soll nur zum genaueren Hinsehen anregen. */
.portal-header .portal-icon-logout { color: var(--warning); }
.portal-header .portal-icon-logout .tooltip-bubble { --tt-tone: var(--warning); }
/* Ring-Hervorhebung gilt nur für den Icon-Knopf auf dem Desktop - im
   Mobilmenü ist daraus eine Zeile ohne Ring geworden. */
@media (min-width: 941px) {
    /* --warning-text fürs SYMBOL, --warning für den Ring: Das reine
       --warning erreicht auf heller Fläche nur 1,97:1 - genau der Fall, für
       den es --warning-text gibt (siehe css/tokens.css). Jetzt 5,43:1 hell,
       im Dunkelmodus ist es derselbe Ton wie zuvor (11,46:1).

       Aufgefallen NICHT durch die Kontrastprüfung: Die misst den ruhenden
       Zustand, und dies hier ist ein Überfahr-Zustand. Gefunden wurde es
       beim Nachsehen, welche Regeln überhaupt eine Signalfarbe als Fläche
       setzen. */
    .portal-header .portal-icon-logout:hover { color: var(--warning-text); }
    .portal-header .portal-icon-logout:hover::before { background: var(--warning); }
}

/* Abstand ZWISCHEN den Menü-Buttons identisch zur Startseite (seit
   2026-08-01, Nutzerwunsch): dort trennt css/index.css zwei Ebenen -
   .nav-right (Abstand Menüblock <-> Icon-Buttons) mit 28px und .nav-links
   (Abstand der Menü-Buttons untereinander) mit 12px. Im KundenPORTAL ist
   .tool-header-right BEIDES in einem Element und erbte aus tools.css die
   28px, wodurch die Buttons hier deutlich weiter auseinander standen als
   auf der Startseite. Der Theme-Toggle ist absolut positioniert
   (right:30px, siehe css/shared.css) und liegt damit außerhalb des
   Flex-Flusses - die Lücke zu ihm regelt weiterhin das padding-right
   oben, nicht dieser gap. Im aufgeklappten Mobilmenü überschreibt
   css/mobile-menu.css das ohnehin mit gap:0 (Zeilen mit Trennlinien). */
.portal-header .tool-header-right { gap: 12px; }

/* Mobilmenü selbst (Burger, aufklappbares Panel, Zeilen-Optik) kommt seit
   2026-07-31 vollständig aus css/mobile-menu.css - identisches, zentral
   gepflegtes CI-Standard-Bauteil wie auf der Startseite (siehe dort und
   _intern/STANDARD-Grundlagen.md "Mobilmenü"). portal/_header.php gibt dafür den Klassen
   "nav-toggle"/"nav-links"/"nav-btn" zusätzlich zu den bestehenden
   "tool-header-right"/"tool-back" mit ins Markup.

   Einzige echte KundenPORTAL-Sondereinstellung, die im geteilten Bauteil
   keinen Sinn ergibt (dort gibt es keine Icon+Label-Kombination): tools.css
   blendet .tool-back-label global unter <=600px aus (dort genügt sonst das
   Icon) - im aufgeklappten Mobilmenü hier soll der Text aber IMMER sichtbar
   bleiben (seit 2026-07-30, Nutzerwunsch: "Textbeschriftungen hinter den
   Icons fielen noch"), sonst stünden nur nichtssagende Icons da. */
@media (max-width: 940px) {
    .portal-header .tool-header-right .tool-back-label { display: inline; }
}

/* Beschriftungen der Menü-Buttons brechen NIE um (seit 2026-08-01,
   Nutzerwunsch). "Mein Konto" ist der einzige zweiteilige Text und zerriss
   bei knapper Breite in zwei Zeilen - der Button wurde dadurch höher als
   seine Nachbarn, und die ganze Reihe geriet aus dem Lot. Lieber wird es
   eng, als dass eine Zeile umbricht; für den Fall, dass der Platz wirklich
   nicht reicht, ist die Umstellung auf reine Symboldarstellung mit
   Sprechblase vorgesehen (noch offen). */
.portal-header .tool-back { white-space: nowrap; }

/* "Admin" und "Abmelden" bekommen eine dezent abweichende Farbe (seit
   2026-08-01, Nutzerwunsch: "damit man diesen schneller sieht" /
   "nicht aus Versehen klicken") - bewusst auf .portal-header
   gescopet, NICHT als allgemeine .nav-btn-Variante, da .nav-btn als
   Klasse auch auf der Startseite genutzt wird (siehe _intern/STANDARD-Grundlagen.md
   "Mobilmenü") und dort keine Admin-/Abmelde-Buttons existieren, die das
   bräuchten. Beide Farbtöne entstehen per color-mix aus bestehenden
   CI-Tokens statt eines neuen, fest codierten Farbwerts:
   - Admin: Blau (--accent-color) + Rot (--danger) ergibt einen violetten
     Ton, der sich klar von "Mein Konto" (reines Blau) abhebt, ohne dass
     die Palette einen eigenen Lila-Token bräuchte.
   - Abmelden: --warning (Orange) direkt, wie vom Nutzer vorgeschlagen -
     bewusst NICHT --danger (Rot), das ist im Backend für tatsächlich
     destruktive Aktionen (Löschen) reserviert; Abmelden ist nicht
     destruktiv, soll nur zum genaueren Hinsehen anregen.

   **Abgeschwächt am 2026-08-01 (Nutzerwunsch):** Beide trugen zusätzlich zur
   Schriftfarbe eine getönte Kontur (45% Farbanteil) UND eine getönte Fläche
   (9%) - im Verbund mit "Mein Konto" und "Cockpit" wirkten sie dadurch wie
   hervorgehobene Sonderfälle statt wie Teil derselben Reihe. Kontur und
   Fläche entsprechen jetzt im Ruhezustand den übrigen Menü-Buttons
   (--line / --paper-raised aus .tool-back); unterschieden werden sie allein
   über Schrift- und Symbolfarbe. Erst beim Überfahren kommt die Tönung
   zurück - dort stört sie nicht, sondern bestätigt die Bedeutung. */
.portal-header .nav-btn--admin {
    --admin-accent: color-mix(in srgb, var(--accent-color) 60%, var(--danger) 40%);
    color: var(--admin-accent);
}
/* Hover-Tönung NUR auf dem Desktop: im aufgeklappten Mobilmenü ist der
   Knopf eine randlose Zeile, dort würde das border-color die untere
   Haarlinie violett einfärben. Die Zeilen dort haben ihre eigene,
   einheitliche Hover-Regel (siehe css/mobile-menu.css). */
@media (min-width: 941px) {
    .portal-header .nav-btn--admin:hover {
        border-color: color-mix(in srgb, var(--admin-accent) 55%, var(--line));
        background: color-mix(in srgb, var(--admin-accent) 10%, var(--paper-raised));
    }
}

/* ============================================================================
   Cockpit (seit 2026-08-02) - Security Briefing, Empfehlungen, Fun Facts
   ----------------------------------------------------------------------------
   Durchgehend dieselbe Rastersprache wie die übrigen Admin-Listen
   (.reminder-grid/.user-summary-grid): feste Spalten für kurze, gleichförmige
   Angaben, der Fließtext bekommt den Rest. Unter 860px bricht alles auf eine
   Spalte um - nebeneinander bliebe zu wenig Platz zum Lesen.
   ============================================================================ */

/* ---- Schlagwortwolke über dem Security Briefing (seit 2026-08-06) ------
   Nutzerwunsch: "oben eine Art Tag-Cloud mit allen wichtigen Begriffen".

   Baut bewusst auf .user-filter-btn auf statt auf einer eigenen Pille: Es
   ist derselbe Handgriff wie die Rollenfilter nebenan (anklicken, filtert
   die Liste, erneut anklicken hebt auf), also soll es auch gleich aussehen.
   Hier kommt nur die Schriftgröße dazu.

   ALLE Schlagworte gleich groß (Nutzervorgabe 2026-08-06: "richte dich nach
   dem Standard, es soll gut lesbar sein"). Sie erben damit die 0.8rem von
   .user-filter-btn wie jeder andere Filterknopf im Backend. Zuvor stand hier
   eine Staffelung nach Häufigkeit in vier Stufen - der kleinste Wert lag bei
   0.74rem, und ausgerechnet die seltenen Begriffe, nach denen man am ehesten
   sucht, waren damit am schlechtesten zu lesen.

   Wie oft ein Begriff vorkommt, sagt weiterhin die Zahl dahinter - nur eben
   als Angabe zum Nachlesen statt als Schriftgröße zum Schätzen. */
/* Abstand zwischen den Rubriken wie zwischen den Karten der Admin-Listen
   (.user-accordion) - der Behälter setzt ihn, nicht die einzelne Rubrik. */
#secList { display: flex; flex-direction: column; gap: 0.6rem; }

/* Werkzeugzeile: die Suche darf den Platz neben dem Knopf ausfüllen. */
.sec-toolbar { flex-wrap: nowrap; }
.sec-toolbar .sec-suche { flex: 1 1 auto; min-width: 0; }

.sec-wolke {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: 0.2rem 0 0.9rem;
}
/* Die Zahl etwas größer und in der Akzentfarbe (Nutzervorgabe 2026-08-06:
   "die Zahlen müssten noch etwas größer, heb sie farblich ein wenig ab").

   0.72rem absolut statt em-Anteil vom Knopf: Sie hat mit dem Begriff davor
   nichts zu tun und soll bei einer künftigen Änderung der Knopfschrift nicht
   unbemerkt mitwandern. 11,5px sind für zweistellige Zahlen bequem lesbar.

   --accent-color statt eines gedämpften Grautons: Sie ist mit 8:1 auf heller
   Fläche die kontraststärkste Farbe der Palette (siehe css/tokens.css) - das
   Abheben geht hier also NICHT auf Kosten der Lesbarkeit, wie es ein
   helleres Grau getan hätte. */
.sec-tag-zahl {
    margin-left: 0.4rem;
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
    color: var(--accent-color);
}
/* Im gewählten Zustand färbt .user-filter-btn.is-active den ganzen Knopf in
   die Akzentfarbe - dort hebt sich die Zahl nicht mehr durch Farbe ab,
   sondern durch etwas weniger Deckkraft. Ohne das stünde sie farbgleich im
   Text und wäre als Angabe nicht mehr zu erkennen. */
.sec-tag.is-active .sec-tag-zahl { color: inherit; opacity: 0.7; }

/* Das Suchfeld darf hier die volle Breite nehmen: Gesucht wird in
   Fließtext, nicht in Namen - da hilft jedes zusätzliche sichtbare Zeichen. */
.sec-suche { width: 100%; }
.sec-suche .tool-input { width: 100%; min-width: 0; }

/* Abschnittsüberschrift innerhalb eines Panels - zurückhaltender als eine
   Seitenüberschrift, aber klar gliedernd. */
/* ---- Rubriken des Briefings als Aufklapper (seit 2026-08-08) ----------
   Vorher <section> mit <h3>, jetzt <details> mit <summary>.

   Das Aussehen kommt seit 2026-08-08 aus DENSELBEN Regeln wie die
   Admin-Listen (Nutzerwunsch: "gestalte die zugeklappten Bereiche optisch
   genauso wie bei Bereiche zuordnen, dann ist es einheitlich") - Rahmen,
   Rundung, Schatten, Zeiger- und Offen-Zustand stehen weiter oben bei
   .section-card/.user-accordion, dort ist .sec-block einfach in die
   Selektorlisten aufgenommen. Eine eigene Fassung hier wäre genau die
   Doppelpflege, vor der der Kommentar dort schon warnt.

   Hier bleibt nur, was diese Liste eigen hat: die Zahl je Rubrik. */
.sec-block,
.unbestaetigt {
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    corner-shape: round;
    box-shadow: var(--shadow-tight);
    background: var(--paper-raised);
    /* Polsterung sitzt am <summary>, damit die ganze Zeile klickbar ist -
       Begründung wie bei .section-card. */
    padding: 0;
}
.sec-block-title {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.9rem 1.1rem;
    cursor: pointer;
    list-style: none;
    font-size: 1rem;
    font-weight: 700;
    color: var(--ink-soft);
    letter-spacing: 0.01em;
}
.sec-block-title::-webkit-details-marker { display: none; }
.sec-block-name { flex: 1 1 auto; min-width: 0; }

/* Die Zahl trägt beim Filtern "3 von 9" statt nur "9" - deshalb keine feste
   Breite und kein Kreis, sondern eine mitwachsende Pille. */
.sec-block-zahl {
    flex: 0 0 auto;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--ink) 7%, transparent);
    color: var(--secondary-color);
    font-size: 0.78rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.sec-block-title .chevron {
    flex-shrink: 0;
    color: var(--secondary-color);
    font-size: 0.85em;
    transition: transform 0.2s ease;
}
.sec-block[open] > .sec-block-title .chevron,
.unbestaetigt[open] > .sec-block-title .chevron { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
    .sec-block-title .chevron { transition: none; }
}

/* Der Inhalt einer geöffneten Rubrik - abgesetzt wie .user-accordion-body:
   dieselben Ränder, dieselbe Trennlinie unter der Kopfzeile. */
.sec-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin: 0 1.1rem 0.9rem;
    padding-top: 1rem;
    border-top: 1px solid var(--line);
}

.sec-item {
    display: grid;
    grid-template-columns: 148px 1fr;
    align-items: start;
    gap: 0.3rem 1rem;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
}
.sec-item-status .status-badge { white-space: nowrap; }
.sec-item-body { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.sec-item-name { font-size: 0.95rem; font-weight: 700; }
.sec-item-text { font-size: 0.9rem; line-height: 1.55; color: var(--ink-soft); overflow-wrap: anywhere; }
.sec-item-quelle {
    font-size: 0.78rem;
    color: var(--ink-faint);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    overflow-wrap: anywhere;
}
.sec-item-quelle i { margin-right: 0.3rem; }

/* Empfehlungen: wie .reminder-grid, aber mit zusätzlicher Aufwand-Spalte. */
.empf-grid {
    display: grid;
    grid-template-columns: 58px 92px 150px 92px 1fr;
    align-items: start;
    gap: 0.3rem 1rem;
    text-align: left;
}
.empf-grid--head {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-faint);
    padding: 0 0.9rem 0.35rem;
    border-bottom: 1px solid var(--line);
}
.empf-body { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.empf-titel { font-size: 0.95rem; font-weight: 700; }
.empf-nutzen { font-size: 0.84rem; color: var(--success); }
.empf-nutzen i { margin-right: 0.3rem; }
.empf-aufwand .status-badge { text-transform: capitalize; }

/* Uhrzeit unter dem Datum (Nutzerwunsch) - kleiner und blasser, damit das
   Datum die Zeile führt. Gilt für Reminder UND Empfehlungen. */
.reminder-time {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.75rem;
    color: var(--ink-faint);
    font-weight: 400;
}

/* Kennzahlen als Kachelraster - die Zahl führt, Erläuterung darunter. */
.fakt-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 0.7rem;
}
.fakt-karte {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
}
.fakt-wert { font-size: 1.45rem; font-weight: 800; color: var(--accent-color); line-height: 1.1; }
.fakt-titel { font-size: 0.9rem; font-weight: 700; }
.fakt-hinweis { font-size: 0.8rem; color: var(--ink-faint); line-height: 1.5; }

/* Zeitleiste: senkrechte Linie mit Punkten - macht die Abfolge auf einen
   Blick lesbar, ohne dass man Daten vergleichen muss. */
.timeline { list-style: none; margin: 0; padding: 0 0 0 1.35rem; position: relative; }
.timeline::before {
    content: "";
    position: absolute;
    left: 5px; top: 0.4rem; bottom: 0.4rem;
    width: 2px;
    background: var(--line);
}
.timeline-punkt { position: relative; display: grid; grid-template-columns: 92px 1fr; gap: 0.3rem 1rem; padding: 0.5rem 0; }
.timeline-punkt::before {
    content: "";
    position: absolute;
    left: -1.35rem; top: 0.95rem;
    width: 12px; height: 12px;
    border-radius: 50%;
    background: var(--paper);
    border: 2px solid var(--accent-color);
}
.timeline-datum { font-size: 0.84rem; color: var(--ink-faint); white-space: nowrap; }
.timeline-body { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.timeline-titel { font-size: 0.95rem; font-weight: 700; }
.timeline-text { font-size: 0.88rem; line-height: 1.55; color: var(--ink-soft); }

/* Aufwand/Kosten: Wert groß, Herleitung klein darunter - die Herleitung ist
   hier genauso wichtig wie die Zahl selbst. */
/* Zwei Felder je Zeile (Nutzerwunsch 2026-08-01) - macht den Abschnitt
   spürbar kompakter. Summen und Einordnungen laufen über die volle Breite,
   weil neben ihnen keine Detailangabe stehen sollte. */
.aufwand-gruppe {
    margin: 1.4rem 0 0.6rem;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-faint);
}
.aufwand-gruppe:first-of-type { margin-top: 0.8rem; }
.aufwand-liste {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    /* Bewusst KEIN align-items:start (seit 2026-08-01, Nutzerwunsch): mit dem
       Standardwert "stretch" ziehen sich beide Felder einer Zeile auf
       dieselbe Höhe, statt je nach Textlänge unterschiedlich hoch
       auszufallen. Das beruhigt das Bild deutlich. */
}
.aufwand-zeile--breit { grid-column: 1 / -1; }
.aufwand-zeile {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    /* Mindesthöhe, damit auch kurze Einträge nicht deutlich flacher
       ausfallen als ihre Nachbarn - die Zeilen wirken dadurch über den
       ganzen Abschnitt hinweg gleichmäßig. Der Hinweistext schiebt die
       Karte bei Bedarf weiter auf. */
    min-height: 10.5rem;
    padding: 1rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
}
/* Volle-Breite-Karten (Summe, Einordnung) brauchen die Mindesthöhe nicht -
   sie stehen allein in ihrer Zeile, da gibt es nichts anzugleichen. */
.aufwand-zeile--breit { min-height: 0; }
.aufwand-kopf { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.aufwand-titel { font-size: 0.95rem; font-weight: 700; }
.aufwand-wert { font-size: 1.25rem; font-weight: 800; color: var(--accent-color); }
.aufwand-wert--offen { color: var(--ink-faint); font-size: 1rem; font-style: italic; font-weight: 600; }
/* Gleiche Schriftgröße wie der Zeitleisten-Text (Nutzerwunsch: war zu
   klein zum bequemen Lesen). */
.aufwand-hinweis { font-size: 0.88rem; line-height: 1.55; color: var(--ink-soft); }

/* Vergleichslisten (Token-Legende, Größenordnungen). */
.vergleich-liste { display: flex; flex-direction: column; gap: 0.4rem; }
.vergleich-zeile {
    display: grid;
    grid-template-columns: 190px 200px 1fr;
    align-items: baseline;
    gap: 0.3rem 1rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--line);
    border-radius: var(--squircle-sm);
    background: var(--paper-raised);
}
/* Die eigene Zeile deutlich hervorheben (Nutzerwunsch 2026-08-01) - vorher
   nur ein farbiger Rahmen, der im Fluss der Liste kaum auffiel. Jetzt
   zusätzlich getönte Fläche, kräftigere Kontur und ein Kennzeichen über der
   Bezeichnung. Bewusst in BEIDEN Vergleichslisten identisch (Token-Legende
   und Größenordnungen), damit man das eigene Projekt überall gleich
   wiedererkennt. */
.vergleich-zeile--eigen {
    border-color: color-mix(in srgb, var(--accent-color) 55%, var(--line));
    background: color-mix(in srgb, var(--accent-color) 8%, var(--paper-raised));
    box-shadow: inset 3px 0 0 var(--accent-color);
}
.vergleich-zeile--eigen .vergleich-menge { color: var(--accent-color); }
.vergleich-tag {
    display: block;
    margin-bottom: 0.25rem;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent-color);
}
.vergleich-tag i { margin-right: 0.25rem; }
.vergleich-menge { font-size: 0.92rem; font-weight: 700; }
.vergleich-mitte { font-size: 0.88rem; color: var(--ink-soft); }
.vergleich-bild { font-size: 0.88rem; line-height: 1.55; color: var(--ink-soft); }

@media (max-width: 860px) {
    .sec-item,
    .empf-grid,
    .timeline-punkt,
    .vergleich-zeile { grid-template-columns: 1fr; gap: 0.35rem; }
    .empf-grid--head { display: none; }
    .fakt-grid { grid-template-columns: 1fr 1fr; }
    .aufwand-liste { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
    .fakt-grid { grid-template-columns: 1fr; }
}

/* ============================================================================
   Info-Pille und Leermeldung (seit 2026-08-02, Nutzerwunsch)
   ----------------------------------------------------------------------------
   Ausgangslage: Jeder Hinweistext stand ausgeschrieben über seiner Liste, in
   einer gelb getönten Fläche. Für den ersten Besuch richtig - im Adminbereich
   sieht man dieselbe Erklärung aber jeden Tag wieder, und ab dem dritten Mal
   ist sie nur noch Vorspann, durch den man hindurchscrollt.

   Nutzerwunsch: "der Text soll nicht dargestellt werden, sondern in der
   Infopille verschwinden. Nur wenn ich diese anklicke, zeigt er mir die Info."

   ---- Zwei Sorten, die vorher gleich aussahen ----
   Die Trennung ist der eigentliche Gewinn:

     ERKLÄRUNG  ("Hier bestimmen Sie, wer welchen Bereich sieht.")
                → .info-pille. Zusammengeklappt, gelb wie bisher. Wer sie
                  braucht, klickt; wer sie kennt, sieht die Liste sofort.

     LEERMELDUNG ("Es wurde noch kein Bereich angelegt.")
                → .field-hint--leer. Bleibt IMMER sichtbar und wird neutral
                  grau dargestellt. Sie erklärt nichts, sondern beschreibt
                  einen Zustand - hinter einen Klick gehört sie schon
                  deshalb nicht, weil sie sonst niemand fände: Sie steht ja
                  gerade dort, wo sonst der Inhalt wäre.

   Warum <details> und nicht ein eigenes Aufklapp-Skript: Akkordeons sind im
   Backend verbindlich als <details> umgesetzt (siehe STANDARD-Portal.md).
   Damit bekommt die Pille die Slide-Animation, die Tastaturbedienung und das
   Verhalten ohne JavaScript geschenkt.
   ============================================================================ */

/* Der Rahmen ist ein Block, damit sich der Text darunter über die volle
   Breite entfalten kann - nur die Pille selbst ist inline. */
.info-pille { margin: 1.2rem 0; }
.info-pille:first-child { margin-top: 0; }

.info-pille > summary {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    cursor: pointer;
    /* Eigener Marker unterdrückt - das Dreieck des Browsers säße neben dem
       "i" und behauptete ein zweites Bedienelement. */
    list-style: none;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    corner-shape: round;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1;
    color: var(--warning-text);
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
    transition: background 0.15s ease, border-color 0.15s ease;
}
.info-pille > summary::-webkit-details-marker { display: none; }
.info-pille > summary:hover {
    background: color-mix(in srgb, var(--warning) 22%, transparent);
    border-color: var(--warning);
}
.info-pille > summary:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
/* ---- Geöffnet: tiefer getönt statt Vollton (korrigiert 2026-08-02) -----
   Vorher war der offene Zustand eine VOLL eingefärbte Fläche mit fast
   schwarzer Schrift. Zwei Dinge stimmten daran nicht:

   1. Das Symbol verschwand. Die Regel ".fa-circle-info { color: var(--warning) }"
      weiter oben färbt JEDES Info-Symbol amber - auch das auf der amberfarbenen
      Fläche. Amber auf Amber. Behoben unten, indem das Symbol in der Pille
      die Schriftfarbe erbt statt sie vorgeschrieben zu bekommen.

   2. Der Sprung war zu laut - vom Nutzer gemeldet. Und er passte nicht zur
      Sprache dieses Backends: Getönte Flächen stehen hier für Zustände
      (.user-filter-btn.is-active mit 12 %, .btn-sm--vorstufe, die
      Statuspillen), Volltonflächen sind den echten Schaltflächen
      vorbehalten (Speichern). Ein Info-Schalter, der lauter auftritt als
      "Speichern", stellt die Rangfolge auf den Kopf.

   Jetzt bleibt alles in derselben Familie: gleiche Schriftfarbe, gleiches
   Symbol, nur die Fläche wird von 12 % auf 22 % dichter und der Rahmen
   voll. Denselben Schritt macht schon .btn-sm--vorstufe beim Überfahren.

   Den Zustand trägt zusätzlich der Pfeil unten - der ist eindeutig, ohne
   dass die Farbe dafür schreien muss. */
.info-pille[open] > summary {
    background: color-mix(in srgb, var(--warning) 22%, transparent);
    border-color: var(--warning);
}

/* Symbol erbt die Schriftfarbe der Pille. Ohne diese Zeile greift die
   globale .fa-circle-info-Regel und macht es auf der getönten Fläche
   unsichtbar - siehe oben. */
.info-pille > summary .fa-circle-info { color: inherit; }

/* Pfeil als eigentliches Zustandszeichen: dreht sich beim Aufklappen.
   Über ::after statt als Markup, weil die Pille an 13 Stellen steht - ein
   zusätzliches Element hätte man an jeder einzelnen nachtragen müssen und
   an der vierzehnten vergessen. Dieselbe Geste wie der .chevron an den
   Nutzerkarten, damit "aufklappbar" im Backend überall gleich aussieht. */
.info-pille > summary::after {
    content: "\f078";                 /* fa-chevron-down */
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    font-size: 0.62em;
    line-height: 1;
    opacity: 0.75;
    transition: transform 0.2s ease;
}
.info-pille[open] > summary::after { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
    .info-pille > summary::after { transition: none; }
}

/* Der eigentliche Text - dieselbe getönte Fläche wie bisher ein Hinweis,
   aber ohne eigenes Symbol: Das "i" sitzt schon in der Pille darüber. */
.info-pille .info-pille-text {
    margin: 0.6rem 0 0;
    padding: 0.7rem 0.95rem;
    border-radius: var(--squircle-sm);
    corner-shape: round;
    background: color-mix(in srgb, var(--warning) 9%, transparent);
    font-size: var(--backend-text);
    line-height: 1.6;
}
:root[data-theme="dark"] .info-pille .info-pille-text {
    background: color-mix(in srgb, var(--warning) 14%, transparent);
}
/* Wie bei den Hinweisen: keine Fettung innerhalb der getönten Fläche -
   Fläche und <strong> sagen dasselbe. */
.info-pille .info-pille-text strong,
.info-pille .info-pille-text b { font-weight: inherit; }

/* ---- Leermeldung: sichtbar, aber neutral -------------------------------
   Bewusst KEIN Gelb: Gelb heißt in diesem Backend "hier steht eine
   Erklärung". "Es ist noch nichts da" ist keine Erklärung, sondern ein
   Zustand - und einer, an dem nichts zu tun ist. Grau gemischt aus --ink,
   dieselbe Tönungssprache wie die Kopfzeile der Login-Tabelle. */
p.field-hint--leer {
    position: relative;
    padding: 0.7rem 0.95rem 0.7rem 2.45rem;
    border-radius: var(--squircle-sm);
    corner-shape: round;
    background: color-mix(in srgb, var(--ink) 5%, transparent);
    color: var(--secondary-color);
}
p.field-hint--leer::before {
    content: "\f15c";              /* fa-file-lines - "hier ist noch nichts" */
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    font-size: 0.95em;
    line-height: inherit;
    position: absolute;
    left: 0.95rem;
    top: 0.7rem;
    color: var(--ink-faint);
}

/* ---- Hinweis INNERHALB einer geöffneten Karte (seit 2026-08-02) --------
   Abgrenzung zur .info-pille, und die ist der ganze Punkt:

     .info-pille      steht ÜBER einer Liste und erklärt den Bereich. Man
                      sieht sie im Adminalltag täglich wieder, deshalb ist
                      sie zugeklappt.
     .karten-hinweis  steht INNERHALB einer Karte, die man gerade eigens
                      aufgeklappt hat. Wer sie geöffnet hat, hat bereits
                      gesagt, dass er Einzelheiten sehen will - ihn dort
                      erneut klicken zu lassen, wäre ein Klick zu viel.

   Deshalb hier kein Aufklappen und keine getönte Fläche, sondern ein
   ruhiger Vermerk auf der Kartenfläche; das gelbe Info-Symbol davor stammt
   aus der globalen .fa-circle-info-Regel und stellt die Verbindung zur
   Pille her.

   Zusammengeführt am 2026-08-02 (Nutzerwunsch "angleichen"): Zuvor war der
   Vermerk unter "Bereiche zuordnen" eine Pille und unter
   "Nutzer-Verwaltung" ein Absatz mit Inline-Abstand - zwei Aussehen für
   dieselbe Sache. Der Abstand steckt jetzt in dieser Klasse statt in einem
   style-Attribut, damit er sich überhaupt zentral ändern lässt. */
.karten-hinweis {
    margin: 0 0 0.9rem;
    font-size: var(--backend-text);
    line-height: 1.55;
}
.karten-hinweis .fa-circle-info { margin-right: 0.15rem; }

/* ============================================================================
   Rollen-Pillen, gemeinsame Bauteilhöhe, Mobil-Umbrüche (seit 2026-08-02)
   ----------------------------------------------------------------------------
   Nutzerhinweis: "info, verwalter und rechte button admin haben fast die
   gleichen Farben." Stimmte - alle drei liefen über --warning:

     Info-Pille          --warning   "hier steht eine Erklärung"
     Verwalter-Pille     --warning   eine Rechteebene
     Admin-Häkchen       --warning   die weitreichendste Rechtevergabe

   Drei Bedeutungen, eine Farbe. Zusätzlich hat die Kontrastmessung einen
   echten Mangel aufgedeckt: --warning als SCHRIFT erreicht im Hellmodus nur
   1,8:1 gegen die eigene Tönung - WCAG 2.1 AA verlangt 4,5:1 für kleinen
   Text und ist in diesem Projekt verbindlich. Behoben über --warning-text
   (siehe css/tokens.css).

   ---- Gibt es dafür eine Norm? ----
   Für die BEDEUTUNG von Farbtönen: nein. Es existiert keine W3C-Vorgabe,
   die "Gelb = Hinweis" oder "Rot = gefährlich" festlegt. Verbindlich sind
   nur zwei Dinge, und beide sind hier eingehalten:
     WCAG 1.4.1  Farbe darf nicht das EINZIGE Unterscheidungsmerkmal sein.
                 Erfüllt: Jede Pille trägt ihr Wort ("Admin", "Verwalter").
     WCAG 1.4.3  Kontrast >= 4,5:1 für kleinen Text. Jetzt durchgehend
                 erfüllt, nachgerechnet für Hell UND Dunkel.
   Alles Weitere ist Konvention. Die hier gewählte:

     grau   Nutzer      Grundzustand, keine Sonderrechte
     blau   Verwalter   die Farbe für "ausgewählt/zugeteilt" im Backend
     rot    Admin       weitreichendste Rechte, hier ist Vorsicht geboten
     gelb   Info        bleibt der Erklärung vorbehalten - und nur ihr

   ---- Warum Rot für Admin, obwohl Rot bisher "zerstörerisch" hieß ----
   Die Regel wird damit auf "irreversibel ODER weitreichend" erweitert. Wer
   Adminrechte vergibt, verschenkt Zugriff auf alle Kundendaten und kann das
   nicht ohne Weiteres zurücknehmen, wenn der Empfänger sie inzwischen
   genutzt hat. Diese Nähe zum Löschen ist gewollt und keine Verwechslung.
   ============================================================================ */
.status-badge--rolle-nutzer {
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    color: var(--secondary-color);
}
.status-badge--rolle-verwalter {
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    color: var(--accent);
}
/* 10 % statt 16 %: Bei Rot fällt der Kontrast schneller: 16 % ergäbe 4,4:1
   und läge damit knapp unter der Schwelle. Nachgerechnet - 10 % ergibt
   4,8:1 im Hellmodus und 4,5:1 im Dunkelmodus. */
.status-badge--rolle-admin {
    background: color-mix(in srgb, var(--danger) 10%, transparent);
    color: var(--danger);
}

/* ---- Eine gemeinsame Höhe für alle Bedienelemente einer Zeile ----------
   Nutzervorgabe: "Filter-Buttons, die Rechte-Buttons sowie Speichern,
   Deaktivieren und Löschen sollen alle gleich hoch sein. Richte dich an
   die Rechte-Buttons."

   Also ist .section-grant das Maß, und die Höhe steht ab jetzt an EINER
   Stelle. Vorher trug .user-filter-btn eine eigene feste Höhe (34px),
   .btn-sm ergab sich aus seiner Polsterung und .section-grant aus einer
   dritten - drei Wege zu drei leicht verschiedenen Höhen, die im
   Nebeneinander sofort auffallen.

   min-height statt height: Bricht ein Label doch einmal um (schmales
   Gerät, langes Wort), wächst das Element mit, statt seinen Inhalt
   abzuschneiden. */
:root { --backend-bauteil-hoehe: 34px; }
.section-grant,
.user-filter-btn,
.btn-sm,
.section-list-toolbar .add-new-toggle > summary {
    min-height: var(--backend-bauteil-hoehe);
    box-sizing: border-box;
}
/* .section-grant bildete seine Höhe bisher aus der geerbten Zeilenhöhe
   (1,6) und landete dadurch bei 35px statt 34 - ein Pixel, das im
   Nebeneinander mit den Filterknöpfen als Versatz sichtbar wird. Mit
   line-height:1 ergibt sich die Höhe wie bei .btn-sm und .user-filter-btn
   allein aus der gemeinsamen Vorgabe oben, nicht mehr aus dem Zufall der
   Schriftmetrik. */
.section-grant { line-height: 1; }
/* Die feste Höhe der Filterzeile entfällt - sie kommt jetzt aus der
   gemeinsamen Regel darüber. Das Suchfeld bleibt eigens gesetzt, weil ein
   <input> seine Höhe anders bildet als ein Knopf. */
.user-toolbar .btn-sm,
.user-filter-btn { height: auto; }
.user-search .tool-input { height: var(--backend-bauteil-hoehe); }

/* ---- Rollenzeile darf umbrechen (seit 2026-08-02) ---------------------
   Eingeführt, als das Admin-Häkchen auf schmalen Geräten über den rechten
   Rand lief. Das Häkchen ist inzwischen entfallen (Adminvergabe entfernt),
   die Regel bleibt trotzdem: Ein starrer Flex-Container ohne Umbruch ist
   auch mit zwei Optionen eine Falle, sobald eine Beschriftung länger wird
   oder eine dritte Rolle dazukommt. */
.permission-role-choice { flex-wrap: wrap; }

@media (max-width: 700px) {
    /* ---- Aktionszeile: Speichern zuletzt und über die volle Breite ----
       Nutzervorgabe. Auf dem Handy ist der Daumen unten - der Knopf, den
       man am häufigsten braucht, gehört dorthin. Über "order" statt über
       eine andere Reihenfolge im Markup: In der Breitenansicht steht
       "Speichern" weiterhin links und abgesetzt von den roten Knöpfen
       (siehe .permission-actions oben), und das soll so bleiben.

       Volle Breite nur für Speichern. Deaktivieren und Löschen bleiben
       nebeneinander und schmaler - sie sollen NICHT die bequemste Fläche
       des Bildschirms bekommen. */
    .permission-actions {
        flex-direction: column;
        align-items: stretch;
        gap: 0.5rem;
    }
    .permission-actions-eingriff {
        order: 1;
        margin-left: 0;
        display: flex;
    }
    .permission-actions-eingriff > form { flex: 1; }
    .permission-actions-eingriff .btn-sm { width: 100%; min-width: 0; }
    .permission-save {
        order: 2;
        width: 100%;
    }
}

/* ---- Fußzeile im Portal: schmal, zweispaltig (seit 2026-08-02) ---------
   Nutzerwunsch: "ganz schmal gestalten, weniger Höhe, das Copyright links
   im Contentbereich ausrichten, Links dann auf der rechten Seite."

   Vorher: zwei gestapelte, mittig gesetzte Absätze in einer 40px hohen
   Polsterung - zusammen rund 130px für zwei Zeilen, die niemand liest. Im
   Adminbereich, wo man ohnehin nach unten scrollt, ist das verschenkter
   Platz.

   Jetzt eine Zeile: Copyright am linken Rand des Inhaltsbereichs, die
   rechtlichen Links am rechten. space-between statt fester Breiten - der
   .container gibt die Inhaltsbreite bereits vor, beide Enden sitzen damit
   genau auf der Kante des Inhalts darüber.

   Eigene Klasse, weil .footer aus css/shared.css auch die Tool-Seiten
   bedient (siehe portal/_footer.php). */
/* Nur noch Höhe und Abstand - Zeilenaufteilung, Haarlinie und Tönung kommen
   aus css/shared.css, gemeinsam mit den Tool-Seiten. */
/* Die Fußzeile des Portals steht seit 2026-08-08 in css/footer.css - sie
   ist dort die Vorgabe für Werkzeug- und Vorschauseiten gleich mit
   (Nutzervorgabe: "die Fußleiste auf den Portalseiten ist die optische
   Vorgabe für diesen Bereich"). */

/* ---- Unbestätigte Registrierungsanfragen (seit 2026-08-08) -------------
   Steht unter der eigentlichen Liste und ist zugeklappt. Absicht: Der Block
   soll da sein, aber nicht mitreden. Was oben steht, will bearbeitet werden;
   was hier steht, erledigt sich in 48 Stunden von selbst.

   Aussehen und Verhalten kommen aus DENSELBEN Regeln wie die Admin-Listen
   und die Briefing-Rubriken (Nutzerwunsch: "soll wieder so aussehen wie beim
   Security Briefing, mit Accordion, Hover etc.") - .unbestaetigt steht dort
   oben einfach mit in den Selektorlisten. Hier bleibt nur der Abstand nach
   oben, den diese eine Stelle braucht. */
.unbestaetigt { margin-top: 1.6rem; }
/* Die Zahl steht hier LINKS beim Namen, nicht rechts wie in den
   Briefing-Rubriken (Nutzerwunsch 2026-08-08: "die Anzahl der Anfragen kann
   ruhig links beim Blocknamen stehen, mit Abstand natürlich").

   Passt auch inhaltlich: Im Briefing beantwortet die Zahl "lohnt sich das
   Öffnen?" und gehört ans Ende der Zeile, wo der Blick beim Überfliegen der
   Rubriken hinfällt. Hier gehört sie zum Namen - "Unbestätigt 3" ist eine
   Angabe, nicht zwei.

   Der Abstand kommt aus dem gap der Zeile (1rem), die Zahl braucht also
   keinen eigenen. margin-right: auto schiebt alles Nachfolgende - also das
   Chevron - weiterhin an den rechten Rand. */
.unbestaetigt > .sec-block-title > .sec-block-name { flex: 0 0 auto; }
.unbestaetigt > .sec-block-title > .sec-block-zahl { margin-right: auto; }
/* Innenrand wie .user-accordion-body: Der Inhalt sitzt nicht an der Kante
   der Karte, und die Kopfzeile bekommt eine Trennlinie darunter. */
.unbestaetigt-inhalt {
    margin: 0 1.1rem 0.9rem;
    padding-top: 1rem;
    border-top: 1px solid var(--line);
}

/* ---- Countdown bis zur automatischen Löschung (seit 2026-08-08) --------
   tabular-nums, damit die Ziffern gleich breit sind: Ohne das sind "1" und
   "4" verschieden breit, und die Zahl zappelt bei jedem Tick.

   Das allein reicht aber NICHT (Nutzerhinweis: "gestalte die Spalte so, dass
   dadurch die anderen Spalten nicht zucken"). Ziffern gleich breit zu machen
   hilft nichts, wenn sich die Anzahl der WÖRTER ändert - von
   "noch 47 Std. 11 Min. 05 Sek." über "noch 1 Min. 05 Sek." zu "abgelaufen".
   Bei jedem dieser Sprünge würde die Spalte schmaler und alle Nachbarspalten
   rutschten mit.

   Deshalb reserviert das ::after die Breite der LÄNGSTEN Fassung. Es steht
   als Block unter dem Text, ist aber null hoch und unsichtbar - es nimmt
   also keinen Platz ein, bestimmt aber die Breite des inline-block. Kein
   fester Zahlenwert, der bei einer anderen Schrift oder Beschriftung
   danebensäße: Die Vorlage IST der längste Text.

   Wer das Format in frist_text() (portal/admin/index.php) ändert, ändert
   die Vorlage hier mit.

   visibility: hidden statt nur transparent - so wird die Vorlage auch nicht
   vorgelesen.

   Unter sechs Stunden warnfarbig - nicht als Alarm, sondern als Hinweis,
   dass eine Rückfrage jetzt keinen Sinn mehr hat: Wer die Zeile für einen
   Menschen aufheben will, muss vorher handeln. */
.frist {
    display: inline-block;
    font-variant-numeric: tabular-nums;
    color: var(--secondary-color);
    white-space: nowrap;
}
.frist::after {
    content: "noch 00 Std. 00 Min. 00 Sek.";
    display: block;
    height: 0;
    overflow: hidden;
    visibility: hidden;
    font-weight: 600;   /* die fette Fassung ist die breitere */
}
.frist--knapp { color: var(--warning-text); font-weight: 600; }

/* ============================================================================
   Zuordnungs-Matrix "Bereiche zuordnen" (seit 2026-08-13)
   ----------------------------------------------------------------------------
   Löst die Nutzer-Akkordeons ab, in denen je Karte die vollständige
   Bereichsliste als Häkchenreihe stand.

   ---- Was daran nicht aufging ----
   Die alte Ansicht beantwortete genau eine Frage: "Welche Bereiche hat dieser
   Nutzer?" Die Frage, die beim Anlegen eines Kundenbereichs tatsächlich
   entsteht, ist aber die umgekehrte - "Wer sieht diesen Bereich?" -, und dafür
   musste man jede Karte einzeln aufklappen. Zugeklappt sagte eine Karte nicht
   einmal, ob jemand null oder fünf Bereiche hat. Gespeichert wurde je Nutzer,
   ein Bereich an vier Leute waren also vier Formulare und vier Neuladungen.

   ---- Die Form ----
   Zeilen sind Nutzer, Spalten sind Bereiche, die Kreuzung ist der Schalter.
   Eine Zeile lesen heißt "was sieht dieser Nutzer", eine Spalte lesen heißt
   "wer sieht diesen Bereich". Beide Fragen an derselben Fläche, ohne einen
   einzigen Klick.

   ---- Warum keine Drag-and-drop-Fläche ----
   Naheliegend, aber falsch: Ziehen bedeutet "verschieben", hier ist es
   "verknüpfen" - ein Bereich gehört mehreren Nutzern gleichzeitig. Dazu wäre
   es mit der Tastatur nicht bedienbar (siehe Empfehlung E05), auf dem Tablet
   kollidiert die Geste mit dem Scrollen, und "diesen Bereich an vier Leute"
   wären vier Ziehbewegungen statt vier Klicks in einer Spalte.

   ---- Drei Größen, EIN Markup ----
   Die Tabelle steht genau einmal im HTML. Ab 720px abwärts lösen sich
   Tabellenzeilen und -zellen in Blöcke auf (display:block) und werden zu
   Karten mit Beschriftungs-Chips; der Bereichsname kommt dabei aus
   data-bereich am Schalter selbst. Bewusst KEINE zweite Fassung fürs Handy:
   Zwei Fassungen derselben Liste hätten dasselbe Schicksal ereilt wie
   Fußzeile und Kopfzeilen-Schalter - sie laufen auseinander, und man merkt
   es nicht, weil nie beide gleichzeitig sichtbar sind.
   ============================================================================ */

.zu-scroll { overflow-x: auto; }
.zu-matrix {
    /* min-width statt width: Die Tabelle fuellt den Bereich, waechst aber
       darueber hinaus, sobald die Bereichsspalten mehr Platz brauchen - dann
       greift das overflow-x der Huelle und man schiebt seitlich. Die
       Namensspalte bleibt dabei stehen (position: sticky weiter unten). */
    min-width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.85rem;
}
/* Die Fuellspalte ganz rechts nimmt den uebrigen Platz auf.
   Ohne sie verteilt die automatische Tabellenberechnung jeden freien Pixel
   auf die vorhandenen Spalten - bei zwei Bereichen waeren die Schalter dann
   ueber die halbe Seite auseinandergezogen, bei sechs eng beieinander. Mit
   ihr behalten Namens- und Bereichsspalten immer dieselbe Breite, und der
   Rest bleibt schlicht leer. */
.zu-matrix .zu-fueller {
    width: 100%;
    padding: 0;
    border: 0;
}
/* Der Browser gibt jeder Zelle von sich aus 1px Innenabstand - hier setzen
   die Bauteile ihren eigenen, deshalb erst einmal auf null.

   ACHTUNG, hier lag ein Fehler bis 2026-08-13: Diese Regel ist ZWEISTUFIG
   (.zu-matrix th), die Regeln der einzelnen Zellen darunter waren
   EINSTUFIG (.zu-name, .zu-kopf). Damit gewann die Null gegen jeden
   Abstand, den die Bauteile setzen wollten - die Namensspalte stand ohne
   einen Pixel Luft an der Blattkante, obwohl in ihrer Regel Werte standen.
   Vom Nutzer gemeldet ("gequetscht"), und beim Nachmessen kam raus: nicht
   zu wenig Abstand, sondern gar keiner. Deshalb tragen alle Zellenregeln
   unten jetzt .zu-matrix vor sich. */
.zu-matrix th, .zu-matrix td { padding: 0; }

/* ---- Kopfzeile: ein Bereich je Spalte ---- */
/* width UND min-width: Bei automatischem Tabellenlayout ist width nur ein
   Wunsch - reicht der Platz nicht, staucht der Browser die Spalten bis auf
   ihre Inhaltsbreite zusammen, statt die Tabelle breiter werden zu lassen.
   Nachgemessen mit zwoelf Bereichen auf 1280px: 48 bis 96px statt 118, und
   kein Querscrollbalken. Erst die Untergrenze zwingt die Tabelle, ueber die
   Huelle hinauszuwachsen - und genau dann greift deren overflow-x. */
.zu-matrix .zu-kopf {
    vertical-align: bottom;
    padding: 0 0 0.5rem;
    text-align: center;
    width: 118px;
    min-width: 118px;
}
.zu-kopf-inner { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 0 4px; }
.zu-kopf-name {
    font-weight: 700;
    color: var(--primary-color);
    font-size: 0.78rem;
    line-height: 1.25;
    hyphens: none;
}
.zu-kopf-zahl { font-size: 0.7rem; color: var(--ink-faint); font-weight: 600; }
/* Ein Bereich, den niemand sieht, ist fast immer ein Versehen - die
   Spiegelung des Sicherheitsfehlers vom 13.08.2026, wo ein Ordner OHNE
   Bereich offen stand. Beides sind stille Versehen, beide sollen auffallen. */
.zu-kopf-zahl.ist-null { color: var(--danger-text); }
.zu-kopf--oeffentlich .zu-kopf-zahl { color: var(--success-text); }

/* ---- Namensspalte: bleibt beim Querscrollen stehen ----
   Die Abstände waren bis 2026-08-13 zu knapp (Nutzerbefund: "gequetscht").
   Drei Zeilen - Name, Adresse, Rollenschild samt Anzahl - standen mit 0,55rem
   Luft nach oben und unten und mit GAR keiner nach links direkt an der
   Blattkante. Nebeneinander gestellt sah der Block dadurch enger aus als die
   Schalterspalten daneben, obwohl er dreimal so viel Inhalt trägt.

   1rem rundum ist kein geratener Wert: Es ist derselbe Abstand, den die
   Schalterspalten faktisch haben (30px Schalter in einer 118px breiten
   Spalte lassen links und rechts je rund 44px stehen). Der Namensblock zieht
   damit gleich, statt als einziger auf Kante zu sitzen.

   Der linke Abstand macht aus der ersten Spalte außerdem eine Fläche mit
   eigenem Rand - beim Querscrollen schiebt sich der Rest der Tabelle
   darunter, und eine Kante ohne Luft davor sähe nach abgeschnitten aus, nicht
   nach stehengeblieben. Dafür die Haarlinie rechts, siehe unten. */
/* Feste Breite, nicht nur eine Mindestbreite (seit 2026-08-21, Nutzerwunsch:
   "immer eine gleiche Breite auf der Desktopdarstellung"). Vorher stand hier
   min-width: Die Tabelle rechnet mit automatischem Layout, und ein langer
   Name oder eine lange Adresse zog die Spalte dann breiter - bei jedem
   Nutzerbestand anders. Drei Angaben, weil die Tabellenberechnung sonst
   trotzdem daran zieht: width als Wunsch, min-width als Untergrenze,
   max-width als Obergrenze. */
.zu-matrix .zu-name {
    text-align: left;
    padding: 0.95rem 1.1rem 0.95rem 1rem;
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--paper);
    width: 260px;
    min-width: 260px;
    max-width: 260px;
}
/* Trennlinie zur Schalterfläche: Ohne sie klebten beim Querscrollen die
   durchlaufenden Spalten unvermittelt am Namen. Bewusst nur hier und nicht
   zwischen allen Spalten - ein durchgezogenes Gitter machte aus der Übersicht
   eine Tabellenkalkulation. */
.zu-matrix .zu-name { border-right: 1px solid var(--line); }
/* Im Tabellenkopf sitzt die Zeile "6 Nutzer · 6 Bereiche" auf derselben
   Grundlinie wie die Bereichsnamen daneben - deshalb dort dieselbe untere
   Luft wie in .zu-kopf und nicht die großzügige der Datenzeilen. */
.zu-matrix thead .zu-name { vertical-align: bottom; padding-bottom: 0.5rem; }
/* Zeilenhöhe statt Standard: Die drei Zeilen im Block sind verschieden groß
   (0,88rem / 0,74rem / Schild), und mit der Vorgabe des Browsers standen sie
   unterschiedlich weit auseinander. Ausgeschrieben stehen sie gleichmäßig. */
.zu-name strong {
    display: block;
    font-size: 0.88rem;
    line-height: 1.35;
    color: var(--primary-color);
}
.zu-mail {
    display: block;
    font-size: 0.74rem;
    line-height: 1.45;
    color: var(--ink-faint);
    overflow-wrap: anywhere;
}
/* Rollenschild und Anzahl in einer eigenen Zeile unter der Adresse
   (Nutzerwunsch 2026-08-13: "die Anzeige, wieviele Bereiche ein User hat, in
   der nächsten Zeile"). Gilt auf ALLEN Größen, nicht nur auf dem Handy: Auch
   auf dem Desktop ist es die dritte Auskunft über dieselbe Person und gehört
   nicht in dieselbe Zeile wie die Adresse. */
.zu-meta { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.4rem; }
.zu-zahl { font-size: 0.72rem; color: var(--ink-faint); font-weight: 600; }
.zu-zahl.ist-null { color: var(--danger-text); }

/* Auch die Namenszelle: Sie ist ein <th scope="row">, nicht <td> -
   ohne sie endete die Trennlinie an der ersten Spalte. */
.zu-matrix tbody td,
.zu-matrix tbody .zu-name { border-top: 1px solid var(--line); }
.zu-matrix tbody tr[hidden] { display: none; }
.zu-matrix tbody tr:hover td { background: color-mix(in srgb, var(--accent) 5%, transparent); }
.zu-matrix tbody tr:hover .zu-name { background: color-mix(in srgb, var(--accent) 5%, var(--paper)); }

/* ---- Die Zelle IST der Schalter ---- */
/* Dieselbe Untergrenze auch an den Datenzellen: Eine Tabellenspalte ist so
   breit wie ihre breiteste Zelle - ohne diese Angabe koennte der Kopf 118px
   fordern und die Zellen darunter trotzdem schrumpfen. */
.zu-matrix .zu-zelle { text-align: center; min-width: 118px; }
.zu-schalter {
    width: 30px;
    height: 30px;
    border: 1px solid var(--line);
    background: var(--paper-raised);
    border-radius: var(--squircle-sm);
    corner-shape: round;
    cursor: pointer;
    /* Das Häkchen ist im Aus-Zustand da, aber unsichtbar: So springt beim
       Umschalten nichts, und der Knopf hat in beiden Zuständen dieselbe
       Grundfläche. */
    color: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    padding: 0;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.zu-schalter:hover {
    border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
    color: color-mix(in srgb, var(--accent) 35%, transparent);
}

/* ---- Der Wert steckt im Kästchen, die Fläche ist das Etikett ----
   Das <input> selbst wird weggeblendet, bleibt aber im Formular UND für die
   Tastatur erreichbar (clip statt display:none - Letzteres nähme ihm den
   Fokus). Dass die Färbung an :checked hängt und nicht an einer vom Skript
   gesetzten Klasse, ist Absicht: Ohne JavaScript bleibt die Matrix damit
   vollständig bedienbar - anhaken, absenden, fertig. Das Skript ergänzt nur
   Zähler, Änderungsring und Speicherleiste. */
.zu-box {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    margin: -1px;
    padding: 0;
    border: 0;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}
.zu-box:focus-visible + .zu-schalter { outline: 2px solid var(--accent); outline-offset: 2px; }
/* --success-solid, nicht --success: Auf der gefüllten Fläche steht ein weißes
   Häkchen, und weiße Schrift braucht eine Fläche, die sich nicht mit dem
   Thema dreht (siehe .btn-sm--approve weiter oben). */
.zu-box:checked + .zu-schalter {
    background: var(--success-solid);
    border-color: var(--success-solid);
    color: #fff;
}

/* Tabellen-Beschriftung nur für die Sprachausgabe: Wer die Matrix sieht,
   liest die Überschriften; wer sie vorgelesen bekommt, braucht den Satz
   davor, um Zeilen und Spalten überhaupt einordnen zu können. */
.zu-matrix caption {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    margin: -1px;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}
/* Noch nicht gespeichert - ein Ring in der Akzentfarbe, damit man beim
   Blick über die Tabelle sieht, was die Speicherleiste unten meint. */
.zu-schalter.ist-geaendert { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
/* Öffentliche Bereiche: gesetzt, aber nicht änderbar. Ein anklickbares
   Häkchen, das nichts bewirkt, wäre eine Behauptung - dieselbe Begründung
   wie beim Admin-Vermerk. */
.zu-schalter.ist-fest {
    background: color-mix(in srgb, var(--success) 16%, var(--paper-raised));
    border-color: color-mix(in srgb, var(--success) 30%, var(--line));
    color: var(--success-text);
    cursor: default;
}
/* ---- Anmerkung unter der Tabelle ----
   Bis 2026-08-13 stand hier .zu-ganze-zeile: der Adminvermerk als eigene
   Tabellenzeile, in der sonst nichts war. Er ist zur Fußnote geworden
   (Nutzerwunsch: Platz sparen), und damit ist auch die Regel eine andere -
   sie beschreibt keine Zelle mehr, sondern einen Satz. */
.zu-fussnote {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0.9rem 0 0;
    font-size: 0.8rem;
    line-height: 1.5;
    color: var(--ink-soft);
}
.zu-fussnote strong { color: var(--secondary-color); font-weight: 700; }
.zu-fussnote .fa-circle-info { margin-top: 0.2em; color: var(--ink-faint); }

/* ---- Hinweiszeile unter der Tabelle ---- */
/* [hidden] muss hier ausdruecklich stehen: Sobald eine Regel display setzt,
   verliert die Voreinstellung des Browsers gegen sie - der Hinweis staende
   sonst auch dann da, wenn es nichts zu melden gibt. Dieselbe Falle greift
   unten bei den Zeilen, die Suche und Filter ausblenden. */
.zu-hinweis-null[hidden] { display: none; }
.zu-hinweis-null {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    font-size: 0.82rem;
    color: var(--danger-text);
    margin: 0.9rem 0 0;
}

/* ---- Speicherleiste: eine für die ganze Tabelle ----
   z-index über dem Nach-oben-Knopf (der steht auf 1000, siehe
   css/bedienelemente.css). Gemeldet am 18.08.2026: Auf dem Telefon lag der
   runde Knopf auf der Leiste - er ist position:fixed bei bottom:30px/
   right:30px und damit mitten in einer Leiste, die am unteren Rand klebt
   und dort rund 96px hoch ist. Genau über "Verwerfen".

   Zwei Dinge waren nötig, eines allein hätte es nicht getan: Die Leiste
   muss davor liegen (hier), UND der Knopf muss ausweichen (dort). Nur der
   z-index hätte den Knopf auf dem Rechner halb verschluckt - dort ist die
   Leiste nur rund 50px hoch, der Knopf wäre zur Hälfte hinter ihr
   hervorgeschaut. Die Höhe trägt js/zuordnungs-matrix.js als
   --leiste-abstand ein, sobald die Leiste erscheint. */
.zu-leiste {
    position: sticky;
    bottom: 0;
    z-index: 1001;
    margin-top: 1rem;
    display: flex;
    align-items: center;
    gap: 0.8rem;
    flex-wrap: wrap;
    padding: 0.7rem 0.9rem;
    border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
    border-radius: var(--squircle-sm);
    background: color-mix(in srgb, var(--accent) 7%, var(--paper-raised));
}
.zu-leiste[hidden] { display: none; }
.zu-leiste-text { font-size: 0.84rem; font-weight: 600; color: var(--primary-color); }

/* ============================================================================
   Ab hier: Tabelle wird zur Karte (bis 940px)
   ----------------------------------------------------------------------------
   940px ist im Projekt bereits die Linie, ab der es schmal wird: Dort schaltet
   die Seitennavigation aufs Mobilmenü um und die Knöpfe gehen von 38px auf
   34px (siehe css/bedienelemente.css und _intern/STANDARD-Grundlagen.md). Die
   Matrix folgt derselben Linie, statt eine eigene einzuführen - eine zweite
   gemerkte Zahl wäre nur eine weitere Stelle, die man beim nächsten Umbau
   übersieht.

   Sie passt hier auch der Sache nach: Namensspalte (210px) und sechs
   Bereichsspalten (je 118px) brauchen rund 920px. Darunter müsste man quer
   scrollen, um überhaupt alle Bereiche zu sehen - und Querscrollen ist die
   Bewegung, die man auf einem Tablet am wenigsten erwartet.

   Ein Tablet quer (1024px) bleibt damit bei der Matrix, hochkant (768px oder
   834px) wechselt es auf die Karten. Genau richtig: Hochkant ist ein Tablet so
   breit wie ein großes Handy, und dort sind fingergroße Chips mit
   ausgeschriebenem Bereichsnamen die bessere Bedienung als sechs 30px-Kästchen
   hinter einem Scrollbalken.
   ============================================================================ */
@media (max-width: 940px) {
    .zu-scroll { overflow-x: visible; }
    .zu-matrix, .zu-matrix tbody, .zu-matrix tr, .zu-matrix td { display: block; width: auto; }
    .zu-matrix tbody tr[hidden] { display: none; }
    /* Die Spaltenüberschriften tragen auf dem Handy nichts mehr: Der
       Bereichsname steht jetzt auf dem Schalter selbst. */
    .zu-matrix thead { display: none; }
    /* Die Fuellspalte ebenfalls: In der Kartenansicht gibt es keine Spalten,
       die man auffuellen muesste - sie saesse sonst als leerer Chip in der
       Reihe. */
    .zu-matrix .zu-fueller { display: none; }

    .zu-matrix tbody tr {
        border: 1px solid var(--line);
        border-radius: var(--squircle-sm);
        corner-shape: round;
        background: var(--paper-raised);
        padding: 0.8rem 0.9rem;
        margin-bottom: 0.7rem;
    }
    .zu-matrix tbody tr:hover td,
    .zu-matrix tbody tr:hover .zu-name { background: none; }
    .zu-matrix tbody td,
    .zu-matrix tbody .zu-name { border-top: none; }

    /* Mit .zu-matrix davor, nicht nur .zu-name: Die Grundregel oben ist
       zweistufig, und eine Medienabfrage erhoeht die Spezifitaet nicht -
       die einstufige Fassung haette die Trennlinie in den Karten stehen
       lassen (beim Nachsehen aufgefallen). */
    .zu-matrix .zu-name { border-right: none; }
    .zu-matrix .zu-name {
        position: static;
        background: none;
        min-width: 0;
        /* Links und rechts KEINE eigene Luft: Die Karte bringt ihre
           0,9rem schon mit, sonst stünde der Name doppelt eingerückt. */
        padding: 0 0 0.7rem;
    }
    .zu-name strong { font-size: 0.95rem; }

    /* Die Schalter werden zu Chips mit Beschriftung und fließen um. Sie
       stehen als einzelne <td> nebeneinander - deshalb hier ein Umbruch über
       den Zeilen-Container statt über einen eigenen Wrapper im Markup. */
    .zu-matrix tbody tr {
        display: flex;
        flex-wrap: wrap;
        gap: 0.4rem;
    }
    .zu-name { flex: 1 0 100%; }
    /* Zweistufig, wie die Grundregel oben - eine Medienabfrage erhoeht die
       Spezifitaet nicht. Ohne das behielten die Chips ihre 118px Untergrenze
       und stuenden in der Karte unnoetig breit nebeneinander. */
    .zu-matrix .zu-zelle { min-width: 0; }
    .zu-zelle { flex: 0 1 auto; }

    .zu-schalter {
        width: auto;
        /* 40px: bequeme Fingergröße, siehe _intern/STANDARD-Grundlagen.md.
           Auf dem Desktop reichen 30px, dort zielt eine Maus. */
        min-height: 40px;
        gap: 0.45rem;
        padding: 0 0.8rem;
        font-size: 0.8rem;
        font-weight: 600;
        color: var(--secondary-color);
    }
    /* Der Bereichsname steht am Schalter als Datenattribut - eine Quelle,
       keine zweite Beschriftung im Markup, die auseinanderlaufen könnte. */
    .zu-schalter::after {
        content: attr(data-bereich);
        font-family: var(--font-body);
    }
    .zu-schalter .fa-check { opacity: 0.25; }
    .zu-box:checked + .zu-schalter .fa-check,
    .zu-schalter.ist-fest .fa-check { opacity: 1; }
    .zu-box:checked + .zu-schalter { color: #fff; }
    .zu-schalter.ist-fest { color: var(--success-text); }

    .zu-leiste { padding: 0.8rem; }
    .zu-leiste-text { flex: 1 0 100%; }
    .zu-leiste .btn-sm { flex: 1 1 auto; justify-content: center; }
}
