/* =========================================================
   TRcrewverwaltung – Design im TRgallery-Look
   Farben/Variablen/Font 1:1 von https://trgallery.net übernommen.
   Dunkel ist Standard (body.dark wird serverseitig gesetzt).
   ========================================================= */

/* Runde 140 (Crewler-Rückmeldung via Toby: die bisherige Zierschrift Nova Flat
   sei teils schwer lesbar, Buchstaben wie G/B sähen sich ähnlich, auch
   Vergrößern helfe nicht): neue App-Schrift ist "Atkinson Hyperlegible"
   (Braille Institute, SIL Open Font License, Lizenztext liegt unter
   assets/fonts) - speziell dafür entworfen, ähnliche Zeichen (G/B, I/l/1,
   O/0, a/e ...) eindeutig unterscheidbar zu machen. Selbst gehostet (keine
   externen Server). Dieselben Dateien werden zusätzlich unter dem Namen
   'Lato' eingebunden: Semantic UI setzt an gut zwei Dutzend Stellen Lato -
   dort wirkt jetzt automatisch ebenfalls Atkinson, statt dass die Seite wie
   bisher aus zwei verschiedenen Schriften gemischt war. Nova Flat bleibt
   als --font-brand definiert (nur zum bequemen Zurückschalten). */
@font-face {
    font-family: 'Atkinson Hyperlegible';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/atkinson-hyperlegible-latin-400-normal.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Atkinson Hyperlegible';
    font-style: italic;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/atkinson-hyperlegible-latin-400-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Atkinson Hyperlegible';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/atkinson-hyperlegible-latin-ext-400-normal.woff2') format('woff2');
    unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
    font-family: 'Atkinson Hyperlegible';
    font-style: normal;
    font-display: swap;
    font-weight: 700;
    src: url('../fonts/atkinson-hyperlegible-latin-700-normal.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Atkinson Hyperlegible';
    font-style: italic;
    font-display: swap;
    font-weight: 700;
    src: url('../fonts/atkinson-hyperlegible-latin-700-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Atkinson Hyperlegible';
    font-style: normal;
    font-display: swap;
    font-weight: 700;
    src: url('../fonts/atkinson-hyperlegible-latin-ext-700-normal.woff2') format('woff2');
    unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/atkinson-hyperlegible-latin-400-normal.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Lato';
    font-style: italic;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/atkinson-hyperlegible-latin-400-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/atkinson-hyperlegible-latin-ext-400-normal.woff2') format('woff2');
    unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-display: swap;
    font-weight: 700;
    src: url('../fonts/atkinson-hyperlegible-latin-700-normal.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Lato';
    font-style: italic;
    font-display: swap;
    font-weight: 700;
    src: url('../fonts/atkinson-hyperlegible-latin-700-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-display: swap;
    font-weight: 700;
    src: url('../fonts/atkinson-hyperlegible-latin-ext-700-normal.woff2') format('woff2');
    unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

@font-face {
    font-family: 'Nova Flat';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url('../fonts/nova-flat.woff2') format('woff2');
}

:root {
    --font-main: 'Atkinson Hyperlegible', 'Helvetica Neue', Arial, Helvetica, sans-serif;
    --font-brand: 'Nova Flat', sans-serif;
    --bg-color: #f2f2f2;
    --text-color: #000000;
    --accent-color: #00ACFF;
    /* Runde 68 (Toby: "im dunklen Design ist alles irgendwie schwer
       lesbar, blaue icons haben weiße schrift oder icons und der
       Kontrast ist irgendwie komisch für die Augen") - eigene Variable
       NUR für Flächen, auf denen weißer/heller Text oder ein weißes
       Icon liegt (Buttons, Badges, Icon-Kacheln usw.), getrennt von
       --accent-color (das weiterhin unverändert als Text-/Rahmen-/
       Linkfarbe dient, dort mit sehr gutem Kontrast). Grund: derselbe
       Farbwert funktioniert nicht für beide Einsatzzwecke gleich gut -
       als heller Text AUF dunklem Grund ist --accent-color hervorragend
       lesbar, als HINTERGRUND UNTER weißem Text/Icon ergibt v.a. das
       sehr helle Cyan des Dark-Mode-Akzents (#29d7ff) rechnerisch nur
       einen Kontrast von 1,7:1 zu Weiß - weit unter dem WCAG-AA-
       Minimum von 4,5:1 für Text bzw. 3:1 für UI-Komponenten/Icons.
       Im hellen Design bleibt --accent-solid bewusst IDENTISCH zu
       --accent-color (siehe unten) - dort ist der bisherige Wert nicht
       Gegenstand dieser Meldung, es soll sich optisch nichts ändern. */
    --accent-solid: #00ACFF;
    --box-bg: #eee;
    --menu-bg: #fff;
    --footer-bg: #eaeaea;
    --popup-bg: #222222;
    --popup-text: #ffffff;
    --stickyheader-bg: #ffffff;
    --stickyheader-font: #000000;
    --danger-color: #db2828;
    --success-color: #21ba45;
    --warning-color: #f2c037;
    --border-color: rgba(0, 0, 0, 0.12);
    --muted-text: #444;
}

body.dark {
    --bg-color: #17191c;
    --text-color: #f5f5f5;
    --accent-color: #29d7ff;
    /* Deutlich dunkler/gesättigter als --accent-color, aber derselbe
       Blauton (Hue ~191°) - erreicht 4,84:1 Kontrast zu Weiß (WCAG-AA-
       konform für Text UND Icons), siehe Docblock bei :root oben. */
    --accent-solid: #007c99;
    --box-bg: #262a2e;
    --menu-bg: #2c3034;
    --footer-bg: #2c3034;
    --popup-bg: #34383c;
    --popup-text: #ffffff;
    --stickyheader-bg: #2c3034;
    --stickyheader-font: #ffffff;
    --border-color: rgba(255, 255, 255, 0.22);
    --muted-text: #c7c9cc;
}

html, body {
    height: 100%;
}

/* Runde 109 (Toby: "Bei manchen, die ein kleines Smartphone haben, ist
   das Menü seitlich größer als der Browser und lässt sich nicht
   scrollen" + "manche Menüpunkte sind am Smartphone sporadisch nicht
   anklickbar"): auf den hier verfügbaren Testgeräten/-browsern ließ sich
   kein einzelner, hundertprozentig eindeutiger Auslöser reproduzieren -
   sehr wahrscheinlich ein gerätespezifisches Zusammenspiel aus kleiner
   effektiver Bildschirmbreite (kleines Display und/oder vom Nutzer
   vergrößerter Systemschriftgrad/Anzeigegröße, wodurch der tatsächlich
   nutzbare CSS-Viewport schmaler wird, als man vom physischen Gerät
   erwarten würde) und dem seitlichen Ausklapp-Menü (siehe #main-nav
   weiter unten). Da sich die genaue Bedingung nicht isoliert nachstellen
   ließ, hier als generelle, risikofreie Absicherung: HTML/Body dürfen nie
   seitlich scrollen (verhindert, dass IRGENDEIN Element auf IRGENDeiner
   Seite die Seite jemals breiter als den Bildschirm macht) - betrifft
   NICHT die bewusst seitlich scrollbaren Innenbereiche
   (.event-matrix-scroll/.stats-table-scroll weiter unten), da deren
   eigenes "overflow-x:auto" unabhängig vom hier gesetzten Wert auf
   html/body weiterhin funktioniert. */
html, body {
    overflow-x: hidden;
}

body {
    margin: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background-color: var(--bg-color);
    color: var(--text-color);
    font-family: var(--font-main);
    transition: background-color .2s ease, color .2s ease;
}

body, .ui.menu .item:not(.icon), .ui.header, .ui.dropdown .text, h1, h2, h3, h4, h5, .ui.button {
    font-family: var(--font-main) !important;
}

/* Eingabefelder (Freitext/Zahl/Passwort/Textarea) bekommen bewusst NICHT
   die Zierschrift Nova Flat, sondern eine normale, gut lesbare Schrift
   (Feedback Runde 22: "Inputfelder in den Systemeinstellungen sind zu
   groß und kleben aufeinander"). Ursache: Nova Flat ist eine breite,
   geometrische Displayschrift, die für Fließtext/Formulareingaben nicht
   gedacht ist - ohne diese Regel erben <input>/<textarea> die
   Nova-Flat-Deklaration von body (die generierten Dropdown-Widgets
   der Verschlüsselung/Sprache/Status-Auswahl sind bewusst NICHT
   ausgenommen, siehe .ui.dropdown .text oben - dort ist Nova Flat
   gewollter Teil des Look). Bei größeren Font-Größen wirken Nova Flats
   breitere Zeichen in einem normal bemessenen Eingabefeld optisch
   überfüllt/zu groß - deshalb hier auf die von Semantic UI für Formulare
   vorgesehene Schrift zurückgesetzt. */
.ui.form input:not([type=checkbox]):not([type=radio]),
.ui.form textarea,
.ui.input > input {
    font-family: var(--font-main) !important;
}

/* Runde 24 (Toby, fast wortgleich zu Runde 22: "Boxen im Profil sind zu
   groß und kleben aneinander"): exakt derselbe Bug wie bei den
   Eingabefeldern in Runde 22, nur an einer damals bewusst NICHT
   mitgeprüften Stelle - den einzelnen ausgewählten "Chips" (.ui.label)
   INNERHALB einer Mehrfachauswahl-Dropdown (z.B. "Positionen, die ich
   mag", Sprachen, "Positionen dieser Veranstaltung"). Diese Chips sind
   ein eigenes DOM-Element (.ui.label), NICHT der zuvor schon behandelte
   .ui.dropdown .text-Platzhalter, und erben deshalb weiterhin Nova Flat
   von body. Anders als bei einem einzelnen ausgewählten Wert (wo Nova
   Flat als Teil des Looks bewusst bleibt, siehe .ui.dropdown .text oben)
   zeigen diese Chips wie ein Eingabefeld echte, vom Nutzer ausgewählte
   Inhalte (Positions-/Sprachnamen) - gehören also zur selben Kategorie
   wie Formulareingaben. Nova Flats breitere Zeichen ließen die Chips UND
   dadurch die ganze Dropdown-Box unnötig groß wirken, mehrere knapp
   aufeinanderfolgende Boxen wirkten dadurch wie zusammengeklebt. */
.ui.dropdown .ui.label {
    font-family: var(--font-main) !important;
}

/* Runde 27 (Toby, dritte Meldung in Folge, diesmal in Großbuchstaben:
   "NOCH IMMER(!!!) aneinander klebend und sprengen die Box"): Runde 24
   (Chip-Schriftart, oben) und Runde 25 (max-width bei Mehrfachauswahl)
   haben das eigentliche Problem nie behoben - beide waren Symptome,
   nicht die Ursache, und trafen nur EINEN der drei diesmal gemeldeten
   Bereiche ("Positionen & Einschränkungen"), obwohl "Passwort ändern"
   (reine Textfelder, gar keine Dropdowns) und "Einstellungen" (nur
   Einfachauswahl, keine Chips) denselben Fehler zeigten. Echte Ursache
   diesmal mit Playwright + echtem Semantic-UI-CSS gefunden und vermessen:
   Browser implementieren <details> intern über Shadow-DOM - alle Kinder
   außer <summary> werden dabei in einen internen Slot "eingehängt". Für
   VERERBTE CSS-Eigenschaften (wie unser "box-sizing: inherit" im Reset
   ganz oben in dieser Datei) zählt dabei nicht das sichtbare
   Eltern-Element im Light-DOM, sondern dieser interne Shadow-Wrapper -
   und DER hat unser eigenes "box-sizing:border-box"-Reset nie
   abbekommen, sondern bleibt beim Browser-Standard "content-box". Jedes
   direkte Kind-Element eines <details> "erbt" dadurch fälschlich
   content-box, egal was im Light-DOM eigentlich sein Eltern-Element ist -
   und alles darunter (Formulare, Felder, Eingaben, Dropdowns) erbt das
   brav weiter. Bei content-box zählt eine Breite von 100% die eigenen
   Innenabstände/Ränder NICHT mit - das Element wird dadurch breiter als
   der eigentlich verfügbare Platz und sprengt die Nachbarspalte in einer
   "two fields"-Zeile (exakt Tobys Wortwahl: "sprengen die Box"). Das ist
   derselbe Effekt, der in Runde 11 (.event-custom-slot) und Runde 19
   (.settings-section-content) je einzeln nur an EINEM Dropdown-Selektor
   gefixt wurde, ohne die eigentliche, allgemeine Ursache zu erkennen -
   deshalb kam der Bug jetzt ein drittes Mal wieder, an neuen Stellen.
   Echter, allgemeiner Fix: Der direkte Light-DOM-Container INNERHALB
   eines <details>-Elements bekommt sein eigenes explizites
   "box-sizing:border-box" (statt "inherit") - das repariert die
   Vererbungskette genau an der Stelle, an der sie umspringt, und wirkt
   automatisch für ALLES darunter (Felder, Eingaben, Dropdowns, Chips -
   unabhängig vom Feldtyp). Gilt für JEDEN <details>-Innenbereich der
   App, nicht nur die Profilseite - deshalb hier zentral für alle
   *-content-Wrapper-Klassen gesetzt statt einzeln pro Seite. Die
   bisherigen Einzel-Fixes in .settings-section-content und
   .event-custom-slot wurden durch diese allgemeine Regel ersetzt (siehe
   dort). */
.profile-section-content,
.event-position-content,
.announcement-group-content,
.settings-section-content,
.event-subsection-content {
    box-sizing: border-box;
}

/* Etwas mehr Luft zwischen mehreren direkt aufeinanderfolgenden
   Mehrfachauswahl-Feldern (z.B. auf dem Profil: "mag" / "mag nicht" /
   Beeinträchtigungen), damit sie klar als eigene Felder erkennbar
   bleiben statt optisch ineinander überzugehen. */
.profile-section-content .field + .field {
    margin-top: 4px;
}

/* Runde 25 (Toby: "Profilboxen noch immer viel zu groß und ohne platz
   nebeneinander"): Die Mehrfachauswahl-Boxen auf der Profilseite
   (Positions-Vorlieben, Beeinträchtigungen, Sprachen) sind "fluid" und
   haben sich dadurch über die volle Breite des Hauptinhaltsbereichs
   (bis zu 1200px) gestreckt - bei nur ein bis zwei ausgewählten Chips
   wirkte das riesig und leer. "Positionen, die ich besonders gerne
   mache"/"...lieber nicht mache" stehen seit dieser Runde als
   `.two.fields` nebeneinander (siehe profile.php), zusätzlich bekommen
   alle Mehrfachauswahl-Boxen im Profilformular hier eine Höchstbreite,
   damit auch die alleinstehenden Felder (Beeinträchtigungen, Sprachen)
   nicht mehr über die gesamte Breite gehen. */
.profile-form .ui.multiple.dropdown {
    max-width: 600px;
}

a { color: var(--accent-color); }

/* ---- Sticky Header / Navigation ---- */
.sticky-header {
    position: sticky;
    top: 0;
    z-index: 1000;
    background-color: var(--stickyheader-bg);
    color: var(--stickyheader-font);
    box-shadow: 0 2px 5px rgba(0,0,0,.1);
    border-bottom: 3px solid var(--accent-color);
}

.sticky-header .ui.menu {
    background-color: var(--stickyheader-bg) !important;
    border: none !important;
    box-shadow: none !important;
}

.sticky-header .item, .sticky-header .ui.dropdown .text, .sticky-header i.icon {
    color: var(--stickyheader-font) !important;
}

/* Ronde 107, Nachtrag (Toby: "Wieso hast du den Filter auf dem Logo auf
   der Startseite ohne login wieder entfernt?"): der Filter (Runde 104)
   war nie entfernt, aber als schwarzer drop-shadow auf dem seit Runde 31
   dunklen Standard-Hintergrund praktisch unsichtbar - siehe Docblock in
   templates/home.php. Vorher als Inline-Style umgesetzt (konnte daher gar
   nicht themeabhängig reagieren) - jetzt als Klasse, damit Hell- und
   Dunkelmodus unterschiedliche, jeweils tatsächlich sichtbare Schatten/
   Glühen bekommen können. */
.home-logo-img {
    max-height: 150px;
    max-width: 100%;
    margin-bottom: 20px;
    filter: drop-shadow(0 0 0.1rem #000000);
}
body.dark .home-logo-img {
    filter: drop-shadow(0 0 0.35rem rgba(255, 255, 255, .45));
}

/* Runde 110 (Toby: "Das mit dem Auto im Profil muss in eine eigene Box,
   das ist viel zu viel für [die Zusätzliche-Informationen-Box]"): die
   Runde-108-Regel .profile-driver-info-box ist entfallen - der komplette
   Fahrzeug-/Fahrdienst-Block ist jetzt ein eigenständiger
   .profile-section-Akkordeon-Eintrag (siehe templates/crewler/profile.php)
   und braucht keine zusätzliche Box-in-der-Box-Umrandung mehr (Lehre aus
   Runde 14, siehe .announcement-group weiter unten). */

/* Ronde 107: Hilfeseite (templates/help/index.php).
   Nachtrag nach Rückmeldung ("im Dunkelmodus farblich zerstört, ... das
   Inhaltsverzeichnis alles andere als schön"): .help-toc/.help-topic
   waren ursprünglich als rohe ".ui.segment" (Semantic-UI-eigene Klasse)
   umgesetzt - die bringt ihr eigenes festes weißes background/box-shadow
   mit, das NICHT über unsere CSS-Variablen eingefärbt wird (anders als
   ".ui.segment.trcard" weiter oben, das genau dafür extra gestylt ist).
   Ergebnis: 15 helle, unpassende Kästen mitten auf der dunklen Seite.
   Lösung: dieselbe dezente, theme-fähige "Box-in-der-Box"-Optik wie
   .announcement-group (siehe dort) - eigene Klassen statt ".ui.segment",
   Farben ausschließlich über die bestehenden CSS-Variablen, damit es in
   Hell- UND Dunkelmodus korrekt aussieht. scroll-margin-top bleibt nötig,
   da der Seitenkopf sticky ist und sonst die angesprungene Überschrift
   verdecken würde. */
.help-toc, .help-topic {
    scroll-margin-top: 90px;
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 6px;
    padding: 16px 18px 14px;
    margin-bottom: 18px;
}
.help-topic:last-child { margin-bottom: 0; }

.help-toc { margin-bottom: 28px; }
.help-toc h4.ui.header { margin-top: 0; margin-bottom: 14px; }
.help-topic h4.ui.header { margin-top: 0; }

.help-topic-body p:first-child { margin-top: 0; }
.help-topic-body ul { margin-bottom: 0; padding-left: 20px; }
.help-topic .ui.mini.basic.button { margin-top: 10px; }

/* Inhaltsverzeichnis: eigenes, kompaktes Link-Raster statt der (im
   Dunkelmodus schlecht lesbaren) Semantic-UI-Standardliste. */
.help-toc-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 40px;
}
.help-toc-col {
    flex: 1 1 260px;
    min-width: 220px;
}
.help-toc-col-title {
    font-weight: bold;
    color: var(--accent-color);
    margin-bottom: 6px;
    font-size: 14px;
}
.help-toc-links {
    display: flex;
    flex-direction: column;
}
.help-toc-link {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 8px;
    margin: 0 -8px;
    border-radius: 6px;
    color: var(--text-color) !important;
    text-decoration: none;
    font-size: 14px;
    line-height: 1.3;
}
.help-toc-link i.icon {
    color: var(--accent-color);
    margin: 0;
    width: 1.15em;
    text-align: center;
}
.help-toc-link:hover {
    background-color: rgba(127, 127, 127, .12);
    color: var(--accent-color) !important;
}

.logo-wrapper {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 16px;
}

.logo-wrapper img {
    /* Runde 88: von 32px auf 46px angehoben - das neue kombinierte Logo
       (Runde 88, Entwurf A) ist ein zweizeiliger Schriftzug (TRgallery-Marke
       + "CREWVERWALTUNG" darunter) statt der bisherigen einzeiligen breiten
       Wortmarke, und braucht dadurch etwas mehr Höhe, um lesbar zu bleiben -
       bei 32px verschwamm der untere Schriftzug zu einem unleserlichen
       Strich. Der bisher separat daneben stehende Text "TRcrewverwaltung"
       (.logo-text, siehe main.php) entfällt seitdem, da das neue Logo den
       Produktnamen bereits selbst enthält - dadurch bleibt trotz der
       größeren Bildhöhe insgesamt sogar Platz gespart statt zusätzlich
       verbraucht. */
    max-height: 52px;
    height: auto;
}

/* ---- Mobiles Menü ----
   Runde 30 (Toby: "Bau das mobile menü als burgermenü das seitlich
   eingeslidet wird"): #main-nav klappte bisher einfach unterhalb des
   Headers im normalen Seitenfluss auf. Jetzt ein echtes seitliches
   Slide-In-Panel: #main-nav liegt fest (position:fixed) rechts, startet
   außerhalb des sichtbaren Bereichs (translateX(100%)) und fährt beim
   Öffnen per CSS-Transition ein, mit einem abdunkelnden Hintergrund
   (#nav-backdrop) dahinter, der beim Antippen das Menü wieder schließt
   (siehe app.js). Der Hamburger-Button selbst bleibt bewusst an seiner
   Position im Header (nicht im Panel selbst) und bekommt einen höheren
   z-index als das Panel, damit er beim geöffneten Menü sichtbar
   anklickbar bleibt (app.js tauscht sein Icon dann gegen ein
   "X" (close) - dieselbe Fläche dient so als Öffnen- UND
   Schließen-Schalter, ohne einen zweiten Button im Panel zu brauchen). */
.nav-toggle {
    display: none;
    background: none;
    border: none;
    color: var(--stickyheader-font);
    font-size: 20px;
    padding: 10px 16px;
    cursor: pointer;
}

/*
 * z-index 999, NICHT 1000: #main-nav liegt (im Markup) innerhalb von
 * .sticky-header, das selbst position:sticky + z-index:1000 hat und damit
 * einen eigenen Stacking-Context bildet. #main-navs eigener z-index:1001
 * (siehe unten) gilt nur INNERHALB dieses Contexts (z.B. gegenüber dem
 * .nav-toggle-Button). #nav-backdrop liegt dagegen als Geschwister-Element
 * AUSSERHALB von .sticky-header im Markup (siehe main.php) - stünde sein
 * z-index ebenfalls bei 1000, würde er als (im Dokument spätere) gleich
 * hohe Stacking-Context-Ebene den KOMPLETTEN .sticky-header-Context
 * überdecken, das eingeschobene Panel eingeschlossen, egal welchen
 * z-index #main-nav intern hat (führte dazu, dass das Panel sichtbar
 * abgedunkelt und nicht mehr anklickbar war). Mit 999 bleibt der Hintergrund
 * zuverlässig unter dem gesamten Header-Context, aber (da .app-main/.app-
 * footer unpositioniert sind) weiterhin über der eigentlichen Seite.
 */
#nav-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .45);
    z-index: 999;
    opacity: 0;
    transition: opacity .25s ease;
}
#nav-backdrop.nav-open {
    display: block;
    opacity: 1;
}

/* Runde 102 (Toby: "Mein anderes Projekt (conarchiv.de) hat ein cooleres
   Menü in der mobilen Ansicht ... Kannst du meins auch so ähnlich aussehen
   lassen?"): dieselben Nav-Elemente wie auf dem Desktop (kein zweiter,
   separat gepflegter Menübaum) - auf dem Desktop bleiben die neuen
   Wrapper/Klassen unten wirkungslos (".mobile-nav-tiles" per
   "display:contents" komplett aus dem Box-Baum entfernt, alle
   ".mobile-*"-Klassen per Default unsichtbar), auf Mobile (siehe
   @media-Block weiter unten) werden daraus ein Icon-Kachel-Raster für die
   echten Top-Level-Seiten sowie durchgehend sichtbare, mit Kopfzeile
   abgesetzte Listenabschnitte für "Verwaltung"/"Mehr"/"Konto"/"Darstellung"/
   "Info" - keine Klick-zum-Aufklappen-Untermenüs mehr, analog zum
   ConArchiv-Screenshot. */
/* Aus demselben Spezifitäts-Grund wie beim Bugfix direkt darunter
   vorsorglich ebenfalls auf #main-nav gestützt + "!important", statt nur
   ".mobile-nav-tiles" - auch wenn hier bisher kein konkreter Fehler
   gemeldet wurde, hätte ein zu unspezifischer Selektor genau dasselbe
   Risiko (Semantic-Regel gewinnt, Wrapper bleibt ein normaler Block statt
   aus dem Box-Baum zu verschwinden, Desktop-Menüzeile könnte umbrechen). */
#main-nav .mobile-nav-tiles {
    display: contents !important;
}
/*
 * Bugfix (Nachtrag zu Runde 102, Toby: "jetzt hast du dummerweise in der
 * Desktopversion auch Impressum, Datenschutz und Kontakt auch nach oben
 * ins Menü gelegt"): diese drei "hidden by default"-Regeln waren
 * ursprünglich reine Ein-Klassen-Selektoren (z.B. einfach
 * ".mobile-only-item { display:none }"). Semantic UIs eigene Menü-Item-
 * Regeln (z.B. ".ui.menu .item", zwei Klassen) sind SPEZIFISCHER als ein
 * einzelner Klassen-Selektor und haben deshalb - unabhängig von der
 * Reihenfolge im CSS - das "display:none" ausgehebelt, wodurch Info-
 * Menüpunkt & Co. auch auf dem Desktop sichtbar blieben. Fix: auf die ID
 * #main-nav gestützt (höhere Spezifität als jede reine Klassen-Regel,
 * dasselbe bereits etablierte Muster wie bei den übrigen
 * Mobile-Erzwingungsregeln weiter unten) plus "!important" zur
 * Absicherung gegen jede denkbare Semantic-Kombination.
 */
#main-nav .mobile-section-header,
#main-nav .mobile-only-item {
    display: none !important;
}
#main-nav .mobile-only-label {
    display: none !important;
}

@media (max-width: 900px) {
    .sticky-header .ui.menu {
        flex-wrap: wrap;
    }
    .nav-toggle {
        display: block;
        margin-left: auto;
        position: relative;
        z-index: 1002;
    }
    /*
     * Body-Scroll sperren, während das Menü offen ist (nur mobil - vgl.
     * die Bug-Notiz: wenn diese Regel außerhalb der Media Query stünde,
     * bliebe der Body gesperrt, falls jemand bei geöffnetem Menü das
     * Fenster auf Desktop-Breite vergrößert, ohne das Menü zu schließen).
     */
    body.nav-lock {
        overflow: hidden;
    }
    /*
     * Semantic UIs eigene Regel ".ui.menu .right.menu { display: flex }" ist
     * spezifischer als eine reine Klassen-Regel und würde ein einfaches
     * ".right.menu { display:none }" hier immer schlagen. Deshalb über die
     * ID #main-nav (höhere Spezifität) + !important erzwingen.
     */
    #main-nav {
        display: flex !important;
        flex-direction: column;
        align-items: stretch;
        position: fixed;
        top: 0;
        right: 0;
        width: min(82vw, 320px);
        /*
         * Runde 109: doppelte Absicherung gegen das gemeldete "Menü ist
         * seitlich größer als der Browser" - "max-width:100vw" garantiert,
         * dass das Panel (unabhängig davon, wie "width" oben im Zusammenspiel
         * mit einem im Einzelfall abweichenden Geräte-Viewport berechnet
         * wird) NIE breiter werden kann als der tatsächlich sichtbare
         * Bildschirm, und "overflow-x:hidden" verhindert zusätzlich, dass
         * IRGENDein Kind-Element (z.B. ein absolut positioniertes Dropdown-
         * Menü wie die Benachrichtigungsglocke) das Panel seitlich
         * aufreißt oder es (da "overflow-y:auto" gesetzt ist und laut
         * CSS-Spezifikation "overflow-x" dadurch sonst automatisch zu
         * "auto" statt "visible" wird) seitlich wischbar/verschiebbar
         * macht - das Panel soll sich AUSSCHLIESSLICH vertikal verhalten.
         */
        max-width: 100vw;
        height: 100vh;
        /*
         * "100dvh" (dynamic viewport height) NACH der "100vh"-Zeile, damit
         * ältere Browser ohne dvh-Unterstützung bei der vh-Fallback-Zeile
         * bleiben: "100vh" auf Mobile bezieht sich auf die maximale
         * Browserhöhe OHNE die (ein-/ausblendende) Adressleiste und kann
         * dadurch faktisch höher sein als der gerade sichtbare Bereich -
         * unterste Menüpunkte (Abmelden, Sprachumschalter) wären dann nur
         * erreichbar, wenn das Scrollen innerhalb des Panels zuverlässig
         * funktioniert. "100dvh" passt sich stattdessen laufend der
         * tatsächlich sichtbaren Höhe an.
         */
        height: 100dvh;
        margin: 0;
        overflow-y: auto;
        overflow-x: hidden;
        /*
         * "touch-action:pan-y" sagt dem Browser vorab, dass innerhalb
         * dieses Panels NUR vertikal gewischt werden soll - ohne das muss
         * der Browser bei jeder Berührung erst kurz abwarten, ob eventuell
         * eine seitliche Wisch- oder Zoom-Geste gemeint ist, bevor er einen
         * Tap als Klick auf einen Menüpunkt akzeptiert. Genau diese kurze
         * Unklarheit ist eine bekannte, verbreitete Ursache dafür, dass
         * Taps auf mobilen Geräten "manchmal" (nicht immer) ignoriert
         * werden, obwohl optisch alles unverändert aussieht - passt genau
         * zu Tobys Beschreibung "sporadisch nicht anklickbar".
         */
        touch-action: pan-y;
        padding-top: 56px;
        background-color: var(--stickyheader-bg);
        border-left: 1px solid var(--border-color);
        box-shadow: -6px 0 20px rgba(0, 0, 0, .3);
        transform: translateX(100%);
        visibility: hidden;
        transition: transform .25s ease, visibility 0s linear .25s;
        z-index: 1001;
    }
    /* visibility:hidden hält das geschlossene Panel (und seine Links)
       aus der Tab-Reihenfolge/Screenreader-Wahrnehmung heraus, obwohl es
       technisch weiter "da" ist (display bleibt flex, nur per transform
       verschoben) - die "transition-delay" auf visibility sorgt dafür,
       dass es beim SCHLIESSEN erst nach Ende der Slide-Animation
       verschwindet, beim ÖFFNEN aber sofort sichtbar wird. */
    #main-nav.nav-open {
        transform: translateX(0);
        visibility: visible;
        transition: transform .25s ease;
    }
    #main-nav .item,
    #main-nav .ui.dropdown.item {
        width: 100%;
        box-sizing: border-box;
    }
    /*
     * Semantic UI legt ".ui.dropdown.item" (bzw. ".ui.menu .dropdown.item")
     * standardmäßig als Flex-Container an, um Text + Pfeil-Icon in einer
     * Zeile auszurichten. Das ".menu" liegt im DOM als weiteres Kind in
     * genau diesem Flex-Container - dadurch wird es bei geöffnetem Dropdown
     * trotz "position:static" NICHT unter das Label gesetzt, sondern als
     * weiteres Flex-Item daneben (und läuft so über den rechten Rand
     * hinaus). Fix: Auf Mobile "display:block" erzwingen, damit Label und
     * Untermenü normal untereinander im Fluss stehen.
     */
    #main-nav .ui.dropdown.item {
        display: block;
    }
    #main-nav .ui.dropdown.item .menu {
        position: static;
        box-shadow: none;
        width: 100%;
        border: none;
        margin-top: 8px;
    }

    /* Runde 102: Icon-Kachel-Raster für die echten Top-Level-Seiten
       (Dashboard/Veranstaltungen bzw. Verfügbarkeit/Einsätze/
       Ankündigungen) - 2 Spalten wie im ConArchiv-Screenshot. Reine
       Mobile-Optik, siehe Docblock oben. */
    #main-nav .mobile-nav-tiles {
        display: grid !important;
        grid-template-columns: repeat(2, 1fr);
        gap: 10px;
        padding: 14px 14px 6px;
        width: 100%;
        box-sizing: border-box;
    }
    .mobile-nav-tiles .nav-tile {
        display: flex !important;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 8px;
        text-align: center;
        padding: 18px 8px !important;
        background: rgba(127, 127, 127, .08);
        border: 1px solid var(--border-color);
        border-radius: 12px;
        position: relative;
        min-height: 0;
    }
    .mobile-nav-tiles .nav-tile i.icon {
        margin: 0;
        font-size: 22px;
        color: var(--accent-color);
    }
    .mobile-nav-tiles .nav-tile .nav-menu-badge {
        position: absolute;
        top: 8px;
        right: 8px;
        margin-left: 0;
    }

    /* Runde 102: "Verwaltung"/"Mehr" (und die übrigen Dropdown-Menüs -
       Profil, Sprache) verlieren ihr Klick-zum-Aufklappen-Verhalten und
       zeigen ihre Einträge stattdessen dauerhaft an, mit ihrem bisherigen
       Auslöser-Text als kleine, gedämpfte Gruppenüberschrift darüber -
       genau wie die "Konto"/"Info"-Abschnitte im ConArchiv-Screenshot.
       Bewusst NICHT auf die Benachrichtigungsglocke angewendet (eigene,
       schon bestehende Klick-Logik/Optik, siehe .notification-bell-*
       weiter unten in dieser Datei) - dort bleibt es beim Antippen zum
       Öffnen, sonst stünde bei jedem Seitenaufruf sofort die komplette
       Benachrichtigungsliste offen im Menü. */
    #main-nav .ui.dropdown.item:not(.notification-bell-item) .menu {
        display: block !important;
    }
    #main-nav .ui.dropdown.item:not(.notification-bell-item) > i.dropdown.icon {
        display: none;
    }
    #main-nav .mobile-section-label {
        display: inline-block;
        font-size: 11px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .05em;
        color: var(--muted-text);
        opacity: .85;
    }
    /* Eigenständige (nicht-anklickbare) Gruppenüberschriften, z.B. "Konto"
       über dem Profil-Dropdown oder "Darstellung" über Design-/
       Sprachumschalter - dieselbe gedämpfte Optik wie .mobile-section-label
       oben, aber als eigene Zeile (kein Geschwister-Badge, das inline
       daneben bleiben müsste). */
    /*
     * Dieselben Selektoren wie bei der "hidden by default"-Regel oben
     * (#main-nav-Präfix + "!important") - sonst würde die dortige höhere
     * Spezifität hier innerhalb des Media Queries weiterhin gewinnen und
     * die Elemente blieben auch mobil unsichtbar (siehe Docblock beim
     * Default-Fall weiter oben in dieser Datei).
     */
    #main-nav .mobile-section-header {
        display: block !important;
        font-size: 11px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .05em;
        color: var(--muted-text);
        opacity: .85;
        padding: 14px 18px 2px;
        width: 100%;
        box-sizing: border-box;
    }
    #main-nav .mobile-only-item {
        display: block !important;
    }
    #main-nav .mobile-only-label {
        display: inline !important;
        margin-left: 6px;
        font-size: 13px;
    }
}

body.dark .ui.menu .dropdown.item .menu,
body.dark .ui.dropdown .menu {
    background-color: #2f3336 !important;
}

body.dark .ui.menu .dropdown.item .menu .item,
body.dark .ui.dropdown .menu .item {
    color: #f0f0f0 !important;
}

body.dark .ui.menu .dropdown.item .menu .item:hover,
body.dark .ui.dropdown .menu .item:hover {
    background-color: #3a3a3a !important;
}

/*
 * Runde 77 Bugfix: Semantic UI rendert eine Gruppenüberschrift innerhalb
 * eines Dropdown-Menüs (".menu .header", seit Runde 76 im
 * "Verwaltung"-Menü verwendet) standardmäßig in einem sehr dunklen Grauton
 * (fast Schwarz), gedacht für einen HELLEN Menühintergrund. Die obigen
 * Dark-Mode-Regeln deckten bisher nur ".item" ab, nicht ".header" - dadurch
 * blieb die Überschrift im Dunkelmodus praktisch unlesbar auf dem dunklen
 * Menühintergrund. Fix: dieselbe gedämpfte Textfarbe wie für sonstige
 * sekundäre Beschriftungen im Dunkelmodus (--muted-text).
 */
body.dark .ui.menu .dropdown.item .menu .header,
body.dark .ui.dropdown .menu .header {
    color: var(--muted-text) !important;
}

/* ---- Layout ---- */
main.app-main {
    flex: 1 0 auto;
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 28px 20px 60px;
    box-sizing: border-box;
}

.app-footer {
    margin-top: auto;
    padding: 18px 20px;
    background-color: var(--footer-bg);
    text-align: center;
    font-size: 14px;
    color: var(--text-color);
}

.app-footer a {
    color: var(--text-color);
    opacity: .75;
    margin: 0 10px;
    text-decoration: none;
}

.app-footer a:hover { opacity: 1; text-decoration: underline; }

/* Runde 32 ("Versionsnummer klein und unauffällig im Footer"): bewusst
   deutlich gedämpfter als die Footer-Links (opacity .75) - reine
   Diagnose-Info für Toby/den Support, nicht etwas, das Nutzer aktiv
   wahrnehmen sollen. */
.app-footer-version {
    margin-top: 6px;
    font-size: 11px;
    opacity: .35;
}

/* Runde 114 (Toby: Dank an die Beta-Tester im Footer, per Nachtrag als
   Modalbox statt als Fließtext - siehe #beta-thanks-modal in
   templates/layout/main.php): im Footer selbst steht nur noch ein kurzer
   Link, der die eigentliche Dank-Botschaft in einer Modalbox öffnet. Der
   Link selbst erbt die normale Footer-Link-Optik von ".app-footer a"
   weiter oben (Opacity .75, Unterstreichung erst bei Hover) - dieser
   Wrapper sorgt nur für einen eigenen Absatz mit etwas Abstand zur
   Versionsnummer direkt darüber, analog zu .app-footer-donate. */
.app-footer-beta-thanks {
    margin-top: 10px;
    font-size: 13px;
}

/* Runde 114, zweiter Nachtrag (Toby schickte den gewünschten Dank-Wortlaut
   als Liste mit Bulletpoints statt als Fließtext-Satz): die Namen in der
   #beta-thanks-modal-Modalbox stehen seitdem als echte <ul>-Liste
   zwischen Intro- und Schluss-Satz - dieselbe Abstand-/Einzug-Optik wie
   bei .legal-text ul weiter unten, nur ohne den zusätzlichen
   Absatz-Abstand darunter (margin-bottom: 0), da hier direkt danach noch
   der Schluss-Satz ("Ihr seid die Besten!") folgt. */
.beta-thanks-list {
    margin: 0 0 1em;
    padding-left: 22px;
}
.beta-thanks-list li {
    margin-bottom: 4px;
}
.beta-thanks-list li:last-child {
    margin-bottom: 0;
}

/* Runde 100 (Toby: "Kannst du diese kleinen Spendenbutton ganz unten unter
   dem Impressum und co einfügen") - der Button ist ein extern generiertes
   Bild mit eigener Farbgebung, daher hier bewusst NICHT die gedämpfte
   Optik/den Rand-Abstand der übrigen Footer-Links (.app-footer a oben)
   übernehmen, sondern in voller Farbe/Deckkraft anzeigen; auf schmalen
   Bildschirmen darf das Bild schrumpfen statt den Footer zu sprengen. */
.app-footer-donate {
    margin-top: 14px;
}
.app-footer-donate a {
    display: inline-block;
    opacity: 1;
    margin: 0;
}
.app-footer-donate img {
    max-width: 100%;
    height: auto;
    vertical-align: middle;
    /* Runde 100 (Nachtrag, Toby: "den Spendenbutton um 20% kleiner
       machen") - dasselbe bereits im Projekt etablierte `zoom`-Verfahren
       wie bei der individuellen Schriftgrößen-Einstellung (siehe
       src/Core/FontSize.php), hier fest auf 80% statt wählbar: `zoom`
       verkleinert (anders als `transform: scale()`) auch die Layout-Box
       selbst mit, es bleibt also kein leerer Freiraum um das Bild übrig. */
    zoom: 0.8;
}

/* ---- Cards / Segmente im Box-Look ---- */
.ui.segment.trcard {
    background-color: var(--box-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    margin: 0 0 26px 0;
}
main.app-main > .ui.segment.trcard:last-child { margin-bottom: 0; }

/* ---- Positionen-Blöcke innerhalb einer Veranstaltung ----
   Jede Position ist eine <details>-Box: eingeklappt zeigt die
   <summary>-Kopfzeile Name + kompakte Kennzahlen (Anzahl Zeitslots,
   Besetzungsstand), sodass man bei mehreren Positionen nicht mehr durch
   lauter voll aufgeklappte Matrix-Tabellen scrollen muss (siehe Feedback
   Runde 12). Kein Semantic-Accordion-JS nötig – native <details>, gleiches
   Muster wie schon bei "Einzelnen Sonderslot hinzufügen" (Runde 10). */
.event-position-block {
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 6px;
    margin-bottom: 20px;
    overflow: hidden;
}
.event-position-block:last-of-type { margin-bottom: 24px; }

.event-position-summary {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    padding: 14px 18px;
    cursor: pointer;
    list-style: none;
}
/* Natives Dreieck abschalten (verhält sich zusammen mit display:flex
   browserabhängig unzuverlässig) – stattdessen ein eigenes Pfeil-Icon,
   das sich beim Öffnen dreht. */
.event-position-summary::-webkit-details-marker { display: none; }
.event-position-summary::marker { content: ''; }
.event-position-summary:hover { background-color: rgba(127, 127, 127, .08); }

.event-position-caret {
    flex: 0 0 auto;
    color: var(--accent-color);
    transition: transform .15s ease;
}
details[open] > .event-position-summary .event-position-caret {
    transform: rotate(90deg);
}

.event-position-title {
    font-family: var(--font-main);
    font-size: 18px;
    color: var(--accent-color);
    font-weight: normal;
}

.event-position-summary-badges {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.event-position-badge {
    display: inline-block;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
    border-radius: 100px;
    padding: 2px 10px;
    font-size: 12px;
    color: var(--muted-text);
    white-space: nowrap;
}
.event-position-badge-full {
    color: #fff;
    background: var(--success-color);
    border-color: var(--success-color);
}
.event-position-badge-empty { font-style: italic; }

/* Runde 72 ("Zusätzliche Tage" außerhalb von datum_von/datum_bis, siehe
   EventController::addExtraDay()): kleine, auffällige Markierung an jeder
   Stelle, an der ein solcher Tag neben den regulären Veranstaltungstagen
   auftaucht (Zeitslot-Liste, Matrix-Zeile), damit klar bleibt, dass er
   außerhalb des eigentlichen Zeitraums liegt. */
.event-extra-day-tag {
    display: inline-block;
    background: var(--warning-color);
    color: #000;
    border-radius: 100px;
    padding: 1px 8px;
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
    margin-left: 4px;
}

.event-position-delete-inline {
    margin-left: auto;
}
.event-position-delete-inline button {
    background: none;
    border: none;
    color: var(--danger-color);
    cursor: pointer;
    padding: 4px;
}

.event-position-content {
    padding: 4px 18px 18px;
    border-top: 1px solid var(--border-color);
}

/* ---- Ausklappbare Feedback-/Fahrgemeinschaft-/Kommentare-Boxen ----
   Runde 27, Toby: "die Boxen 'Fahrgemeinschaft', 'Kommentare' und
   'Feedback' ausklappbar mache, standard ist eingeklappt, aber mit so
   einer kleinen sprechblase anzeigen wieviele dadrin sind". Eigene
   Klasse .event-subsection statt Wiederverwendung von .event-position-*
   oder .profile-section: anders als bei .profile-section bleibt hier
   JEDE Box ihr eigenes .trcard-Kästchen (nur ein <details> pro Karte,
   keine mehreren gestapelten Abschnitte in einer gemeinsamen Karte) -
   deshalb wieder mit eigenem Innenabstand statt nur einem Trennstrich,
   analog zu .event-position-block/-content oben. */
.event-subsection-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    list-style: none;
}
.event-subsection-summary::-webkit-details-marker { display: none; }
.event-subsection-summary::marker { content: ''; }

.event-subsection-caret {
    flex: 0 0 auto;
    color: var(--accent-color);
    transition: transform .15s ease;
}
details[open] > .event-subsection-summary .event-subsection-caret {
    transform: rotate(90deg);
}

.event-subsection-title.ui.header {
    margin: 0 !important;
}

/* "Kleine Sprechblase" (Tobys Wortwahl) mit der Anzahl der Einträge in
   der Box - eigene, kleine Pfeilspitze unten links per ::after simuliert
   einen Sprechblasen-Schwanz, ohne eine Grafik/Icon-Font laden zu
   müssen. Grau/gedämpft statt Akzentfarbe, wenn die Box leer ist, damit
   auf den ersten Blick klar ist, ob sich das Aufklappen überhaupt
   lohnt. */
.event-subsection-badge {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 18px;
    padding: 0 6px;
    margin-left: 2px;
    margin-bottom: 4px;
    background: var(--accent-solid);
    color: #fff;
    font-size: 11px;
    font-weight: bold;
    border-radius: 9px;
    line-height: 18px;
}
.event-subsection-badge::after {
    content: '';
    position: absolute;
    left: 5px;
    bottom: -4px;
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 4px solid var(--accent-color);
}
.event-subsection-badge-empty {
    background: var(--bg-color);
    color: var(--muted-text);
    border: 1px solid var(--border-color);
}
.event-subsection-badge-empty::after {
    border-top-color: var(--border-color);
}

.event-subsection-content {
    padding: 14px 2px 2px;
}

/* ---- Kommentare-Liste auf der Veranstaltungsseite: Runde 27, Toby:
   "Die Kommentare in dieser Box dann auch schöner auflisten!" - bewusst
   weiterhin flach (keine verschachtelte Extra-Box je Kommentar, siehe
   .feedback-comment-Lektion aus Runde 14 weiter unten), aber mit
   kleinem Initialen-Avatar und klarerem Zeilenlayout statt reinem
   Fließtext-Block. */
.event-comment {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}
.event-comment-avatar {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--accent-solid);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: bold;
}
.event-comment-body {
    flex: 1 1 auto;
    min-width: 0;
}
.event-comment-delete {
    flex: 0 0 auto;
}
.event-comment-delete button {
    background: none;
    border: none;
    color: var(--danger-color);
    cursor: pointer;
    padding: 4px;
}

/* ---- Ausklappbare Bereiche auf der Profilseite ----
   Gleiches <details>-Grundprinzip wie die Positionen-Blöcke oben
   (Runde 12) und "Einzelnen Sonderslot hinzufügen" (Runde 10) – bewusst
   eigene Klassen statt Wiederverwendung von .event-position-*, damit
   Änderungen an der Veranstaltungsseite die Profilseite nicht
   versehentlich mit betreffen (siehe Feedback Runde 13: Profilseite
   aufräumen + Passwortänderung ebenfalls als ausklappbare Box).
   Seit Runde 14 bewusst OHNE eigenen Kasten-Look (kein
   background/border/radius wie bei .event-position-block): Toby fand die
   vorherige Version mit farbigem Rand + eigenem Hintergrund "zu viele
   verschachtelte Boxen", weil sie optisch eine Karte-in-der-Karte war
   (identischer Stil wie die umgebende .trcard-Box). Jetzt nur noch ein
   schlichter Trennstrich zwischen den Abschnitten, keine eigene
   Box-Optik – wirkt als EIN zusammenhängender Bereich statt mehrerer
   verschachtelter Kästen. */
.profile-section {
    border-bottom: 1px solid var(--border-color);
}
.profile-section:last-of-type { border-bottom: none; }
/* Runde 113 (Toby: "alle Unterpunkte ein sauberes ausklappbares Menü"):
   jeder Profil-Unterpunkt liegt jetzt einzeln in seiner eigenen
   .trcard-Box (siehe profile.php) statt mehrere .profile-section-Einträge
   in einer gemeinsamen Box zu bündeln - die frühere Sonderregel für den
   "ersten" Abschnitt einer solchen Sammel-Box (Trennstrich zum darüber
   liegenden, damals noch nicht ausklappbaren "Persönliche Daten"-Bereich)
   ist damit hinfällig und wurde entfernt. Übrig gebliebene Mehrfach-Boxen
   (z.B. "Positionen & Einschränkungen" + "Anzeige" waren bis Runde 112
   zusammen in einer Box) sind jetzt ebenfalls einzeln in eigenen Boxen. */

.profile-section-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 16px 4px;
    cursor: pointer;
    list-style: none;
}
.profile-section-summary::-webkit-details-marker { display: none; }
.profile-section-summary::marker { content: ''; }
.profile-section-summary:hover { background-color: rgba(127, 127, 127, .08); }

.profile-section-caret {
    flex: 0 0 auto;
    color: var(--accent-color);
    transition: transform .15s ease;
}
details[open] > .profile-section-summary .profile-section-caret {
    transform: rotate(90deg);
}

.profile-section-title.ui.header {
    margin: 0 !important;
    font-size: 16px !important;
    color: var(--accent-color) !important;
}

.profile-section-content {
    padding: 4px 4px 24px 32px;
}

/* Großzügigerer, gleichmäßiger Abstand zwischen Feldzeilen, damit
   aufeinanderfolgende Eingabefelder nicht "aneinanderkleben" (Feedback
   Runde 14). Gilt für alle Formularbereiche der Profilseite, nicht nur
   innerhalb der ausklappbaren Abschnitte.
   Runde 113: die Selektoren für .profile-section-content sind von einem
   direkten Kind-Kombinator (">") auf einen Nachfahren-Kombinator
   umgestellt, weil jeder Unterpunkt jetzt ein eigenes <form> besitzt (siehe
   profile.php) - die .field/.fields-Elemente liegen also eine Ebene tiefer
   als vorher (.profile-section-content > form > .field statt
   .profile-section-content > .field). */
.profile-form .fields,
.profile-section-content .field,
.profile-form > .field {
    margin-bottom: 20px !important;
}
.profile-section-content .field:last-child,
.profile-section-content .fields:last-child {
    margin-bottom: 0 !important;
}

/* ---- Ankündigungen: nach Alter gruppierte, ausklappbare Boxen ----
   (Runde 18, Feedback: "Ankündigungen gruppieren nach alter... und diese
   Boxen zuklappbar und nur die ersten zwei sollen standardmäßig
   aufgeklappt sein"). Eigene Klassen-Familie statt Wiederverwendung von
   .event-position-* oder .profile-section-*, siehe Konvention seit Runde
   13. Die Gruppen-Box selbst bekommt den Kasten-Look von
   .event-position-block (sie ersetzt die vorherige lose Liste einzelner
   .trcard-Boxen). Einzelne Ankündigungen INNERHALB einer Gruppe bekommen
   bewusst KEINE eigene .trcard-Optik, sondern nur einen schlichten
   Trennstrich – sonst entstünde wieder eine Box-in-der-Box (Lehre aus
   Runde 14). */
.announcement-group {
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 6px;
    margin-bottom: 20px;
    overflow: hidden;
}
.announcement-group:last-of-type { margin-bottom: 26px; }

.announcement-group-summary {
    display: flex;
    align-items: center;
    gap: 10px 14px;
    padding: 14px 18px;
    cursor: pointer;
    list-style: none;
}
.announcement-group-summary::-webkit-details-marker { display: none; }
.announcement-group-summary::marker { content: ''; }
.announcement-group-summary:hover { background-color: rgba(127, 127, 127, .08); }

.announcement-group-caret {
    flex: 0 0 auto;
    color: var(--accent-color);
    transition: transform .15s ease;
}
details[open] > .announcement-group-summary .announcement-group-caret {
    transform: rotate(90deg);
}

.announcement-group-title {
    font-family: var(--font-main);
    font-size: 18px;
    color: var(--accent-color);
    font-weight: normal;
}

.announcement-group-count {
    margin-left: auto;
    display: inline-block;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
    border-radius: 100px;
    padding: 2px 10px;
    font-size: 12px;
    color: var(--muted-text);
}

.announcement-group-content {
    padding: 4px 18px 6px;
    border-top: 1px solid var(--border-color);
}

.announcement-item {
    padding: 16px 0;
    border-bottom: 1px solid var(--border-color);
}
.announcement-item:last-child { border-bottom: none; padding-bottom: 12px; }

/* Runde 101 (Toby: "auch ds sieht etwas unübersichtlich aus") - Datum und
   Zielgruppe waren bisher eine einzelne, kleine, gedimmte Fließtext-Zeile
   ("12.09.2026 12:00 · Alle Crewler") - auf einen Blick schwer von der
   Überschrift/dem eigentlichen Text zu unterscheiden. Jetzt als eigene
   Chips im selben Muster wie .announcement-attachment-chip weiter unten
   (konsistente "Pille mit Icon"-Optik), dadurch klar vom Fließtext
   abgesetzt und dank Icon schneller erfassbar. */
.announcement-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 6px 0 12px;
}
.announcement-meta-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    padding: 3px 10px;
    border-radius: 14px;
    background: var(--box-bg);
    border: 1px solid var(--border-color);
    color: var(--muted-text);
}
.announcement-meta-chip { line-height: 1.3; }
/* Runde 145: Icon-Glyphen der Semantic-Schrift sitzen unterhalb der Textmitte -> in den Chips per Flex zentrieren und optisch anheben */
.announcement-meta-chip i.icon {
    margin: 0; color: var(--accent-color);
    display: inline-flex; align-items: center; justify-content: center;
    flex: none; width: 1.1em; height: 1.1em; line-height: 1;
    position: relative; top: 0.1em;
}
.announcement-meta-chip i.icon::before { display: block; line-height: 1; }
.announcement-body { margin: 0 0 6px; }

/* ---- Anhänge bei Ankündigungen (Runde 31) ---- */
.announcement-attachments {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 8px 0 4px;
}
.announcement-attachment-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    padding: 4px 10px;
    border-radius: 14px;
    background: var(--box-bg);
    border: 1px solid var(--border-color);
    color: var(--text-color) !important;
    text-decoration: none;
}
.announcement-attachment-chip:hover { border-color: var(--accent-color); }
.announcement-attachment-chip .icon { color: var(--accent-color); }
.announcement-attachment-size { opacity: .65; }

/* ---- Ausklappbare Bereiche auf der Einstellungen-Seite ----
   Ursprünglich (Runde 19, Feedback: "Gruppiere die Systemeinstellungen
   auch mit zuklappbaren Boxen") bewusst OHNE eigenen Kasten-Look, exakt
   wie .profile-section (Lehre aus Runde 14: keine Karte-in-der-Karte) -
   eine schlichte Liste mit Trennstrichen.
   Runde 120 (Toby: "das sind jetzt ganz viele Einstellungen. kannst du das
   irgendwie aufräumen, übersichtlicher machen, evtl. mit Kacheln?"): die
   Liste war über 20 Runden hinweg auf 12 Abschnitte angewachsen und damit
   genau die lange, unübersichtliche Liste geworden, die Runde 14 vermeiden
   wollte - bei so vielen Abschnitten hilft die "keine Karte-in-der-Karte"-
   Regel nicht mehr, im Gegenteil. Die frühere Lehre gilt also weiterhin für
   WENIGE Abschnitte (Profil, Ankündigungsgruppen), nicht mehr hier.
   Eigene Klassen statt Wiederverwendung von .profile-section-*,
   .event-position-* oder .announcement-group-*, damit Änderungen an
   einer Stelle die anderen nicht versehentlich mit betreffen (Konvention
   seit Runde 13), gilt unverändert weiter.
   (Hinweis für künftige Sessions: dieser Kommentar hatte bis Runde 120
   versehentlich ein "*" direkt gefolgt von "/" mitten im Fließtext stehen
   - das beendet einen CSS-Kommentar vorzeitig und hat dadurch die gesamte
   .settings-tiles-Regel unten unbemerkt verschluckt, bis ein Playwright-
   Test ein kaputtes Grid-Layout zeigte. Bitte in Kommentaren IMMER auf die
   Zeichenfolge "*" + "/" ohne Leerzeichen dazwischen achten.) */
.settings-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 14px;
    margin-top: 14px;
}
/* Kategorie-Überschriften (Runde 120) - eigene Grid-Kinder, die per
   grid-column über die volle Breite gespannt werden, damit sie unabhängig
   von der aktuellen Spaltenzahl immer eine eigene Zeile bilden. Reine
   Gliederungshilfe zum schnelleren Überblick, kein eigenes Formularfeld. */
.settings-group-title {
    grid-column: 1 / -1;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--muted-text);
    margin: 10px 0 -2px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-color);
}
.settings-tiles .settings-group-title:first-child { margin-top: 0; }

.settings-section {
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background-color: rgba(127, 127, 127, .04);
    align-self: start;
    overflow: hidden;
}
/* Aufgeklappte Kachel über die volle Breite spannen, statt den Inhalt in
   eine einzelne, oft zu schmale Rasterspalte zu zwängen (z.B. die
   zweispaltigen Felder im SMTP-Abschnitt oder die Backup-Box mit ihren
   FTP-Feldern). */
.settings-section[open] {
    grid-column: 1 / -1;
}

.settings-section-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    cursor: pointer;
    list-style: none;
}
.settings-section-summary::-webkit-details-marker { display: none; }
.settings-section-summary::marker { content: ''; }
.settings-section-summary:hover { background-color: rgba(127, 127, 127, .08); }

.settings-section-caret {
    flex: 0 0 auto;
    color: var(--accent-color);
    transition: transform .15s ease;
}

/* Runde 94 (Toby: "kannst du die Einstellungsboxen auch alle mit icons
   versehen.") - ein Icon je Abschnittstitel, dieselbe Farbe/Größe wie der
   bestehende Pfeil, aber ohne dessen Rotation beim Auf-/Zuklappen. Der
   Flexbox-`gap` von .settings-section-summary sorgt automatisch für den
   passenden Abstand zum Pfeil links und zum Titeltext rechts. */
.settings-section-icon {
    flex: 0 0 auto;
    color: var(--accent-color);
}
details[open] > .settings-section-summary .settings-section-caret {
    transform: rotate(90deg);
}

.settings-section-title.ui.header {
    margin: 0 !important;
    font-size: 16px !important;
    color: var(--accent-color) !important;
}

/* Runde 120: kompakter Status-Hinweis ("Aktiv"/"Inaktiv") rechtsbündig in
   der Kopfzeile jeder Kachel mit genau einem Ein/Aus-Schalter - dadurch
   sieht man auf einen Blick, was aktiv ist, ohne jede Kachel einzeln
   aufklappen zu müssen (genau das war die "unübersichtlich"-Beschwerde). */
.settings-section-status {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: 3px 9px;
    border-radius: 999px;
    white-space: nowrap;
}
.settings-section-status.is-active {
    color: var(--success-color);
    background-color: rgba(33, 186, 69, .15);
}
.settings-section-status.is-inactive {
    color: var(--muted-text);
    background-color: rgba(127, 127, 127, .15);
}

.settings-section-content {
    padding: 4px 16px 20px 16px;
}
.settings-section-content .fields,
.settings-section-content > .field {
    margin-bottom: 20px !important;
}
.settings-section-content .fields:last-child,
.settings-section-content > .field:last-child {
    margin-bottom: 0 !important;
}
/* Der frühere Einzel-Fix hier (nur .ui.selection.dropdown, Runde 19) ist
   seit Runde 27 überflüssig: .settings-section-content selbst bekommt
   jetzt weiter oben in dieser Datei generell box-sizing:border-box (siehe
   die ausführliche Erklärung dort, bei .ui.dropdown .ui.label) - das
   behebt dieselbe <details>-Shadow-DOM-Falle bereits für ALLE Kinder,
   nicht nur Dropdowns. */

@media (max-width: 500px) {
    /* Auf sehr schmalen Bildschirmen bringt eine zweite Spalte ohnehin
       nichts (minmax(280px,1fr) würde eh nur eine Spalte zulassen) - der
       Media Query hier ist nur eine explizite Absicherung, falls ein noch
       schmaleres Gerät als 280px+Gap zur Verfügung hat. */
    .settings-tiles { grid-template-columns: 1fr; }
}

.event-slots-heading.ui.dividing.header {
    margin-top: 16px !important;
    margin-bottom: 10px !important;
    font-size: 13px !important;
    text-transform: uppercase;
    letter-spacing: .05em;
    opacity: .85;
}

/* ---- Schicht-Vorlagen (oberhalb der Positionen) ---- */
.event-shifts-hint {
    color: var(--muted-text);
    font-size: 14px;
    margin: 0 0 14px 0;
}

.event-shift-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 4px;
}

.event-shift-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    background-color: rgba(127, 127, 127, .08);
    border: 1px solid var(--border-color);
    border-radius: 20px;
    padding: 6px 8px 6px 14px;
    font-size: 14px;
}

.event-shift-chip-time {
    font-weight: 600;
    color: var(--accent-color);
}

.event-shift-chip-name {
    color: var(--text-color);
}

.event-shift-chip-delete {
    background: none;
    border: none;
    color: var(--muted-text);
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    padding: 2px 6px;
    border-radius: 50%;
}
.event-shift-chip-delete:hover {
    color: var(--danger-color);
    background-color: rgba(219, 40, 40, .1);
}

/* ---- Tage-x-Schichten-Matrix pro Position ---- */
.event-matrix-wrap {
    margin-top: 16px;
}

.event-matrix-heading.ui.header {
    margin: 0 0 4px 0 !important;
    font-size: 14px !important;
    text-transform: uppercase;
    letter-spacing: .05em;
    opacity: .85;
}

.event-matrix-hint {
    color: var(--muted-text);
    font-size: 13px;
    margin: 0 0 10px 0;
}

.event-matrix-scroll {
    overflow-x: auto;
}

.event-matrix-table.ui.table {
    width: auto;
    min-width: 100%;
}

.event-matrix-table.ui.table th,
.event-matrix-table.ui.table td {
    min-width: 92px;
}

.event-matrix-table.ui.table td:first-child,
.event-matrix-table.ui.table th:first-child {
    min-width: 110px;
    text-align: left;
}

.event-matrix-table.ui.table th {
    text-align: center;
    white-space: nowrap;
}

.event-matrix-shift-time {
    color: var(--muted-text);
    font-weight: normal;
    font-size: 12px;
}

.event-matrix-input {
    width: 64px;
    text-align: center;
    padding: 6px 4px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    background-color: var(--bg-color);
    color: var(--text-color);
}

/* Zeigt in der Matrix-Zelle direkt an, wie viele der benötigten Plätze
   schon zugeteilt sind (statt nur einer Eingabe-Zahl ohne Kontext). */
.event-matrix-assigned {
    margin-top: 4px;
    font-size: 11px;
    color: var(--muted-text);
    white-space: nowrap;
}
.event-matrix-assigned-full {
    color: var(--success-color);
    font-weight: 600;
}

/* ---- Einzelner Sonderslot (Ausnahme außerhalb der Matrix) ---- */
.event-custom-slot {
    margin-top: 14px;
}
.event-custom-slot summary {
    cursor: pointer;
    color: var(--muted-text);
    font-size: 14px;
}
.event-custom-slot summary:hover {
    color: var(--accent-color);
}
/* width:100% zählt bei content-box die eigenen Innenabstände nicht mit -
   die Box wird dadurch breiter als ihr Platz und sprengt Nachbarfelder.
   Betrifft hier nicht nur das Dropdown (früherer Einzel-Fix), sondern
   JEDES Feld in diesem Formular - .event-custom-slot hat (anders als
   z.B. .profile-section) keinen eigenen "-content"-Wrapper-Div, das
   Formular selbst ist das direkte Kind des <details>. Seit Runde 27
   deshalb direkt hier statt nur am Dropdown gefixt (siehe die
   ausführliche Erklärung zur <details>-Shadow-DOM-Falle weiter oben bei
   .ui.dropdown .ui.label). */
.event-custom-slot > form {
    box-sizing: border-box;
}

.ui.button.trcrew-red {
    background-color: #e0503f !important;
    color: #fff !important;
}
.ui.button.trcrew-red:hover { background-color: #c8422f !important; }

/* Runde 27, Toby: "Die Whatsappbuttons in der whatsappfarbe einfärben" -
   offizielles WhatsApp-Grün (#25D366) statt neutralem Grau. Zwei
   Varianten je nach Kontext: als echter .ui.button (Icon auf "Meine
   Einsätze") komplett eingefärbt wie .trcrew-red oben, als reiner
   Text-Link (Überschriftzeile auf der Veranstaltungsseite) nur Icon +
   Schrift in Markenfarbe, ohne eigenen Button-Hintergrund. */
.ui.button.trcrew-whatsapp {
    background-color: #25D366 !important;
    color: #fff !important;
}
.ui.button.trcrew-whatsapp:hover { background-color: #1ebe5b !important; }

.trcrew-whatsapp-link,
.trcrew-whatsapp-link:visited {
    color: #25D366 !important;
}
.trcrew-whatsapp-link:hover { color: #1ebe5b !important; }

/* ---- Team-Kontakte auf "Meine Einsätze" (Runde 31,
   "Kontaktmöglichkeit zwischen Crew-Mitgliedern") ---- */
.team-contact-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.team-contact-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    white-space: nowrap;
}
.team-contact-chip a { color: var(--muted-text) !important; }
.team-contact-chip a:hover { color: var(--accent-color) !important; }
.team-contact-chip a[href^="https://wa.me/"] { color: #25D366 !important; }
.team-contact-chip a[href^="https://wa.me/"]:hover { color: #1ebe5b !important; }

/* Runde 32 (Toby: Icon-Farben auf "Meine Einsätze" unterscheidbarer machen)
   führte hier .myassignments-route-icon/.myassignments-comment-icon ein, um
   die damals farblosen Icon-Buttons in der "Aktionen"-Spalte
   unterscheidbarer zu machen. Runde 101 hat diese Icon-Buttons zu einem
   einzigen Kebab-Menü mit Textbeschriftung je Eintrag zusammengefasst (s.u.
   ".myassignments-actions-menu") - dadurch übernehmen jetzt die Textlabels
   die Unterscheidung, eigene Icon-Farben sind nicht mehr nötig und wurden
   entfernt (keine anderen Verwendungsstellen mehr, siehe README). */

/* ---- Einsatz-Meilensteine/Abzeichen (Runde 31, "Crew-Erlebnis") ---- */
.milestone-badge-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 10px 0;
}
.milestone-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: 999px;
    background: var(--accent-solid);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
}
.milestone-badge-chip-mini {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--accent-solid);
    color: #fff;
    white-space: nowrap;
}

.ui.form .field > label { color: var(--text-color); }

/* Runde 30: input[type=tel] fehlte hier bisher (z.B. das Telefon-Feld bei
   Registrierung/Profil) und blieb im Dark Mode dadurch weiß statt dunkel -
   beim Testen der neu strukturierten Registrierungs-Boxen aufgefallen.
   Runde 75: derselbe Fehler bei input[type=number] (Toby: "Freie Plätze"
   bei der Fahrgemeinschaft sah im Dunkelmodus anders/weiß aus) - betrifft
   denselben Feldtyp an allen drei Stellen der App, die ihn verwenden
   (Fahrgemeinschaft-Formular, Zeitslot-Kapazität, Systemeinstellungen). */
body.dark .ui.input input,
body.dark .ui.form textarea,
body.dark .ui.form input[type=text],
body.dark .ui.form input[type=email],
body.dark .ui.form input[type=password],
body.dark .ui.form input[type=date],
body.dark .ui.form input[type=time],
body.dark .ui.form input[type=tel],
body.dark .ui.form input[type=number],
body.dark .ui.selection.dropdown {
    background-color: var(--stickyheader-bg) !important;
    color: var(--text-color) !important;
    border-color: var(--border-color) !important;
}

body.dark .ui.selection.dropdown .menu {
    background-color: #2f3336 !important;
    border-color: var(--border-color) !important;
}
body.dark .ui.selection.dropdown .menu > .item {
    color: #f0f0f0 !important;
}

/* Pflichtfelder: Semantic UI generiert per .required.field automatisch das
   rote Sternchen; hier nur die Fehlermarkierung ergänzen, wenn ein
   Pflichtfeld beim Absenden leer geblieben ist. */
.ui.form .required.field > label:after {
    color: var(--danger-color);
}
.ui.form .field.error input,
.ui.form .field.error select,
.ui.form .field.error textarea,
.ui.form .field.error .ui.selection.dropdown {
    background-color: rgba(219, 40, 40, .08) !important;
    border-color: var(--danger-color) !important;
}
.ui.form .field.error > label {
    color: var(--danger-color) !important;
}
.ui.error.message {
    background-color: rgba(219, 40, 40, .12);
    color: var(--danger-color);
    border: 1px solid var(--danger-color);
    box-shadow: none;
}
.required-hint {
    color: var(--muted-text);
    font-size: 13px;
    margin-top: -6px;
    margin-bottom: 14px;
}
/* Runde 79 (Toby: sofortige Warnung bei zu großem/falschem Profilfoto
   direkt bei der Dateiauswahl, siehe register.php) - derselbe <small>-Hinweis
   unter dem Datei-Feld wird bei einem ungültigen Bild kurzzeitig rot statt
   grau und zeigt die konkrete Fehlermeldung an. */
#register-photo-hint.register-photo-hint-error {
    color: var(--danger-color);
    font-weight: bold;
}
.ui.dividing.header {
    color: var(--text-color);
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 6px;
    margin-top: 22px;
}
.ui.form h4.dividing.header:first-of-type { margin-top: 4px; }

body.dark .ui.table {
    background-color: var(--box-bg);
    color: var(--text-color);
    border-color: var(--border-color);
}
body.dark .ui.table thead th {
    background-color: #1e2124;
    color: var(--text-color);
    border-color: var(--border-color);
}
body.dark .ui.table tr td { border-color: var(--border-color); }
body.dark .ui.table tbody tr:hover { background-color: #33383c !important; }

body.dark .ui.modal { background-color: var(--box-bg); color: var(--text-color); }
body.dark .ui.modal > .header { background-color: var(--box-bg); color: var(--text-color); border-color: var(--border-color); }
body.dark .ui.modal > .content { background-color: var(--box-bg); color: var(--text-color); }
body.dark .ui.modal > .actions { background-color: #1e2124; border-color: var(--border-color); }

body.dark .ui.card, body.dark .ui.cards > .card {
    background-color: var(--box-bg);
    color: var(--text-color);
}

/*
 * Semantic UI setzt die Textfarbe vieler Bausteine (Überschriften,
 * Checkbox-Labels, Listen, Karten) fest auf ein sehr dunkles Grau/Schwarz
 * und erwartet einen hellen Hintergrund. Im Darkmode blieb das bisher
 * unangetastet -> praktisch unlesbarer Text. Hier global nachziehen.
 */
body.dark h1, body.dark h2, body.dark h3, body.dark h4, body.dark h5, body.dark h6,
body.dark .ui.header,
body.dark .ui.header .sub.header {
    color: var(--text-color) !important;
}

body.dark .ui.checkbox label,
body.dark .ui.radio.checkbox label,
body.dark .ui.checkbox .box {
    color: var(--text-color) !important;
}

/* Runde 120 (Toby: "im dunklen Modus sind die Texte hinter den Switches
   schwarz und somit schwer lesbar"): Semantic UI setzt für eingeschaltete
   (":checked") Toggle-Switches eine eigene, hart codierte Textfarbe
   (rgba(0,0,0,.95), siehe semantic.min.css) - diese Regel hat wegen des
   zusätzlichen ":checked"/":focus"-Selektors eine HÖHERE CSS-Spezifität
   als die allgemeine .ui.checkbox-Regel direkt oberhalb, gewinnt also
   trotz "!important" dort. Nur ein eigener, mindestens ebenso spezifischer
   Selektor (hier: zusätzlich body.dark vorangestellt) kann das
   überschreiben - betrifft nur eingeschaltete Toggles, ausgeschaltete
   waren bereits vorher korrekt lesbar. */
body.dark .ui.toggle.checkbox input:checked ~ label,
body.dark .ui.toggle.checkbox input:checked ~ .box,
body.dark .ui.toggle.checkbox input:focus:checked ~ label,
body.dark .ui.toggle.checkbox input:focus:checked ~ .box {
    color: var(--text-color) !important;
}

body.dark .ui.list .item .header,
body.dark .ui.card .header,
body.dark .ui.card > .content > .header {
    color: var(--text-color) !important;
}

body.dark .ui.list .item .description,
body.dark .ui.card .description,
body.dark .ui.card .meta {
    color: var(--muted-text) !important;
}

/* Kein !important auf "color" hier: einige Status-Badges (z.B. Crewler-
   Liste) setzen ihre Textfarbe bewusst per Inline-Style für Kontrast auf
   ihrem eigenen (farbigen) Hintergrund – das soll weiter gewinnen. */
body.dark .ui.label {
    background-color: #34383c;
    color: var(--text-color);
    border: 1px solid var(--border-color);
}

/* Runde 107, Nachtrag (Toby zu den "Öffnen"-Buttons auf der Hilfeseite:
   "im dunkelmodus ... sieht man ihn fast gar nicht"): ".ui.basic.button"
   setzt bei Semantic UI selbst einen dunklen Text (rgba(0,0,0,.6)) und
   einen ebenso dunklen Rahmen (box-shadow in rgba(34,36,38,.15)) - beides
   praktisch unsichtbar auf dunklem Grund. Diese Klasse wird app-weit an
   mehreren Stellen verwendet (nicht nur auf der Hilfeseite), daher hier
   bewusst als globale Dunkelmodus-Regel statt nur für .help-topic. */
body.dark .ui.basic.button {
    color: var(--text-color) !important;
    box-shadow: 0 0 0 1px var(--border-color) inset !important;
    background: transparent !important;
}
body.dark .ui.basic.button:hover {
    color: var(--accent-color) !important;
    box-shadow: 0 0 0 1px var(--accent-color) inset !important;
    background-color: rgba(255, 255, 255, .05) !important;
}

.ui.primary.button, .ui.button.trcrew-accent {
    background-color: var(--accent-solid) !important;
    color: #fff !important;
}

.ui.label.trcrew-accent { background-color: var(--accent-solid) !important; color: #fff !important; }

/* Runde 32 (Toby: "alle Buttons sollen die selbe blaue farbe tragen und
   etwas mehr schlagschatten" auf /dashboard): Farb-Vereinheitlichung lief
   bereits über die trcrew-accent-Klasse (s.o.), hier nur der zusätzliche
   Schlagschatten. Bewusst auf .dashboard-page beschränkt (Wrapper-Div in
   templates/dashboard/crewler.php und verwalter.php) statt global auf
   .ui.button, damit Buttons in Formularen/Tabellen an anderer Stelle der
   App ihr bisheriges, flacheres Erscheinungsbild behalten. Wert deutlich
   sichtbarer als die vorhandenen Karten-Hover-Schatten (0 2px 8px
   rgba(0,0,0,.15)), aber unterhalb der Toast-Schatten (0 4px 14px
   rgba(0,0,0,.3)), da Buttons dauerhaft sichtbar sind statt nur kurz
   eingeblendet. */
.dashboard-page .ui.button {
    box-shadow: 0 3px 10px rgba(0, 0, 0, .25);
}
body.dark .dashboard-page .ui.button {
    box-shadow: 0 3px 10px rgba(0, 0, 0, .45);
}

/* ---- Auth-Seiten ---- */
.auth-wrapper {
    max-width: 440px;
    margin: 20px auto;
}

/* Runde 29 (Toby: "Registrierformular ist nun echt groß und lange
   geworden ... übersichtlicher, gerne auch breitere box um mehr felder
   nebeneinander zu bekommen"): Das Registrierungsformular ist mit den
   Feldern aus Runde 28 (Erfahrung, Pflicht-Profilfoto) spürbar
   gewachsen. Eigene, breitere Variante von .auth-wrapper NUR für die
   Registrierungsseite (Login/Passwort-Formulare bleiben bewusst schmal
   - dort sind es nur 1-2 Felder, eine breite Box würde dort nur unnötig
   leeren Raum lassen). Die zusätzliche Breite wird genutzt, um
   Vorname/Nachname/Telefon in einer Zeile unterzubringen (siehe
   register.php) statt Telefon in eine eigene Zeile zu zwingen. */
.auth-wrapper-wide {
    max-width: 860px;
    margin: 20px auto;
}

/* Runde 39 (Toby: "einen Weiteren schieberegler um Registrierungen zu
   deaktivieren ... auf den entsprechenden Seiten mit einem schönen Text
   kommuniziert"): freundlicher Hinweis anstelle des Registrierungs-
   formulars, wenn der Settings-Schalter aus ist. Bewusst NEUTRAL statt in
   der Akzentfarbe (wie .home-mitmachen-cta) gehalten - anders als die
   werbende "Mitmachen"-Kachel auf der Startseite ist das hier ein
   Hinweis auf eine vorübergehend nicht verfügbare Funktion, kein Call-to-
   Action, daher dieselbe gedeckte Optik wie z.B. die
   "no_events"-Hinweise an anderer Stelle im Projekt. */
.register-closed-card {
    text-align: center;
    padding: 42px 30px;
}
.register-closed-icon {
    width: 56px;
    height: 56px;
    margin: 0 auto;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
}
.register-closed-icon i.icon { margin: 0; color: var(--muted-text); font-size: 20px; }
.register-closed-card > h2.ui.header { margin-top: 16px; }
.register-closed-card > p { font-size: 15px; max-width: 420px; margin: 10px auto 0; color: var(--muted-text); }

/* Runde 30 (Toby: "strukturiere das registerformular neu in einzelnen
   boxen mit richtigem abstand zwischen den boxen"): Runde 29 hatte die
   Abschnitte noch per <h4 class="dividing header"> INNERHALB einer
   einzigen .trcard-Box getrennt - Toby wollte stattdessen eigene, klar
   getrennte Boxen je Abschnitt (Zugangsdaten/Persönliche Daten/
   Vorlieben/Aktionen), siehe register.php. Jede Box nutzt jetzt einen
   normalen (nicht "dividing") <h4 class="ui header"> als ersten
   Inhalt - Semantic UI setzt bei ".ui.header:first-child" automatisch
   margin-top:0, dieselbe Konvention wie bei allen anderen .trcard-Boxen
   im Projekt (z.B. admin/crewler_show.php), kein eigenes CSS dafür
   nötig. Die Boxen selbst bekommen ihren Abstand zueinander bereits
   über die bestehende .trcard-Regel (margin-bottom: 26px) - hier bleibt
   nur die Feldabstand-Verfeinerung INNERHALB einer Box aus Runde 29
   erhalten, damit die Felder auch innerhalb einer Box nicht zu eng
   aneinander kleben. */
#register-form .field,
#register-form .fields {
    margin-bottom: 1.4em;
}
#register-form .fields .field {
    margin-bottom: 0;
}
#register-form .field small {
    display: block;
    margin-top: 6px;
}
#register-form .ui.segment.trcard:last-child {
    margin-bottom: 0;
}

/* Aktions-Box (Registrieren/Mit Account anmelden/Abbrechen) - die drei
   Buttons stehen in einer Reihe mit Abstand dazwischen, brechen auf
   schmalen Bildschirmen automatisch um (siehe register.php für die
   Button-Reihenfolge: primär zuerst, dann die beiden Neben-Aktionen). */
.register-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

/* ---- Slot-/Kandidatenliste (Personaleinteilung) ---- */
.candidate-list .candidate-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-color);
    gap: 10px;
}
.candidate-list .candidate-row:last-child { border-bottom: none; }
.candidate-row.is-assignable {
    background-color: rgba(33, 186, 69, 0.10);
    border-radius: 6px;
}
.candidate-row.is-blocked {
    background-color: rgba(219, 40, 40, 0.07);
    opacity: .7;
    border-radius: 6px;
}
.candidate-reason { font-size: 12px; opacity: .85; color: var(--danger-color); }

.avatar-sm {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    background-color: var(--box-bg);
}

/* ---- Crewler-Detailansicht (Verwalter) ---- */
.crewler-detail-header {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-bottom: 18px;
}
.crewler-detail-avatar {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    object-fit: cover;
    background-color: var(--box-bg);
    border: 3px solid var(--accent-color);
    flex-shrink: 0;
}
/* Runde 70 (Bugreport Toby, /crewler/4: "Avatar nicht größer anzeigbar") -
   das Bild ist jetzt klickbar und öffnet dieselbe Lightbox-Optik wie die
   Foto-/Ankündigungs-Anhänge (siehe .photo-lightbox-* weiter unten, sowie
   crewler-detail.js). Cursor + dezenter Hover-Effekt signalisieren die
   Klickbarkeit, die vorher komplett fehlte. */
.crewler-detail-avatar.is-clickable {
    cursor: zoom-in;
    transition: opacity .15s ease;
}
.crewler-detail-avatar.is-clickable:hover {
    opacity: .85;
}
.crewler-detail-email {
    color: var(--muted-text);
    font-size: 15px;
}

/* Runde 32 (Toby: WhatsApp- und Brief-Icon hinter Telefonnummer/E-Mail in
   der Verwalter-Detailansicht eines Crewlers): reine Icon-Links direkt
   neben Telefonnummer/E-Mail statt eigener Buttons, damit sie sich
   unauffällig in Zeile/Tabelle einfügen. Whatsapp-Icon nutzt die
   bestehende .trcrew-whatsapp-link-Farbe (Markengrün), das Brief-Icon
   bekommt bewusst die Akzentfarbe statt ebenfalls Grün, damit die beiden
   Kontaktwege optisch unterscheidbar bleiben. */
.crewler-detail-contact-icon {
    margin-left: 6px;
}
.crewler-detail-mail-icon,
.crewler-detail-mail-icon:visited {
    color: var(--accent-color) !important;
}
.crewler-detail-mail-icon:hover {
    opacity: .8;
}
.crewler-info-table.ui.table td:first-child {
    width: 220px;
    color: var(--muted-text);
    font-weight: 600;
}
.crewler-info-table.ui.table td i.icon {
    color: var(--accent-color);
    margin-right: 4px;
}

/* ---- Crewler-Liste: Avatar-Spalte, Name als Modal-Auslöser, Info-
   Modalbox (Runde 58, Toby: Avatar + Rang in der Liste, Klick öffnet eine
   Modalbox mit den wichtigsten Infos) ---- */
.crewler-list-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    object-fit: cover;
    background-color: var(--box-bg);
    display: block;
}
/* Runde 79 (Toby: "das Profilbild in einer Modalbox öffnen wenn man
   darauf klickt") - dieselbe Klick-/Hover-Optik wie beim bereits
   klickbaren Avatar auf der Detailseite (.crewler-detail-avatar.is-clickable,
   Runde 70), nur auf den kleinen Listen-Avatar angewendet. */
.crewler-list-avatar.is-clickable {
    cursor: zoom-in;
    transition: opacity .15s ease;
}
.crewler-list-avatar.is-clickable:hover {
    opacity: .8;
}
/* Runde 79 (Toby: "Tabelle sortierbar machen") - Semantic UIs natives
   .ui.sortable.table-Modul liefert per reinem CSS bereits Cursor, Hover-
   Highlight und Sortierpfeil (:after-Pseudoelement je nach .ascending/
   .descending) - hier nur ergänzt um Dark-Mode-Overrides, da die
   Original-Regeln feste helle rgba(0,0,0,...)-Farben für Hintergrund UND
   Text der .sorted-Spalte setzen (sonst exakt dieselbe Fehlerklasse wie
   die wiederholt aufgetretenen "Text bleibt schwarz im Dunkelmodus"-Bugs
   bei nativen Semantic-UI-Komponenten, siehe u.a. Runde 39/76). Höhere
   Klassenzahl in den Selektoren ist hier bewusst nötig, um Semantic UIs
   gleich spezifische .sorted-Regeln zuverlässig zu überschreiben. */
body.dark .ui.sortable.table thead th {
    background-color: #1e2124;
    color: var(--text-color);
    border-left-color: var(--border-color);
}
body.dark .ui.sortable.table thead th:hover,
body.dark .ui.sortable.table thead th.sorted,
body.dark .ui.sortable.table thead th.sorted:hover {
    background-color: #2a2f34;
    color: var(--text-color);
}
/* Runde 60 (Toby: "die Spalte 'Rang' muss platzsparender aufgesetzt
   werden") - Dropdown + Ändern-Button in EINER Zeile statt (wie bisher)
   Label, Dropdown und Button untereinander gestapelt; das Dropdown
   bekommt eine feste, knappe Breite statt die volle Zellenbreite
   einzunehmen, sonst wird der Button darunter umgebrochen. */
.crewler-role-form {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: nowrap;
}
.crewler-role-select {
    width: 100px;
}
.crewler-rang-cell {
    white-space: nowrap;
}
.crewler-name-link {
    cursor: pointer;
    color: var(--accent-color);
    text-decoration: none;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
}
.crewler-name-link:hover {
    text-decoration: underline;
}
/* Eigene Karte statt eines Bildes innerhalb des dunklen Lightbox-Overlays
   (.photo-lightbox-overlay wird 1:1 wiederverwendet, siehe Vorlage) - im
   normalen Karten-Look der Anwendung (.trcard), damit sie sich nicht wie
   ein Fremdkörper anfühlt. */
.crewler-info-modal {
    position: relative;
    background: var(--box-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 4px;
    padding: 28px;
    width: 100%;
    max-width: 480px;
    max-height: 88vh;
    overflow-y: auto;
}
.crewler-info-modal-header {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 12px;
}
.crewler-info-modal-avatar {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    object-fit: cover;
    background-color: var(--box-bg);
    border: 3px solid var(--accent-color);
    flex-shrink: 0;
}
.crewler-info-modal .ui.button {
    margin-top: 10px;
}

/* ---- Theme-/Sprachumschalter im Header ---- */
.header-toggle {
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* ---- Benachrichtigungsglocke im Header (Runde 31) ---- */
.notification-bell-trigger {
    position: relative;
    display: inline-flex;
    align-items: center;
}
.notification-bell-badge {
    position: absolute;
    top: -6px;
    right: -8px;
    background: var(--danger-color);
    color: #fff;
    font-size: 10px;
    font-weight: bold;
    line-height: 1;
    padding: 3px 5px;
    border-radius: 100px;
    min-width: 16px;
    text-align: center;
}
/* Runde 99 (Toby: Badges an "Alle Crewler" bei wartenden Freischaltungen
   und an "Fahrtkosten verwalten" bei offenen Einreichungen) - dieselbe
   Warnfarbe/Optik wie .notification-bell-badge oben, aber bewusst KEINE
   absolute Positionierung: die Glocke oben sitzt über einem einzelnen Icon,
   diese Badges hängen dagegen direkt hinter dem Linktext eines normalen
   Dropdown-Menüpunkts (z.B. "Alle Crewler (3)") - dort wäre eine absolut
   positionierte Ecke über dem Fließtext unpassend. */
/* Runde 99 (Betreute-Positionen-Abfrage-Modalbox nach einer Beförderung
   zum Supervisor, siehe templates/layout/main.php) - Speichern-Button und
   das separate "Später festlegen"-Formular optisch als eine zusammen-
   gehörige Aktionszeile, mit etwas Abstand zueinander. */
.supervisor-prompt-actions {
    margin-top: 4px;
}
.supervisor-prompt-skip-form {
    margin-top: 10px;
}
.nav-menu-badge {
    display: inline-block;
    background: var(--danger-color);
    color: #fff;
    font-size: 10px;
    font-weight: bold;
    line-height: 1;
    padding: 3px 6px;
    border-radius: 100px;
    min-width: 16px;
    text-align: center;
    margin-left: 6px;
    vertical-align: middle;
}
.notification-bell-menu.menu {
    width: 320px;
    max-width: 90vw;
    max-height: 420px;
    overflow-y: auto;
    padding: 4px 0;
}
.notification-bell-menu .header {
    padding: 10px 14px 8px;
    font-size: 13px;
    text-transform: none;
    color: var(--text-color) !important;
}
.notification-mark-all-link {
    background: none;
    border: none;
    color: var(--accent-color);
    font-size: 12px;
    cursor: pointer;
    padding: 0;
}
.notification-bell-entry {
    display: block !important;
    white-space: normal !important;
    padding: 8px 14px !important;
    border-top: 1px solid var(--border-color);
}
.notification-bell-entry.is-unread { background: rgba(0, 172, 255, 0.07); }
.notification-bell-entry-title { font-size: 13px; font-weight: 600; }
.notification-bell-entry-body { font-size: 12px; opacity: .8; margin-top: 2px; }
.notification-bell-entry-time { font-size: 11px; opacity: .6; margin-top: 3px; }
.notification-empty {
    padding: 10px 14px !important;
    font-size: 13px;
    opacity: .75;
}
.notification-bell-all {
    text-align: center;
    font-size: 12px;
    border-top: 1px solid var(--border-color);
    padding: 8px !important;
    color: var(--accent-color) !important;
}

/* ---- Vollständige Benachrichtigungsliste (/benachrichtigungen) ---- */
.notification-list-item.content { display: block; }
.notification-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent-color);
    flex-shrink: 0;
}

/* ---- Toast-Benachrichtigungen unten rechts ---- */
#toast-container {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 99999;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 340px;
}

.toast {
    background-color: var(--popup-bg);
    color: var(--popup-text);
    padding: 12px 16px;
    border-radius: 8px;
    box-shadow: 0 4px 14px rgba(0,0,0,.3);
    font-size: 14px;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity .25s ease, transform .25s ease;
    border-left: 4px solid var(--accent-color);
}

.toast.show { opacity: 1; transform: translateY(0); }
.toast.toast-success { border-left-color: var(--success-color); }
.toast.toast-error { border-left-color: var(--danger-color); }
.toast.toast-warning { border-left-color: var(--warning-color); }
.toast .toast-close { margin-left: auto; cursor: pointer; opacity: .7; }
.toast .toast-close:hover { opacity: 1; }

/* ---- Verfügbarkeits-Seite ---- */
/* Runde 85, Toby: "Mehr abstand zwischen [Hinweistext] und der ersten Box" -
   der Hinweistext direkt darüber saß ohne Abstand nach unten fast bündig auf
   der ersten .availability-day-Box. */
.availability-days {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-top: 20px;
    margin-bottom: 18px;
}

.availability-day-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 12px;
}

.availability-day-date {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.availability-weekday {
    font-size: 17px;
    font-weight: bold;
}

.availability-datum {
    font-size: 14px;
    opacity: .75;
}

/* Runde 83: Liste der Personen, die Interesse an einem
   Fahrgemeinschafts-Eintrag angemeldet haben. */
.carpool-interest-list {
    font-size: 13px;
    opacity: .8;
    margin-top: 4px !important;
}
.carpool-interest-list .icon {
    color: var(--accent-solid);
}

.availability-allday-toggle label {
    color: var(--text-color) !important;
}

.availability-ranges {
    border-top: 1px solid var(--border-color);
    padding-top: 12px;
    margin-top: 4px;
}

.availability-range-row {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    margin-bottom: 10px;
}

.availability-range-field { margin: 0; }
.availability-range-field label {
    display: block;
    font-size: 12px;
    opacity: .8;
    margin-bottom: 4px;
}

.availability-remove-btn {
    color: var(--danger-color) !important;
    background: none !important;
    box-shadow: none !important;
}

@media (max-width: 480px) {
    .availability-range-row { flex-wrap: wrap; }
}

/* ---- Verfügbarkeits-Kalenderansicht (Runde 31) ---- */
.availability-view-toggle .button {
    background: var(--box-bg);
    color: var(--text-color);
}
.availability-view-toggle .button.active {
    background: var(--accent-solid) !important;
    color: #fff !important;
}

/* Runde 101 (Toby: "Die Legende soll unter jeden Monat und besser
   sichtbar rechtsbündig gestaltet werden") - vorher eine einzelne, eher
   unauffällig gedimmte (opacity .85) Zeile oberhalb aller Monate,
   linksbündig. Jetzt: rechtsbündig (justify-content: flex-end), volle
   Deckkraft + etwas fettere Schrift für bessere Sichtbarkeit, sowie eine
   dezente Trennlinie zum Kalendergitter darüber, da die Legende jetzt
   direkt im selben Monats-Segment sitzt statt in eigenem Abstand davor. */
.availability-calendar-legend {
    display: flex;
    justify-content: flex-end;
    gap: 18px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 10px;
    border-top: 1px solid var(--border-color);
    font-size: 13px;
    font-weight: 600;
}
.calendar-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.calendar-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
}
.calendar-dot.has-availability { background: var(--success-color); }
.calendar-dot.needs-availability { background: var(--warning-color); }

.availability-calendar-month { margin-bottom: 18px; }

.availability-calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
}

.calendar-weekday-label {
    text-align: center;
    font-size: 12px;
    font-weight: bold;
    opacity: .7;
    padding-bottom: 4px;
}

.calendar-cell {
    /* Runde 79 (Toby-Bugreport, Mobilansicht: "Der Kalender ist Mobil
       zerstört, weil eine Veranstaltung die Fensterbreite sprengt"):
       .calendar-cell ist ein Grid-Item von .availability-calendar-grid
       UND gleichzeitig selbst ein Flex-Container. Grid-/Flex-Items haben
       per Spezifikation einen impliziten "min-width: auto", der bei
       nicht umbrechendem Inhalt (siehe .calendar-chip: white-space:nowrap)
       zur MINIMALEN Content-Breite wird - das hebelt sowohl die
       Grid-Spaltenbreite (1fr) als auch das eigentlich schon vorhandene
       text-overflow:ellipsis am Chip aus und sprengt auf schmalen
       Bildschirmen die gesamte Seitenbreite. Klassischer, gut
       dokumentierter CSS-Grid/Flexbox-Fallstrick - Fix: min-width:0
       explizit setzen (hier UND am Chip selbst, siehe unten), damit die
       Grid-Spalte tatsächlich das letzte Wort über die Breite behält. */
    min-width: 0;
    min-height: 64px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 4px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.calendar-cell-empty { border: none; }
.calendar-cell.is-today { border-color: var(--accent-color); border-width: 2px; }

.calendar-cell-daynum { font-size: 12px; opacity: .7; }

.calendar-chip {
    display: block;
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
    font-size: 11px;
    line-height: 1.3;
    padding: 2px 5px;
    border-radius: 4px;
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.calendar-chip.has-availability {
    /* Runde 79 (Toby: "die Farbe ist schlecht gewählt"): vorher blasser
       grüner/gelber Text auf ebenso blassem, nur 15-18% deckendem
       Farbton derselben Farbe - rechnerisch nur ~1,4:1 (needs) bzw.
       ~2:1 (has) Kontrast, weit unter dem WCAG-Richtwert von 3:1 für
       UI-Komponenten. Jetzt dieselbe bereits etablierte "volle Farbe als
       Hintergrund + kontrastierende Textfarbe"-Optik wie bei den
       Status-Badges der Crewler-Liste (aktiv/wartend, siehe
       crewler_index.php) statt einer neuen, ungetesteten Farbkombination. */
    background: var(--success-color);
    color: #fff;
}
.calendar-chip.needs-availability {
    background: var(--warning-color);
    color: #000;
}
.calendar-chip .icon { margin-right: 2px; }

@media (max-width: 600px) {
    .calendar-cell { min-height: 48px; }
    .calendar-weekday-label { font-size: 10px; }
    .calendar-chip { font-size: 10px; padding: 1px 3px; }
}

/* ---- Personaleinteilung (Veranstaltungs-Übersicht) ---- */
.assignment-days {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: 16px;
}

.assignment-day-header {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 14px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border-color);
}

.assignment-slots {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.assignment-slot {
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 12px 14px;
    background: rgba(127, 127, 127, .04);
}

.assignment-slot-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}

.assignment-count-badge {
    background-color: var(--warning-color) !important;
    color: #000 !important;
    white-space: nowrap;
}
.assignment-count-badge.is-full {
    background-color: var(--success-color) !important;
    color: #fff !important;
}

.assignment-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}

.assignment-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background-color: var(--accent-solid);
    color: #fff;
    border-radius: 999px;
    padding: 4px 6px 4px 12px;
    font-size: 13px;
}
.assignment-chip form { margin: 0; line-height: 1; }
.assignment-chip button {
    background: rgba(255, 255, 255, .25);
    border: none;
    color: #fff;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    cursor: pointer;
    line-height: 1;
    font-size: 13px;
    padding: 0;
}
.assignment-chip button:hover { background: rgba(255, 255, 255, .45); }

.assignment-details { margin-top: 8px; }
.assignment-details summary {
    cursor: pointer;
    color: var(--muted-text);
    font-size: 13px;
}
.assignment-details .candidate-list { margin-top: 8px; }

/* ---- Dashboard: "Anstehende Veranstaltungen"-Karten ---- */
.dashboard-event-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.dashboard-event-card {
    display: flex;
    gap: 14px;
    align-items: center;
    padding: 10px 14px;
    background: var(--box-bg);
    border-left: 4px solid var(--accent-color);
    border-radius: 6px;
    cursor: pointer;
    transition: transform .12s ease, box-shadow .12s ease;
}
.dashboard-event-card:hover {
    transform: translateX(2px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
}
.dashboard-event-card-static {
    cursor: default;
}
.dashboard-event-card-static:hover {
    transform: none;
    box-shadow: none;
}
.dashboard-event-date {
    flex: 0 0 auto;
    width: 50px;
    height: 50px;
    border-radius: 8px;
    background: var(--accent-solid);
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1.15;
}
.dashboard-event-day {
    font-size: 17px;
    font-weight: bold;
}
.dashboard-event-month {
    font-size: 10px;
    text-transform: uppercase;
    opacity: .9;
}
.dashboard-event-body {
    flex: 1;
    min-width: 0;
}
.dashboard-event-top {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.dashboard-event-top .ui.label {
    font-size: 10px;
    padding: .35em .6em;
}
a.dashboard-event-name,
span.dashboard-event-name {
    font-weight: bold;
    font-size: 15px;
    color: var(--text-color);
    text-decoration: none;
}
a.dashboard-event-name:hover {
    color: var(--accent-color);
    text-decoration: underline;
}
.dashboard-event-meta {
    margin-top: 4px;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 13px;
    color: var(--muted-text);
}
.dashboard-location-pill {
    display: inline-flex;
    align-items: center;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
    border-radius: 100px;
    padding: 2px 10px;
}
.dashboard-location-pill a {
    color: var(--accent-color);
    font-size: 12px;
    white-space: nowrap;
}
.dashboard-location-pill .icon { margin-left: 3px; margin-right: 0; }

/* ---- Aktionen-Spalte in Verwaltungstabellen (Positionen,
   Beeintraechtigungen, Verwalter) ---- */
.table-actions {
    display: flex;
    align-items: center;
    gap: 6px;
}
.table-actions form { margin: 0; }
.table-actions .ui.icon.button {
    box-shadow: none;
}

/* Runde 71 (Toby-Vorschlag: "Schadensmeldung bei der
   Ausrüstungsverleihliste") - kompakte Checkbox+Notiz direkt im
   "Zurückgeben"-Mini-Formular der Tabellenzeile, damit die Schadensmeldung
   Teil desselben Klicks bleibt statt ein separater zweiter Schritt zu sein. */
.equipment-return-form {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin: 0;
}
.equipment-return-damage-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
}
.equipment-return-damage-toggle .js-equipment-damage-note {
    width: 150px;
    padding: 4px 6px;
    font-size: 12px;
}

/* ---- Veranstaltungsseiten-Kopfzeile (Runde 34, Toby: "Adresse unter den
   veranstaltungsnamen ... darunter dann die Whatsappgruppe. Organisiere
   die Buttons oben rechts neu und platzsparender") ---- */
.event-header-location,
.event-header-whatsapp {
    font-size: 14px;
    opacity: .85;
    margin-top: 2px;
}
/* Runde 100 (Toby: "optional soll man Links zu Webseite, Shop und
   Instagram angeben können") - bis zu drei Links nebeneinander statt
   jeweils eigener Zeile wie beim WhatsApp-Link oben, mit etwas Abstand
   zueinander und Umbruch auf schmalen Bildschirmen. Eigene Link-Farbe
   (Akzentfarbe statt dem festen WhatsApp-Grün von .trcrew-whatsapp-link) -
   diese drei Links haben keine eigene Markenfarbe wie WhatsApp. */
.event-header-links {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    font-size: 14px;
    opacity: .85;
    margin-top: 2px;
}
.event-header-social-link,
.event-header-social-link:visited {
    color: var(--accent-color) !important;
}
.event-header-social-link:hover { text-decoration: underline; }
.event-header-social-link i.icon { margin-right: 4px; }
.event-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.event-header-actions form {
    margin: 0;
    display: flex;
}

/* Runde 96 (Toby: "Es gibt jetzt so viele Buttons [...] kann man da eine
   neue Art Menü einbauen?") - Duplizieren/Löschen bleiben aus
   Sicherheitsgründen echte POST-Formulare mit CSRF-Schutz, sollen aber
   optisch wie ein normaler Punkt im Aktionen-Menü aussehen.
   Das <form> selbst trägt die Semantic-UI-Klasse "item" (bekommt dadurch
   automatisch Innenabstand/Hover/Dunkelmodus-Farben wie jeder andere
   Menüpunkt, siehe body.dark .ui.dropdown .menu .item weiter oben), der
   Button darin wird komplett zurückgesetzt ("all: unset") und auf volle
   Breite gebracht, damit er sich unsichtbar in den Menüpunkt einfügt statt
   wie ein eigenes Formularelement auszusehen. Höhere Spezifität als die
   allgemeine ".event-header-actions form"-Regel oben, damit hier gezielt
   "display:block" statt "display:flex" gilt.

   Runde 97 (Toby: "es ist noch etwas fehlerhaft"): genau dieser
   automatische Innenabstand war der Fehler - Semantic UI legt auf JEDES
   ".ui.dropdown .menu > .item" bereits per "!important"
   "padding: .78571429rem 1.14285714rem" (siehe semantic.css). Die Zeile
   "padding: ... " hier auf dem BUTTON hat genau diesen Abstand ein
   zweites Mal aufaddiert, weil der Button ja INNERHALB des bereits so
   gepolsterten Formulars sitzt - dadurch wirkten Duplizieren/Löschen im
   Menü sichtbar höher/eingerückter als die reinen Link-Einträge
   (Crewbadges/Fotos verwalten/Druckansicht/Crew einteilen). Aus
   demselben Grund wurde auch die eigene ":hover"-Regel unten entfernt -
   Semantic wendet den Hover-Hintergrund schon auf das Formular selbst an
   (bzw. app.css oben im Dunkelmodus), ein zweiter, überlagernder
   Hover-Hintergrund auf dem Button machte den Hover-Effekt dort sichtbar
   dunkler als bei den übrigen Einträgen. "padding" komplett entfernt
   (bleibt dank "all: unset" bei 0, der äußere, bereits gepolsterte
   Formular-Rahmen reicht) - stattdessen "gap" für den Abstand zwischen
   Icon und Text, weil Semantics eigene Abstandsregel dafür
   (".ui.dropdown .menu > .item > .icon") ein DIREKTES Kind von ".item"
   voraussetzt und unser Icon jetzt aber ein Enkelkind ist (item=Formular
   -> Button -> Icon), die Regel also ins Leere läuft. */
.event-header-actions .event-menu-form {
    margin: 0;
    display: block;
    width: 100%;
}
.event-header-actions .event-menu-form button {
    all: unset;
    display: flex;
    align-items: center;
    gap: .78571429rem;
    width: 100%;
    box-sizing: border-box;
    cursor: pointer;
    font: inherit;
    color: inherit;
}

/* ---- Veranstaltungslogo (Runde 36, Toby: "Beim erstellen von
   veranstaltungen optional ein logo der Veranstaltung hochladen") ---- */
.event-header-logo {
    max-height: 52px;
    max-width: 120px;
    object-fit: contain;
    border-radius: 6px;
    flex: none;
}
.event-logo-thumb {
    max-height: 60px;
    max-width: 140px;
    object-fit: contain;
    border-radius: 6px;
    background: var(--box-bg);
    padding: 4px;
}
.event-list-logo {
    width: 32px;
    height: 32px;
    object-fit: contain;
    border-radius: 4px;
    vertical-align: middle;
    margin-right: 8px;
}

/* Runde 122 (Toby: "Nach dem Event sollen alle Texte durchgestrichen
   sein, aber die Links noch funktionieren"): Name/Datum/Ort einer
   vorüber gegangenen Veranstaltung werden optisch durchgestrichen -
   text-decoration wirkt rein auf die Darstellung, das darin liegende
   <a> bleibt normal klickbar/funktionsfähig. Bewusst NICHT auf den
   Status-Tag angewendet (der reagiert stattdessen selbst mit einem
   eigenen "Abgeschlossen"-Label, siehe eventDisplayStatus() in
   helpers.php) und NICHT auf den "Crew einteilen"-Button (der wird
   stattdessen komplett deaktiviert - dafür genügt Semantic UIs
   eigene ".disabled"-Klasse auf dem Button, siehe events_index.php). */
.event-list-text-past {
    text-decoration: line-through;
    opacity: .7;
}

/* ---- Legal Seiten ---- */
/* Runde 96 (Toby-Screenshot: bei großer Systemschrift auf dem Handy
   entstanden auf der Datenschutz-/Impressum-Seite riesige, hässliche
   Lücken zwischen den Wörtern). Ursache: "text-align: justify" auf sehr
   schmalen Zeilen mit wenigen Wörtern (bei stark hochskalierter
   Systemschrift passen oft nur 2-3 Wörter je Zeile) - Justify dehnt dann
   genau diese wenigen Wortzwischenräume auf, um die Zeile trotzdem bis
   zum rechten Rand zu füllen. Fix: linksbündig statt Blocksatz - sieht
   bei jeder Schriftgröße sauber aus, kein Sonderfall für große Schrift
   nötig.
*/
.legal-text {
    text-align: left;
    font-size: 15px;
    line-height: 1.6;
}
.legal-text h2 { margin-top: 1.6em; }

/* Runde 110 (Toby: "Überarbeite die ganze AGB-Seite, mach das ordentlicher,
   nicht nur mit minusen aufzählen etc. beachte auch die responsive
   seite"): templates/legal/datenschutz.php nutzt jetzt echte <h3>-Anker
   (statt reiner Fließtext-Zwischenüberschriften) plus ein
   Inhaltsverzeichnis (.help-toc, siehe dort) - "scroll-margin-top" analog
   zu .help-toc/.help-topic weiter oben, da der Seitenkopf sticky ist und
   sonst die angesprungene Überschrift verdecken würde. Die vormaligen
   "- Text<br>"-Pseudo-Listen sind jetzt echte <ul><li>-Listen; deren
   Standard-Einrückung wird hier bewusst etwas knapper gehalten, damit auf
   schmalen Bildschirmen (siehe @media-Regel weiter unten) nicht unnötig
   Platz für den Text verloren geht. */
.legal-text h3 {
    scroll-margin-top: 90px;
    margin-top: 1.8em;
    margin-bottom: .6em;
}
.legal-text h3 i.icon {
    color: var(--accent-color);
    margin-right: 4px;
}
.legal-text ul {
    margin: 0 0 1em;
    padding-left: 22px;
}
.legal-text ul li {
    margin-bottom: 8px;
}
.legal-text ul li:last-child {
    margin-bottom: 0;
}

@media (max-width: 500px) {
    .legal-text ul {
        padding-left: 18px;
    }
}

/* ---- Crewfotos (Runde 15) ---- */
.photo-count-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 2px 10px;
    font-size: 12px;
    opacity: .9;
}
.photo-count-pill .icon { margin: 0; }

/* ---- Dashboard-Erweiterungen (Runde 19, Feedback: "Vorschläge was man
   auf die Startseite packen könnte") ---- */
.dashboard-quickactions-card {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.dashboard-quickactions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* Kennzahlen-Kacheln (Runde 39, Toby: "die box oben ... ist alles andere
   als schön gemacht"): ersetzt die vorherige Semantic-UI-
   `.ui.statistics`-Leiste, die im Dunkelmodus kaum lesbaren dunkelgrauen
   Text auf dunklem Grund erzeugte (Semantic UIs Statistik-Komponente
   kennt unser Theming-Variablensystem nicht) und durch das reine
   `justify-content:space-between` neben den Aktions-Buttons einen großen,
   leeren Zwischenraum hatte. Stattdessen dasselbe bewährte Kachel-Muster
   wie bei `.dashboard-event-card`/`.dashboard-openslot-item`: eigene
   Kacheln mit `background:var(--box-bg)`, farbigem Icon-Badge und
   Theme-bewussten Text-Variablen, damit die Zahlen in Hell- und
   Dunkelmodus gleichermaßen gut lesbar sind. */
.dashboard-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px;
}
.dashboard-stat-tile {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    background: var(--box-bg);
    border-left: 4px solid var(--accent-color);
    border-radius: 6px;
}
.dashboard-stat-icon {
    flex: 0 0 auto;
    width: 42px;
    height: 42px;
    border-radius: 8px;
    background: var(--accent-solid);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
}
.dashboard-stat-icon .icon { margin: 0; }
.dashboard-stat-value {
    font-size: 26px;
    font-weight: bold;
    line-height: 1.1;
    color: var(--text-color);
}
.dashboard-stat-label {
    margin-top: 2px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--muted-text);
}
/* Wartende Freischaltungen > 0: dieselbe Aufmerksamkeits-Farbe wie bei
   offenen Positionen (.dashboard-openslot-item) und dem
   Geburtstags-/Feedback-Banner, damit sofort auffällt, wenn Handlungsbedarf
   besteht. */
.dashboard-stat-tile-attention {
    border-left-color: var(--warning-color);
}
.dashboard-stat-tile-attention .dashboard-stat-icon {
    background: var(--warning-color);
}

.dashboard-openslot-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.dashboard-openslot-item {
    display: flex;
    gap: 12px;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    background: var(--box-bg);
    border-left: 4px solid var(--warning-color);
    border-radius: 6px;
    transition: transform .12s ease, box-shadow .12s ease;
}
.dashboard-openslot-item:hover {
    transform: translateX(2px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
}
.dashboard-openslot-body { min-width: 0; }
.dashboard-openslot-top {
    font-weight: bold;
    font-size: 14px;
    color: var(--text-color);
}
.dashboard-openslot-meta {
    margin-top: 2px;
    font-size: 12px;
    color: var(--muted-text);
}
.dashboard-openslot-badge {
    flex: 0 0 auto;
    white-space: nowrap;
    background: var(--bg-color);
    border: 1px solid var(--border-color);
    border-radius: 100px;
    padding: 3px 12px;
    font-size: 12px;
    color: var(--muted-text);
}

.dashboard-announcement-list {
    display: flex;
    flex-direction: column;
}
.dashboard-announcement-item {
    padding: 10px 0;
    border-bottom: 1px solid var(--border-color);
}
.dashboard-announcement-item:last-child { border-bottom: none; padding-bottom: 0; }
.dashboard-announcement-title { font-weight: bold; font-size: 14px; }
.dashboard-announcement-meta {
    margin-top: 2px;
    font-size: 12px;
    color: var(--muted-text);
}

.dashboard-alert-card {
    border-left: 4px solid var(--warning-color) !important;
}

/* Runde 32 (Toby: "Warne Supervisoren auf der Startseite mit einem
   auffälligen banner, wenn ein Crewler ... geburtstag hatte") - bewusst
   volltonfarbig mit Farbverlauf statt der schlichten linken Akzentlinie
   wie bei .dashboard-alert-card oben, damit das Banner wirklich
   "auffällig" ist und nicht mit den übrigen, neutralen Dashboard-Kacheln
   verwechselt wird. Feste Farbwerte statt Theme-Variablen (wie schon bei
   .trcrew-whatsapp) - ein bewusst "buntes" Sonderelement, kein normales
   UI-Element im sonstigen App-Farbschema, daher in beiden Themes gleich. */
.dashboard-birthday-card {
    background: linear-gradient(135deg, #ff5fa2, #7c5cff) !important;
    border: none !important;
    color: #fff;
}
.dashboard-birthday-card h3.ui.header {
    color: #fff !important;
}
.dashboard-birthday-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 10px;
}
.dashboard-birthday-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    background: rgba(255, 255, 255, .18);
    border-radius: 6px;
    color: #fff !important;
}
.dashboard-birthday-item:hover {
    background: rgba(255, 255, 255, .3);
}
.dashboard-birthday-badge {
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    opacity: .95;
}
.dashboard-alert-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 10px;
}
.dashboard-alert-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    background: var(--box-bg);
    border-radius: 6px;
}

.dashboard-photo-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.dashboard-photo-thumb {
    display: block;
    width: 64px;
    height: 64px;
    border-radius: 6px;
    overflow: hidden;
    border: 1px solid var(--border-color);
}
.dashboard-photo-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.dashboard-hint-card {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
}
.dashboard-hint-body {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}
.dashboard-hint-icon {
    flex: 0 0 auto;
    font-size: 26px !important;
    color: var(--accent-color);
}
.dashboard-hint-title {
    font-family: var(--font-main);
    font-size: 15px;
}
.dashboard-hint-text {
    margin-top: 2px;
    font-size: 13px;
    color: var(--muted-text);
}

.photo-dropzone {
    border: 2px dashed var(--border-color);
    border-radius: 8px;
    padding: 30px 20px;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s, background-color .15s;
    margin-bottom: 10px;
}
.photo-dropzone:hover,
.photo-dropzone.dragover {
    border-color: var(--accent-color);
    background-color: var(--box-bg);
}
.photo-dropzone > i.icon {
    font-size: 2em;
    color: var(--accent-color);
    margin-bottom: 8px;
}
.photo-dropzone p {
    opacity: .85;
    font-size: 13px;
    max-width: 480px;
    margin: 0 auto 14px;
}

.photo-upload-progress { margin-top: 14px; }
.photo-upload-log {
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
    max-height: 160px;
    overflow-y: auto;
    font-size: 13px;
}
.photo-upload-log li {
    padding: 3px 0;
    border-bottom: 1px solid var(--border-color);
}
.photo-upload-log-ok { color: #21ba45; }
.photo-upload-log-error { color: var(--danger-color); }

.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
    margin-top: 10px;
}
.photo-tile {
    position: relative;
    aspect-ratio: 1 / 1;
    border-radius: 6px;
    overflow: hidden;
    background-color: var(--box-bg);
    border: 1px solid var(--border-color);
}
.photo-tile-link {
    display: block;
    width: 100%;
    height: 100%;
}
.photo-tile img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .15s;
}
.photo-tile:hover img { transform: scale(1.04); }
.photo-tile-delete {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, .6);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity .15s, background-color .15s;
}
.photo-tile:hover .photo-tile-delete { opacity: 1; }
.photo-tile-delete:hover { background: var(--danger-color); }
.photo-tile-delete .icon { margin: 0; }

/* Runde 80 (Foto-Zähler-Diskrepanz, siehe Docblock von
   EventPhotoService::originalFileExists()): Kachel für eine DB-Zeile ohne
   zugehörige Datei - statt eines stillen kaputten Bild-Symbols ein klar
   erkennbarer, dezent gestrichelter Platzhalter samt Warn-Hinweistext
   über dem Grid, damit ein Systemadmin verwaiste Einträge findet und ganz
   normal über den bereits vorhandenen Löschen-Button entfernen kann. */
.photo-missing-hint {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    color: var(--danger-color);
    font-size: 13px;
}
.photo-tile-missing { background-color: transparent; border-style: dashed; }
.photo-tile-missing-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    color: var(--muted-text);
    text-align: center;
    padding: 8px;
}
.photo-tile-missing-placeholder .icon { color: var(--danger-color); font-size: 20px; margin: 0; }
.photo-tile-missing-placeholder span { font-size: 11px; line-height: 1.3; }

.photo-lightbox-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .88);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.photo-lightbox-overlay[hidden] {
    display: none;
}
.photo-lightbox {
    position: relative;
    max-width: 92vw;
    max-height: 92vh;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.photo-lightbox-image {
    max-width: 92vw;
    max-height: 78vh;
    object-fit: contain;
    border-radius: 4px;
    box-shadow: 0 4px 24px rgba(0, 0, 0, .5);
}
.photo-lightbox-footer {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    margin-top: 14px;
    color: #fff;
    flex-wrap: wrap;
    text-align: center;
}
.photo-lightbox-close {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 36px;
    height: 36px;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    cursor: pointer;
    z-index: 1;
}
.photo-lightbox-close:hover { background: rgba(255, 255, 255, .25); }
.photo-lightbox-nav {
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    font-size: 18px;
    cursor: pointer;
}
.photo-lightbox-nav:hover { background: rgba(255, 255, 255, .25); }
.photo-lightbox-prev { left: 24px; }
.photo-lightbox-next { right: 24px; }

/* ---- "Schau auf TRgallery.net vorbei"-Hinweis, leere Crewfotos-Liste
   (Runde 18) ---- */
.photos-external-hint {
    margin-top: 22px;
    padding: 22px;
    text-align: center;
    background: rgba(127, 127, 127, .06);
    border: 1px dashed var(--border-color);
    border-radius: 6px;
}
.photos-external-hint .icon { font-size: 28px; opacity: .7; margin-bottom: 8px; }
.photos-external-hint p { margin: 0 0 14px 0; opacity: .9; }

/* ---- Wartungsmodus-Landingpage (Runde 18) ---- */
.maintenance-page {
    max-width: 480px;
    margin: 12vh auto 0;
    padding: 40px 30px;
    text-align: center;
    background-color: var(--box-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 4px;
}
.maintenance-logo { max-width: 160px; margin-bottom: 24px; }
.maintenance-page h1 { margin: 0 0 14px 0; }
.maintenance-page p { opacity: .9; line-height: 1.5; }

/* Runde 91 (Toby: "Im Wartungsmodus soll unten rechts in der ecke, klein
   und unauffällig der Link zum Login sein.") - fixiert statt in den
   normalen Seitenfluss gesetzt, damit er unabhängig von der Höhe der
   .maintenance-page-Box immer in der Ecke des Bildschirms bleibt, auch bei
   sehr kurzen Wartungstexten. Bewusst gedämpfte Opazität/kleine Schrift im
   Ruhezustand ("unauffällig"), beim Hover/Fokus voll sichtbar, damit er
   trotzdem bedienbar bleibt. */
.maintenance-login-link {
    position: fixed;
    right: 16px;
    bottom: 12px;
    font-size: 12px;
    color: var(--text-color);
    opacity: .45;
    text-decoration: none;
}
.maintenance-login-link:hover,
.maintenance-login-link:focus {
    opacity: .9;
    text-decoration: underline;
}

/* Runde 80 (Toby: "gestalte die Seite '...keine Berechtigung...' bisschen
   schöner"): dieselbe Box-Optik wie .maintenance-page (siehe oben), damit
   eigenständige Seiten ohne normales Layout durchgängig gleich aussehen -
   nur mit einem Warn-/Schloss-Icon statt Logo, da hier kein Wartungsmodus,
   sondern eine konkrete Zugriffsverweigerung gemeint ist. */
.error-page {
    max-width: 480px;
    margin: 12vh auto 0;
    padding: 40px 30px;
    text-align: center;
    background-color: var(--box-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--danger-color);
    border-radius: 4px;
}
.error-page-icon { font-size: 42px; color: var(--danger-color); margin-bottom: 18px; }
.error-page h1 { margin: 0 0 14px 0; }
.error-page p { opacity: .9; line-height: 1.5; margin-bottom: 24px; }

/* Runde 140: gestaltete 404-Seite (templates/errors/404.php) - gleiche Box
   wie die 403-Seite, aber im Akzent- statt Warnrot (kein Fehler des
   Nutzers, nur ein toter Link), mit großer "404" als Blickfang. */
.error-page-404 { border-left-color: var(--accent-color); }
.error-page-404 .error-page-icon { color: var(--accent-color); margin-bottom: 12px; }
.error-page-code {
    font-size: 84px;
    line-height: 1;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--accent-color);
    opacity: .9;
    margin-bottom: 6px;
}
.error-page-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;
}
.error-page-actions .ui.button { margin: 0; }
.error-page-secondary { margin: 18px 0 0 !important; font-size: 14px; }
@media (max-width: 520px) {
    .error-page { margin-top: 6vh; padding: 28px 18px; }
    .error-page-code { font-size: 64px; }
}

/* Runde 92 (Onboarding-Bestätigung): dieselbe eigenständige Box-Optik wie
   .maintenance-page/.error-page oben, aber bewusst breiter und links- statt
   zentriert-ausgerichtet für den Fließtext – der Hinweistext kann (da frei
   editierbar, siehe Systemeinstellungen) mehrere Absätze lang sein und
   liest sich linksbündig deutlich besser als zentriert. */
.onboarding-page {
    max-width: 560px;
    margin: 8vh auto 40px;
    padding: 40px 36px;
    text-align: left;
    background-color: var(--box-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 4px;
}
.onboarding-page-icon { font-size: 42px; color: var(--accent-color); text-align: center; margin-bottom: 18px; }
.onboarding-page h1 { text-align: center; margin: 0 0 20px 0; }
.onboarding-text { line-height: 1.6; margin-bottom: 24px; white-space: normal; }
.onboarding-checkbox-row { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 24px; }
.onboarding-checkbox-row input { margin-top: 4px; }
.onboarding-checkbox-row label { line-height: 1.4; }

/* Runde 94 (Toby: Vorschau-Modalbox für den Einweisungstext, "so aussieht
   als ob es echt wäre") - bewusst dieselbe Optik wie .onboarding-page
   oben (Hintergrund/Rahmen/Akzentstreifen), aber ohne dessen feste
   vh-Außenabstände/max-width - die umschließende Semantic-UI-Modalbox
   übernimmt die Größe/Positionierung bereits selbst. */
.onboarding-preview-box {
    padding: 28px 24px;
    background-color: var(--box-bg);
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 4px;
}
.onboarding-preview-box .onboarding-page-icon { margin-bottom: 14px; }
.onboarding-preview-box h1 { text-align: center; font-size: 20px; margin: 0 0 18px 0; }
.onboarding-preview-notice {
    font-size: 12px;
    opacity: .75;
    margin-bottom: 16px;
}

/* ---- Statistik-Seite (Runde 17/18): eigener, schlichter Fortschrittsbalken
   statt Semantic UIs .ui.progress – die Komponente erwartet eine JS-
   Initialisierung (die diese App bewusst nicht einsetzt) und ihr intern
   absolut positionierter Prozent-Text lief bei kleinen Balkenbreiten über
   die Nachbarspalte (siehe Toby-Screenshot, Runde 18). Eigenes Markup mit
   Label NEBEN statt IN dem Balken vermeidet das grundsätzlich. */
.stats-bar { display: flex; align-items: center; gap: 10px; }
.stats-bar-track {
    flex: 1 1 auto;
    min-width: 60px;
    height: 14px;
    background: rgba(127, 127, 127, .2);
    border-radius: 7px;
    overflow: hidden;
}
.stats-bar-fill { height: 100%; background: var(--accent-color); }
.stats-bar-fill.full { background: var(--success-color); }
.stats-bar-label { font-size: 12px; white-space: nowrap; opacity: .85; }

/* ---- Profil-Vervollständigung, neu gestaltet (Runde 75, Toby: "Das
   Profil ist nicht schön gestaltet mit dem balken.") - eigene, deutlich
   auffälligere Optik statt der schlichten .stats-bar/.ui.relaxed.list-
   Kombination aus Runde 31/74: große farbcodierte Prozent-Badge neben
   dem Titel, dickerer Balken mit weichem Verlauf, Checkliste als
   Abzeichen-Chips (Vorbild: .milestone-badge) statt einspaltiger Liste. */
.profile-completion-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.profile-completion-pct-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 52px;
    height: 52px;
    padding: 0 6px;
    border-radius: 50%;
    color: #fff;
    font-size: 17px;
    font-weight: 700;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .18);
}
.profile-completion-pct-badge--low { background: var(--danger-color); }
.profile-completion-pct-badge--mid { background: var(--warning-color); color: #3a2f00; }
.profile-completion-pct-badge--high { background: var(--accent-solid); }
.profile-completion-pct-badge--full { background: var(--success-color); }
.profile-completion-track {
    margin-top: 14px;
    height: 20px;
    border-radius: 10px;
    background: rgba(127, 127, 127, .2);
    overflow: hidden;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, .12);
}
.profile-completion-fill {
    height: 100%;
    border-radius: 10px;
    transition: width .4s ease;
}
.profile-completion-fill--low { background: linear-gradient(90deg, var(--danger-color), var(--warning-color)); }
.profile-completion-fill--mid { background: linear-gradient(90deg, var(--warning-color), var(--accent-solid)); }
.profile-completion-fill--high { background: linear-gradient(90deg, var(--accent-solid), var(--accent-color)); }
.profile-completion-fill--full { background: linear-gradient(90deg, var(--success-color), #59d980); }
.profile-completion-items {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}
.profile-completion-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 12.5px;
    background: transparent;
    border: 1px solid var(--border-color);
    color: var(--muted-text);
}
.profile-completion-item.is-done {
    background: var(--accent-solid);
    border-color: transparent;
    color: #fff;
    font-weight: 600;
}
/* Runde 80 (Toby: "Verlinke die Box 'Verfügbarkeit für mindestens einen
   Termin eingetragen'..."): einzelne Checklisten-Chips können optional ein
   <a href> statt eines <span> sein (siehe templates/crewler/profile.php) -
   Browser-Standardstil (blau, unterstrichen) zurücksetzen, damit ein
   verlinkter Chip optisch identisch zu den unverlinkten bleibt, nur mit
   Zeigecursor und einer dezenten Hervorhebung beim Hover als Hinweis auf
   die Klickbarkeit. */
.profile-completion-item[href] { text-decoration: none; cursor: pointer; }
.profile-completion-item[href]:hover { border-color: var(--accent-color); color: var(--text-color); }
.profile-completion-item.is-done[href]:hover { opacity: .85; }

/* ---- Öffentliches Profil, Hero-Kopfbereich (Runde 75, Toby: "Mach das
   öffentliche Profil ansprechender, cooler, paar hingucker und
   features ;-)") - Farbverlauf-Kachel mit Foto/Name/Rang/Mitglied-seit,
   plus darunterliegende Kennzahlen-Zeile (Vervollständigungsgrad,
   Meilenstein-Abzeichen). Eigene Klassen statt Wiederverwendung von
   .crewler-detail-header/-avatar/-email (Runde 32/70), da deren feste
   Textfarben auf dem hellen/dunklen Kartenhintergrund ausgelegt sind,
   nicht auf dem farbigen Verlauf hier. */
.profile-hero {
    display: flex;
    align-items: center;
    gap: 22px;
    flex-wrap: wrap;
    border-radius: 14px;
    padding: 26px 24px;
    margin-bottom: 18px;
    background: linear-gradient(135deg, var(--accent-solid), var(--accent-color));
    color: #fff;
}
.profile-hero-avatar {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    object-fit: cover;
    background-color: rgba(255, 255, 255, .25);
    border: 3px solid rgba(255, 255, 255, .85);
    box-shadow: 0 3px 10px rgba(0, 0, 0, .25);
    flex-shrink: 0;
}
.profile-hero-avatar.is-clickable {
    cursor: zoom-in;
    transition: opacity .15s ease;
}
.profile-hero-avatar.is-clickable:hover { opacity: .88; }
.profile-hero-info { flex: 1 1 200px; min-width: 180px; }
.profile-hero-name { font-size: 23px; font-weight: 700; line-height: 1.25; }
.profile-hero-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin: 6px 0;
    font-size: 13px;
    opacity: .95;
}
.profile-hero-role-pill {
    display: inline-flex;
    align-items: center;
    padding: 3px 12px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .24);
    font-weight: 600;
    font-size: 12.5px;
}
.profile-hero-email { font-size: 14px; opacity: .95; }
.profile-hero-contact-icon, .profile-hero-contact-icon:visited {
    color: #fff !important;
    margin-left: 6px;
}
.profile-hero-contact-icon:hover { opacity: .8; }
.profile-hero-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-bottom: 20px;
}
.profile-hero-stat-chip {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 16px;
    border-radius: 10px;
    background: rgba(127, 127, 127, .08);
    border: 1px solid var(--border-color);
}

/* ---- Besucher-Diagramm (Runde 24): reines CSS-Balkendiagramm statt einer
   JS-Chart-Bibliothek (Chart.js o.ä.) – konsistent mit der Runde-17/18-
   Entscheidung, auf Semantic UIs .progress zu verzichten, und passend zum
   Rest der App (keine zusätzliche Abhängigkeit für ein einfaches
   Anwendungsfeld). 30 gleich breite Balken, Höhe relativ zum Tages-
   Maximum, Datum+Anzahl als title-Tooltip. */
.visits-chart {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 110px;
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 2px;
}
.visits-chart-bar {
    flex: 1 1 auto;
    height: 100%;
    display: flex;
    align-items: flex-end;
    cursor: default;
}
.visits-chart-bar-fill {
    width: 100%;
    min-height: 2px;
    background: var(--accent-color);
    border-radius: 2px 2px 0 0;
    transition: background-color .15s ease;
}
.visits-chart-bar:hover .visits-chart-bar-fill { background: var(--success-color); }
/* ---- Saisonale Auslastung nach Monat (Runde 49) - strukturell identisch
   zu .visits-chart-* oberhalb, aber bewusst eine eigene, flache
   Klassen-Familie (seit Runde 13 geltende Konvention, siehe
   .crewlernote-*-Kommentar weiter unten): 12 statt 30 Balken, andere
   Bedeutung (Monat statt Tag) - eine künftige Änderung an einem der beiden
   Diagramme soll das andere nie versehentlich mitbetreffen. */
.season-chart {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    height: 110px;
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 2px;
}
.season-chart-bar {
    flex: 1 1 auto;
    height: 100%;
    display: flex;
    align-items: flex-end;
    cursor: default;
}
.season-chart-bar-fill {
    width: 100%;
    min-height: 2px;
    background: var(--accent-color);
    border-radius: 2px 2px 0 0;
    transition: background-color .15s ease;
}
.season-chart-bar:hover .season-chart-bar-fill { background: var(--success-color); }
.season-chart-labels {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    opacity: .75;
    margin-top: 6px;
}

.visits-chart-labels {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    opacity: .75;
    margin-top: 6px;
}

/* ---- Statistikseite, Runde 76 (Toby: "Räume das Statistikmenü auf,
   bringe mehr Boxen für die Übersicht ein und baue mehr Diagramme ein,
   auch die Tabellen sind irre unübersichtlich."): drei neue,
   wiederverwendbare Bausteine für die komplett überarbeitete
   Statistikseite - eigene flache Klassen-Familien, dieselbe Konvention
   wie bei .visits-chart-* bzw. .season-chart-* oberhalb. ---- */

/* 1) Horizontales Balkendiagramm für Rangfolgen (Top-Crewler,
   Top-Positionen, Beeinträchtigungs-/Qualifikationsverteilung,
   Fill-Speed-Verteilung, Top-Uploader) - ersetzt dort jeweils eine reine
   Name/Anzahl-Tabelle, bei der der Zahlenwert ohne visuellen Vergleichs-
   maßstab schwer einzuordnen war. */
.rank-chart {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin-top: 10px;
}
.rank-chart-row {
    display: flex;
    align-items: center;
    gap: 10px;
}
.rank-chart-label {
    flex: 0 0 170px;
    max-width: 170px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
}
.rank-chart-track {
    flex: 1 1 auto;
    height: 16px;
    border-radius: 8px;
    background: rgba(127, 127, 127, .18);
    overflow: hidden;
}
.rank-chart-fill {
    height: 100%;
    border-radius: 8px;
    background: var(--accent-solid);
    transition: background-color .15s ease;
}
.rank-chart-row:hover .rank-chart-fill { background: var(--success-color); }
.rank-chart-value {
    flex: 0 0 auto;
    min-width: 30px;
    text-align: right;
    font-size: 12.5px;
    font-weight: 600;
}
@media (max-width: 640px) {
    .rank-chart-label { flex-basis: 108px; max-width: 108px; font-size: 12px; }
}

/* 2) Gestapelter Statusbalken (Crewler aktiv/wartend/gesperrt als EIN
   proportionaler Balken statt drei separater Zahlen) - dieselbe
   Farbzuordnung wie die Status-Badges in der Crewler-Liste
   (var(--success-color)/var(--warning-color)/var(--danger-color)), damit
   Toby die Farben sofort wiedererkennt. */
.status-stack-bar {
    display: flex;
    height: 22px;
    border-radius: 8px;
    overflow: hidden;
    margin-top: 12px;
    background: rgba(127, 127, 127, .18);
}
.status-stack-segment { height: 100%; min-width: 0; }
.status-stack-segment--active { background: var(--success-color); }
.status-stack-segment--pending { background: var(--warning-color); }
.status-stack-segment--blocked { background: var(--danger-color); }
.status-stack-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-top: 10px;
    font-size: 12.5px;
}
.status-stack-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.status-stack-swatch {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 3px;
}

/* 3) Scroll-Container für Tabellen, die über die Jahre unbegrenzt wachsen
   können (Veranstaltungs-Auslastung, Fotos je Veranstaltung - anders als
   die übrigen Tabellen der Seite, die serverseitig auf LIMIT 10 gedeckelt
   sind) - hält die Seite auch nach vielen weiteren Runden/Jahren
   überschaubar, ohne ältere Daten aus der Statistik zu entfernen. */
.stats-table-scroll {
    max-height: 420px;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    border-radius: 6px;
}
.stats-table-scroll table.ui.table { margin: 0; border: none; }

/* 4) Sprungmarken-Leiste oben auf der Statistikseite - bei sieben
   Abschnitten mit teils langen Tabellen war "irgendwo hinscrollen" bisher
   die einzige Navigation auf der Seite. */
.stats-quicknav {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 18px;
}
.stats-quicknav a {
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    border-radius: 999px;
    background: var(--box-bg);
    border: 1px solid var(--border-color);
    color: var(--text-color);
    font-size: 13px;
    text-decoration: none;
}
.stats-quicknav a:hover { border-color: var(--accent-color); color: var(--accent-color); }

@media (max-width: 640px) {
    main.app-main { padding: 18px 12px 40px; }
    .photo-grid { grid-template-columns: repeat(auto-fill, minmax(105px, 1fr)); gap: 8px; }
    .photo-lightbox-nav { width: 38px; height: 38px; }
    .photo-lightbox-prev { left: 8px; }
    .photo-lightbox-next { right: 8px; }
}

@media (max-width: 480px) {
    /* Runde 88: die beiden Regeln, die hier vorher .logo-text (den
       separaten "TRcrewverwaltung"-Text neben dem Logo) auf schmalen
       Bildschirmen ausgeblendet haben, sind entfallen - .logo-text gibt es
       seit Runde 88 gar nicht mehr im Markup (siehe main.php), das neue
       Logo enthält den Produktnamen bereits selbst. .logo-wrapper braucht
       auf sehr schmalen Bildschirmen trotzdem weiterhin etwas weniger
       Padding, daher bleibt diese eine Regel bestehen. */
    .logo-wrapper { padding: 6px 10px; }
}

/* ---- Feedback-Sterne (Runde 21) ----
   Reine CSS/HTML-Sternebewertung über die klassische "row-reverse +
   nachfolgende Geschwister"-Technik: die radio-Inputs liegen im DOM in
   umgekehrter Reihenfolge (5..1), flex-direction:row-reverse dreht sie
   visuell wieder auf 1..5 - der ~-Selektor kann nur auf NACHFOLGENDE
   Geschwister im DOM zielen, was durch die Umkehrung genau die Sterne
   BIS zum gehoverten/gewählten Stern einfärbt. Kein JS nötig. */
.star-rating {
    display: inline-flex;
    flex-direction: row-reverse;
    font-size: 32px;
    justify-content: flex-end;
}
.star-rating input { position: absolute; opacity: 0; width: 0; height: 0; }
.star-rating label {
    color: rgba(127, 127, 127, .35);
    cursor: pointer;
    padding: 0 2px;
    line-height: 1;
}
.star-rating input:checked ~ label,
.star-rating label:hover,
.star-rating label:hover ~ label {
    color: #f5b301;
}

/* Schreibgeschützte Sterne-Anzeige (starsDisplay()-Helper) */
.star-display { letter-spacing: 1px; }
.star-display .star-filled { color: #f5b301; }
.star-display .star-empty { color: rgba(127, 127, 127, .35); }

.feedback-comment-list { margin-top: 14px; display: flex; flex-direction: column; gap: 14px; }
.feedback-comment { border-bottom: 1px solid var(--border-color); padding-bottom: 12px; }
.feedback-comment:last-child { border-bottom: none; padding-bottom: 0; }
.feedback-comment-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.feedback-comment p { margin: 0; }

/* ---- Kommentare je Veranstaltung (Runde 23) ----
   Eigene, flache Klassen-Familie wie .feedback-comment (kein Kasten-in-
   Kasten, siehe Runde-14-Lektion) - bewusst nicht mit .feedback-comment-*
   wiederverwendet, damit eine künftige Änderung an einer Stelle die
   andere nicht versehentlich mit betrifft (Konvention seit Runde 13). */
.event-comment-list { margin-top: 14px; display: flex; flex-direction: column; gap: 14px; }
.event-comment { border-bottom: 1px solid var(--border-color); padding-bottom: 12px; }
.event-comment:last-child { border-bottom: none; padding-bottom: 0; }
.event-comment-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; flex-wrap: wrap; }
.event-comment p { margin: 0; white-space: pre-line; }

/* ---- Interne Verwalter-Notizen zu Crewlern (Runde 49) ----
   Eigene, flache Klassen-Familie wie .event-comment-* oberhalb, aus
   demselben seit Runde 13 geltenden Grund bewusst NICHT mit dieser
   wiederverwendet. */
.crewlernote-entry { border-bottom: 1px solid var(--border-color); padding-bottom: 12px; margin-bottom: 12px; }
.crewlernote-entry:last-child { border-bottom: none; padding-bottom: 0; margin-bottom: 0; }
.crewlernote-meta { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; flex-wrap: wrap; font-size: 13px; opacity: .75; }
.crewlernote-author { font-weight: bold; }
.crewlernote-text { margin: 0 0 6px; white-space: pre-line; }

/* ---- Push-Benachrichtigungen im Profil (Runde 49) ---- */
.profile-push-status { font-size: 13px; opacity: .8; margin: 4px 0 12px; min-height: 1em; }

/* ---- Fahrgemeinschaften je Veranstaltung (Runde 23) ---- */
.carpool-list { margin-top: 14px; display: flex; flex-direction: column; gap: 14px; }

/* Runde 24 (Toby: Fahrgemeinschafts-Seite "aufräumen, pimpen, cooler
   machen"): Angebote/Gesuche in zwei nebeneinander liegenden Spalten
   statt einer gemischten Liste, damit auf einen Blick klar ist, wer
   fährt und wer noch eine Mitfahrgelegenheit sucht. */
.carpool-columns { display: flex; gap: 32px; flex-wrap: wrap; margin-top: 10px; }
.carpool-column { flex: 1 1 320px; min-width: 280px; }

@media (max-width: 640px) {
    .carpool-columns { gap: 20px; }
}

/* Runde 25 (Toby: "viel zu tabelarisch und steril") - die Einträge waren
   nur schlichte, durch einen dünnen Trennstrich abgesetzte Textzeilen
   ohne jede eigene Optik. Jetzt echte, leicht abgehobene Karten
   (dezenter Hintergrund + Rahmen + farbiger linker Akzent, je nach Typ
   unterschiedlich eingefärbt) statt reiner Listenzeilen, dazu ein
   farbiger Icon-Kreis statt eines kleinen Inline-Icons und eine farbig
   umrandete statt grauer Aktions-Schaltfläche für den Routenlink. Bewusst
   TROTZDEM kein .trcard-Look (kein Kasten-in-Kasten INNERHALB der
   umgebenden .trcard-Box, siehe Runde-14-Lehre in "Für zukünftige
   Sessions") - nur ein dezenter, aber klar erkennbarer eigener Rahmen. */
.carpool-column-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: 8px;
    margin-bottom: 4px;
    background-color: rgba(127, 127, 127, .08);
}
.carpool-column-header .carpool-type-icon { width: 30px; height: 30px; font-size: 13px; }
.carpool-column-header span.ui.header { margin: 0; }

.carpool-entry {
    display: flex;
    gap: 12px;
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 8px;
    padding: 14px 16px;
}
.carpool-entry-sucht { border-left-color: var(--warning-color); }
.carpool-type-icon {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--accent-solid);
    color: #fff;
}
.carpool-entry-sucht .carpool-type-icon,
.carpool-type-icon.carpool-entry-sucht { background-color: var(--warning-color); }
.carpool-type-icon i.icon { margin: 0; color: #fff !important; line-height: 1; }
.carpool-entry-body { flex: 1 1 auto; min-width: 0; }
.carpool-entry-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; flex-wrap: wrap; }
.carpool-entry-head > span:first-child { font-weight: bold; }
.carpool-entry p { margin: 4px 0 8px; }
.carpool-entry-actions { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.carpool-entry-actions a.ui.button.carpool-route-btn {
    background-color: transparent !important;
    color: var(--accent-color) !important;
    border: 1px solid var(--accent-color);
    box-shadow: none !important;
}
.carpool-entry-actions a.ui.button.carpool-route-btn:hover {
    background-color: var(--accent-solid) !important;
    color: #fff !important;
}
.carpool-empty {
    text-align: center;
    padding: 30px 10px;
    opacity: .75;
}
.carpool-empty i.icon { font-size: 28px; display: block; margin-bottom: 8px; }

/* Runde 30 (Toby: "Pass [die Fahrgemeinschaften-Übersicht] genauso schön
   an wie die [Einzel-Veranstaltungs-Fahrgemeinschaftsseite]"): Die
   Übersicht listete bisher nur eine neutrale Gesamtzahl in einer
   generischen, von der Foto-Galerie geliehenen Pille
   (.photo-count-pill) - visuell hatte die Seite dadurch keinerlei
   erkennbare Verbindung zur Fahrgemeinschafts-Optik aus Runde 24/25
   (farbige Icon-Kreise, Blau für "bietet an"/Orange für "sucht"). Jetzt
   dieselbe Optik: der runde .carpool-type-icon-Kreis (blau, Auto-Icon)
   pro Veranstaltungskarte, plus zwei eigene Pillen für "bietet an"
   (blau) und "sucht" (orange) statt einer einzelnen neutralen Zahl -
   dieselbe Farbcodierung wie die beiden Spalten auf der Einzelseite.
   Basiert auf .dashboard-event-card (Layout/Hover unverändert
   übernommen), nur der Datums-Badge wurde durch den Fahrgemeinschafts-
   Icon-Kreis ersetzt. */
.carpool-overview-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.carpool-overview-card {
    display: flex;
    gap: 14px;
    align-items: center;
    padding: 10px 14px;
    background: var(--box-bg);
    border-left: 4px solid var(--accent-color);
    border-radius: 6px;
    cursor: pointer;
    transition: transform .12s ease, box-shadow .12s ease;
    flex-wrap: wrap;
}
.carpool-overview-card:hover {
    transform: translateX(2px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
}
.carpool-overview-card .carpool-type-icon {
    width: 40px;
    height: 40px;
    font-size: 15px;
}
.carpool-overview-counts {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    margin-left: auto;
}
.carpool-overview-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border-radius: 100px;
    padding: 2px 10px;
    font-size: 12px;
    white-space: nowrap;
    color: #fff;
}
.carpool-overview-pill .icon { margin: 0; line-height: 1; }
.carpool-overview-pill-offers { background-color: var(--accent-solid); }
.carpool-overview-pill-seeks { background-color: var(--warning-color); }
.carpool-overview-pill-empty {
    background-color: var(--bg-color);
    border: 1px solid var(--border-color);
    color: var(--muted-text);
}
@media (max-width: 480px) {
    .carpool-overview-counts { flex-direction: row; align-items: center; margin-left: 54px; }
}

/* ---- Unterkunft (Runde 77, Toby: "alle Ränge zu einer Veranstaltung
   auch Hotels/Ferienwohnung/etc vorschlagen ... Name, Adresse
   automatisch auf google Maps verlinken, Notizfeld") - Layout bewusst an
   .carpool-entry/.carpool-type-icon angelehnt (gleiche Icon-Kreis+Text-
   Zeilen-Optik), aber mit EIGENEN Klassennamen statt der "carpool-"-
   Klassen, da es sich inhaltlich um ein eigenständiges Feature handelt.
   .carpool-list/.carpool-empty/.carpool-entry-actions/.carpool-overview-*
   werden dagegen bewusst UNVERÄNDERT wiederverwendet - das sind bereits
   generische Container-/Listen-Layouts ohne Fahrgemeinschafts-spezifische
   Bedeutung. Die Icon-Zentrierung (line-height:1) ist hier von Anfang an
   korrekt gesetzt - siehe Runde-77-Bugfix bei .carpool-type-icon oben,
   derselbe Fehler soll hier nicht erneut auftreten. */
.accommodation-entry {
    display: flex;
    gap: 12px;
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--accent-color);
    border-radius: 8px;
    padding: 14px 16px;
}
.accommodation-entry-body { flex: 1 1 auto; min-width: 0; }
.accommodation-entry-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; flex-wrap: wrap; }
.accommodation-entry-head > span:first-child { font-weight: bold; }
.accommodation-entry p { margin: 4px 0 8px; }
.accommodation-type-icon {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--accent-solid);
    color: #fff;
}
.accommodation-type-icon i.icon { margin: 0; color: #fff !important; line-height: 1; }
.accommodation-type-ferienwohnung { background-color: var(--success-color); }
.accommodation-type-sonstiges { background-color: var(--muted-text); }

/* Runde 101 (Toby: "Verteile die Liste der Vorschläge auf links und
   rechts, es ist aktuell alles linksbündig und untereinander") - simples
   zweispaltiges Grid statt der bisherigen einspaltigen Liste
   (.carpool-list); "align-items: start" verhindert, dass Karten in der
   linken Spalte auf die Höhe der (oft unterschiedlich langen) Karte
   daneben gestreckt werden. Auf schmalen Bildschirmen wieder einspaltig,
   damit nichts gequetscht wirkt. */
.accommodation-list {
    margin-top: 14px;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    align-items: start;
}
@media (max-width: 700px) {
    .accommodation-list { grid-template-columns: 1fr; }
}

/* ---- Lesebestätigung bei Ankündigungen (Runde 23) ---- */
.announcement-read-stat { margin-top: 8px; font-size: 12px; opacity: .8; }
.announcement-read-stat summary { cursor: pointer; }
.announcement-read-stat p { margin: 4px 0 0; }

/* ---- "Mitmachen"-CTA auf der Gäste-Startseite (Runde 24, Toby: "kann
   ruhig präsenter auf die Startseite für Gäste, das soll ansprechend
   wirken!"; Runde 25, Toby: "ist ja hässlich geworden") - der
   Runde-24-Entwurf nutzte einen zweifarbigen Blau-Grün-Verlauf mit
   einem großen "Hand"-Icon; Grün kommt sonst NUR als Erfolgs-/
   Status-Farbe in der App vor (siehe --success-color), nie als
   Flächenfarbe, und wirkte hier stilfremd zum sehr zurückhaltenden,
   monochromen TRgallery-Look (Logo: Schwarz/Weiß + ein einzelner
   Blauton als Akzent). Jetzt stattdessen: ein einfarbiger Block in der
   App-eigenen Akzentfarbe (kein Verlauf, keine Fremdfarbe), dazu ein
   heller Icon-Kreis statt eines übergroßen freistehenden Icons -
   dasselbe Icon-Kreis-Muster wie bei den neuen Fahrgemeinschafts-Karten
   in dieser Runde, für ein konsistenteres Erscheinungsbild. Icon
   gewechselt von "hand paper outline" (wirkte eher wie eine
   Stopp-Geste) zu "users" (klar als "Community/Team" lesbar). */
.home-mitmachen-cta {
    margin-top: 26px;
    padding: 40px 30px;
    text-align: center;
    border-radius: 10px;
    color: #ffffff;
    background-color: var(--accent-solid);
}
.home-mitmachen-cta-icon {
    width: 56px;
    height: 56px;
    margin: 0 auto;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(255, 255, 255, .18);
}
.home-mitmachen-cta-icon i.icon { margin: 0; color: #ffffff; font-size: 22px; }
.home-mitmachen-cta > h2.ui.header { color: #ffffff; margin-top: 16px; }
.home-mitmachen-cta > p { font-size: 16px; max-width: 560px; margin: 10px auto 22px; opacity: .95; }
/* Weißer Button statt Standard-Akzentfarbe (siehe .ui.primary.button
   weiter unten) - auf dem farbigen Hintergrund würde ein
   akzentfarbener Button sonst kaum als Button erkennbar sein. */
.home-mitmachen-cta > a.ui.primary.button {
    background-color: #ffffff !important;
    color: var(--accent-color) !important;
}
.home-mitmachen-cta > a.ui.primary.button:hover { opacity: .9; }

/* ---- Ungespeicherte-Änderungen-Hinweis am Speichern-Button ----
   Runde 40, Toby: "Bitte den Button pulsieren lassen, wenn man etwas
   verändert hat, aber noch nicht gespeichert wurde." Generisch über
   app.js an jedem Formular mit `data-track-dirty` verdrahtet (siehe
   dort) - hier nur die rein optische Pulsier-Animation als eigene,
   wiederverwendbare Klasse, damit sie unabhängig vom jeweiligen
   Button-Stil (primary/accent) funktioniert. Ein weicher, wachsender/
   schrumpfender Schein in der App-Akzentfarbe statt einer reinen
   Skalierung, damit der Button nicht "hüpft" und sein Platz im Layout
   stabil bleibt. */
@keyframes trcrew-pulse-attention {
    0%, 100% { box-shadow: 0 0 0 0 rgba(0, 172, 255, .55); }
    50% { box-shadow: 0 0 0 8px rgba(0, 172, 255, 0); }
}
.pulse-attention {
    animation: trcrew-pulse-attention 1.4s ease-in-out infinite;
}
body.dark .pulse-attention {
    animation-name: trcrew-pulse-attention-dark;
}
@keyframes trcrew-pulse-attention-dark {
    0%, 100% { box-shadow: 0 0 0 0 rgba(41, 215, 255, .55); }
    50% { box-shadow: 0 0 0 8px rgba(41, 215, 255, 0); }
}

/* ---- Persönlich anordenbare Dashboard-Boxen ----
   Runde 41, Toby: "Kann man diese Boxen verschiebbar machen, dass sich
   jeder für sich alles zusammenstellen, ein- und ausblendbar machen kann
   und das im profil gespeichert wird?" - siehe dashboard.js für die
   Interaktion, DashboardController::widgetDefinitions()/resolveLayout()/
   saveLayout() für die Server-Seite.

   Statt des bisherigen starren ".ui.two.column.grid" mit fest verteilten
   Boxen je Spalte liegen alle anordenbaren Boxen jetzt als gleichrangige
   Kinder in einem CSS-Grid (".dashboard-widgets") - ihre Reihenfolge im
   DOM bestimmt die Grid-Auto-Platzierung (zeilenweise von links nach
   rechts, automatisch umbrechend), wodurch ein einfaches Umsortieren der
   DOM-Knoten per Drag&Drop/Auf-Ab-Buttons genau der gewünschten visuellen
   Neuanordnung entspricht - keine separate "welche Spalte"-Logik nötig. */
.dashboard-page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
}
.dashboard-page-header h2.ui.header { margin-bottom: 0; }
.dashboard-page-header-actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* Runde 42 (Toby: "zwischen dem anpassen-buttom und den boxen etwas mehr
   platz"): der ursprüngliche 4px-Abstand von .dashboard-widgets reichte
   zusammen mit dem knappen Zeilenabstand der Kopfzeile nicht aus - jetzt
   deutlich mehr Luft nach der Kopfzeile/dem Anpassen-Hinweis. */
.dashboard-page-header { margin-bottom: 6px; }
/* Semantic UIs .ui.button setzt selbst "display:inline-block" mit höherer
   Spezifität als die Browser-eigene [hidden]-Regel ("display:none") -
   ohne dieses !important würde der per JS/HTML-Attribut ausgeblendete
   Zurücksetzen-Button trotzdem sichtbar bleiben. */
#dashboard-reset[hidden] { display: none !important; }

.dashboard-edit-hint {
    display: none;
    font-size: 13px;
    opacity: .8;
    margin: 4px 0 18px;
}
.dashboard-page.dashboard-edit-mode .dashboard-edit-hint { display: block; }

/* Runde 43 (Toby: "wäre toll wenn man boxen maximieren könnte auf zwei
   oder drei boxenbreiten"): das Grid nutzte bisher "repeat(auto-fit,
   minmax(360px, 1fr))" - die Spaltenanzahl ergab sich rein aus der
   verfügbaren Breite, ohne dass eine feste Spaltenzahl existierte, über
   die man "diese Box ist 2 oder 3 Spalten breit" hätte ausdrücken können
   (ein Kind mit grid-column:span 3 in einem auto-fit-Grid, das gerade nur
   2 Spalten anzeigt, würde vom Browser durch zusätzliche IMPLIZITE Spalten
   "aufgefüllt" und so das Grid unkontrolliert verbreitern). Stattdessen
   jetzt feste, an den bisherigen auto-fit-Umbruchpunkten orientierte
   Spaltenzahlen je Breakpoint (1/2/3 Spalten) - darauf lässt sich
   grid-column:span sauber und vorhersehbar abbilden, siehe
   .dashboard-widget-w2/-w3 unten. */
.dashboard-widgets {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: start;
    margin-top: 26px;
    /* Runde 47 (Toby-Screenshot: sichtbare leere Fläche zwischen Boxen):
       ohne "dense" lässt CSS Grid eine Spalte frei/leer stehen, sobald
       eine 2- oder 3-breite Box (Runde 43) nicht mehr in die verbleibenden
       Spalten der aktuellen Zeile passt, und rückt die Box stattdessen
       eine ganze Zeile weiter nach unten - die übersprungene(n) Zelle(n)
       bleiben dauerhaft leer, was genau als diese unerwartet große Lücke
       auffällt. "dense" lässt den Browser stattdessen spätere, kleinere
       Boxen rückwirkend in solche Lücken einsortieren, sodass keine
       Zelle ungenutzt bleibt. Nebeneffekt: eine nachfolgende Box kann
       dadurch optisch VOR einer im Anpassen-Modus weiter oben
       einsortierten Box erscheinen, wenn sie so besser in eine Lücke
       passt - die gespeicherte Reihenfolge selbst ändert sich dadurch
       nicht, nur die visuelle Platzierung bei vorhandenen Lücken. */
    grid-auto-flow: row dense;
}
@media (min-width: 780px) {
    .dashboard-widgets { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1160px) {
    .dashboard-widgets { grid-template-columns: repeat(3, 1fr); }
}
/* Der Grid-Zwischenraum (gap) übernimmt den Abstand zwischen den Boxen -
   der sonst app-weit übliche untere Rand von .ui.segment.trcard (siehe
   ganz oben in dieser Datei) würde sonst zusätzlich zum gap wirken und
   uneinheitliche, zu große Lücken erzeugen. Gilt auch für die "Neueste
   Fotos"-Box (Crewler-Dashboard), die zwar kein anordenbares Widget ist,
   aber als weiteres Grid-Kind mitläuft. */
.dashboard-widgets > .ui.segment.trcard { margin: 0; }

/* Runde 48 (Toby: "alle boxen beginnen immer in einer horizontalen
   flucht, es ist nicht möglich die alle untereinander auszurichten ohne
   dass es große leere stellen gibt" - Klarstellung, dass Runde 47s
   "grid-auto-flow: row dense" oben nur dauerhaft übersprungene, leere
   Zellen behob, nicht aber das grundsätzliche CSS-Grid-Verhalten
   "Zeilenhöhe = höchstes Element dieser Zeile": eine niedrige Box neben
   einer hohen lässt darunter zwangsläufig Leerraum stehen, bis die
   nächste Zeile beginnt - das ist mit zeilenbasiertem CSS Grid
   grundsätzlich nicht lösbar). Echtes Masonry-("Pinterest"-)Packing
   braucht pro Box eine individuell auf die jeweils kürzeste Spalte
   berechnete Position - natives CSS-Masonry ("grid-template-rows:
   masonry" / CSS Grid Lanes) ist Stand 09/2026 in keinem Browser
   produktionsreif (Safari nur Technology Preview, Firefox nur Nightly
   mit veralteter Syntax, Chrome/Edge nur hinter einem Flag seit v140).
   dashboard.js (initMasonry()) berechnet die Positionen deshalb per
   JavaScript und setzt sie als "position:absolute" je Box; diese Klasse
   wird von dort erst NACH dem ersten erfolgreichen Layout-Lauf gesetzt.
   Die obigen grid-*-Regeln bleiben unverändert als Fallback bestehen,
   falls JavaScript deaktiviert ist bzw. bevor der erste Lauf
   abgeschlossen ist - dann greift weiterhin das (funktionsfähige, nur
   mit dem o.g. Zeilenhöhen-Nebeneffekt behaftete) CSS-Grid aus
   Runde 41/43/47. */
.dashboard-widgets.masonry-active {
    display: block;
    position: relative;
}
.dashboard-widgets.masonry-active > .ui.segment.trcard {
    position: absolute;
    top: 0;
    left: 0;
    /* Der Zahlenwert 20 (Spaltenabstand) muss zum "gap" oben und zum
       GAP-Wert in dashboard.js (initMasonry()) passen - bewusst an allen
       drei Stellen als reine Zahl gepflegt, siehe dortiger Kommentar. */
    transition: left .18s ease, top .18s ease, width .18s ease;
}

.dashboard-widget { display: flex; flex-direction: column; grid-column: span 1; }

/* Breiten-Stufen (Runde 43) - per Klick auf den ".dashboard-widget-size"-
   Button im Anpassen-Modus umschaltbar (siehe dashboard.js), serverseitig
   in dashboard_layout.sizes gespeichert (DashboardController). Auf
   schmalen Bildschirmen mit nur 1 bzw. 2 Spalten wird eine zu große
   Spannweite automatisch auf die tatsächlich vorhandene Spaltenzahl
   gekappt, statt das Grid zu sprengen. */
.dashboard-widget-w2 { grid-column: span 2; }
.dashboard-widget-w3 { grid-column: span 3; }
@media (max-width: 779px) {
    .dashboard-widget-w2,
    .dashboard-widget-w3 { grid-column: span 1; }
}
@media (min-width: 780px) and (max-width: 1159px) {
    .dashboard-widget-w3 { grid-column: span 2; }
}

.dashboard-widget-bar {
    display: none;
    align-items: center;
    gap: 8px;
    margin: -4px -4px 12px;
    padding: 6px 8px;
    border-radius: 4px;
    background-color: rgba(127, 127, 127, .08);
    cursor: grab;
}
.dashboard-page.dashboard-edit-mode .dashboard-widget-bar { display: flex; }
.dashboard-widget-bar:active { cursor: grabbing; }
.dashboard-widget-handle { display: flex; align-items: center; opacity: .6; }
.dashboard-widget-handle .icon { margin: 0; }
.dashboard-widget-name { font-weight: bold; font-size: 13px; flex: 1 1 auto; }
.dashboard-widget-bar-actions { display: flex; align-items: center; gap: 2px; }
.dashboard-widget-move,
.dashboard-widget-size,
.dashboard-widget-toggle {
    background: none;
    border: none;
    color: var(--text-color);
    opacity: .7;
    cursor: pointer;
    padding: 4px 6px;
    border-radius: 3px;
}
.dashboard-widget-move:hover,
.dashboard-widget-size:hover,
.dashboard-widget-toggle:hover { opacity: 1; background-color: rgba(127, 127, 127, .15); }
.dashboard-widget-move .icon,
.dashboard-widget-toggle .icon { margin: 0; }
/* ".dashboard-widget-size" zeigt die aktuelle Breitenstufe direkt als Text
   ("1×"/"2×"/"3×") statt als Icon - eindeutiger als ein Symbol und spart
   eine eigene Tooltip-Erklärung je Zustand. */
.dashboard-widget-size {
    font-size: 12px;
    font-weight: bold;
    font-variant-numeric: tabular-nums;
    min-width: 22px;
    text-align: center;
}
.dashboard-widget:first-child .dashboard-widget-move[data-dir="up"],
.dashboard-widget:last-child .dashboard-widget-move[data-dir="down"] { visibility: hidden; }

/* Ausgeblendete Boxen: außerhalb des Anpassen-Modus komplett unsichtbar
   (kein leerer Kasten im normalen Dashboard), im Anpassen-Modus
   halbtransparent mit gestricheltem Rahmen sichtbar, damit sie sich
   gezielt wieder einblenden lassen - der Inhalt selbst bleibt dabei
   verborgen (nicht "einmal sehen, was ausgeblendet ist", sondern nur
   "diese Box existiert, hier kannst du sie zurückholen"). */
.dashboard-widget-hidden { display: none; }
.dashboard-page.dashboard-edit-mode .dashboard-widget-hidden {
    display: flex;
    opacity: .55;
    border-style: dashed;
}
.dashboard-widget-hidden .dashboard-widget-body { display: none; }

/* Drag&Drop-Feedback (nur Desktop - siehe dashboard.js für die
   Touch-/Mobil-Alternative per Auf-/Ab-Buttons oben). */
.dashboard-widget.dragging { opacity: .35; }
.dashboard-page.dashboard-edit-mode .dashboard-widget:hover {
    outline: 1px dashed var(--accent-color);
    outline-offset: 2px;
}

/* ---- Uhr-/Datum-Dashboard-Boxen ----
   Runde 42, Toby: "Bitte weitere boxen hinzufügen: Datum, Uhr digital,
   uhr analog, datum+uhrzeit ...". Markup kommt aus dem gemeinsamen
   Helfer dashboardClockWidget() (src/Core/helpers.php), das "Ticken"
   läuft in dashboard.js (initClocks()). font-variant-numeric:tabular-nums
   verhindert, dass die digitale Uhr durch unterschiedlich breite Ziffern
   (z.B. "1" vs. "8") bei jedem Sekundenwechsel minimal "zittert". */
.dashboard-clock-date {
    font-size: 19px;
    font-weight: bold;
    text-align: center;
    padding: 22px 4px;
}
.dashboard-clock-digital {
    font-size: 42px;
    font-weight: bold;
    text-align: center;
    padding: 20px 0;
    font-variant-numeric: tabular-nums;
    letter-spacing: 1px;
}
.dashboard-clock-digital-compact { font-size: 30px; padding: 4px 0 22px; }

.dashboard-clock-analog-wrap { display: flex; justify-content: center; padding: 10px 0; }
.dashboard-clock-analog-face { width: 180px; height: 180px; }
.dashboard-clock-analog-ring { fill: none; stroke: var(--border-color); stroke-width: 3; }
.dashboard-clock-analog-tick { stroke: var(--border-color); stroke-width: 2; }
.dashboard-clock-analog-tick-major { stroke: var(--text-color); stroke-width: 3; }
.dashboard-clock-hand { stroke-linecap: round; }
.dashboard-clock-hand-hour { stroke: var(--text-color); stroke-width: 6; }
.dashboard-clock-hand-minute { stroke: var(--text-color); stroke-width: 4; }
.dashboard-clock-hand-second { stroke: var(--accent-color); stroke-width: 2; }
.dashboard-clock-analog-center { fill: var(--accent-color); }

/* "Gerade angemeldet"-Box (Runde 42) */
.dashboard-active-user-you {
    font-size: 12px;
    font-weight: normal;
    opacity: .7;
}

/* ---- Weitere Dashboard-Boxen (Runde 44) ----
   Toby-Vorschläge auf die Rückfrage nach weiteren Boxen-Ideen: Countdown
   zum nächsten Einsatz, "Wer arbeitet mit mir?", Geburtstage der
   nächsten 30 Tage, Schnellsuche Crewler, Mini-Kalender, eigene
   Notizbox. Markup: siehe templates/dashboard/verwalter.php,
   templates/dashboard/crewler.php und die Helfer
   dashboardMiniCalendarWidget()/dashboardPersonalNoteWidget() in
   src/Core/helpers.php. Interaktion: siehe dashboard.js
   (initCountdown()/initQuickSearch()/initCalendar()/initNote()). */

.dashboard-countdown { text-align: center; padding: 6px 4px 14px; }
.dashboard-countdown-event { font-weight: bold; margin-bottom: 10px; }
.dashboard-countdown-value {
    font-size: 28px;
    font-weight: bold;
    font-variant-numeric: tabular-nums;
    color: var(--accent-color);
}

/* Schnellsuche Crewler: nutzt bewusst Semantic UIs ".ui.input" (statt
   eigener Input-Gestaltung) - erbt dadurch automatisch dieselbe
   Hell-/Dunkelmodus-Theming wie alle anderen Formularfelder der App (s.
   die body.dark .ui.input input-Regel weiter oben in dieser Datei). Nur
   das Ergebnis-Dropdown darunter ist eigenes, neues Markup, da Semantic
   UI dafür kein eingebautes Modul ohne zusätzliches JS bietet. */
.dashboard-quicksearch { position: relative; }
.dashboard-quicksearch-results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 5;
    margin-top: 4px;
    background-color: var(--menu-bg);
    border: 1px solid var(--border-color);
    border-radius: 4px;
    max-height: 260px;
    overflow-y: auto;
    box-shadow: 0 4px 10px rgba(0, 0, 0, .18);
}
.dashboard-quicksearch-result {
    display: block;
    padding: 8px 10px;
    color: var(--text-color);
}
.dashboard-quicksearch-result:hover { background-color: rgba(127, 127, 127, .15); }

/* Mini-Kalender */
.dashboard-calendar-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
}
.dashboard-calendar-nav-btn {
    background: none;
    border: none;
    color: var(--text-color);
    cursor: pointer;
    padding: 4px 8px;
    opacity: .7;
}
.dashboard-calendar-nav-btn:hover { opacity: 1; background-color: rgba(127, 127, 127, .15); border-radius: 3px; }
.dashboard-calendar-title { font-weight: bold; font-size: 14px; }
.dashboard-calendar-weekdays,
.dashboard-calendar-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    text-align: center;
}
.dashboard-calendar-weekdays span {
    font-size: 11px;
    opacity: .6;
    padding-bottom: 4px;
    text-transform: uppercase;
}
.dashboard-calendar-day {
    display: block;
    padding: 6px 0;
    border-radius: 4px;
    font-size: 13px;
    color: var(--text-color);
    text-decoration: none;
}
.dashboard-calendar-day-empty { visibility: hidden; }
.dashboard-calendar-day-today { font-weight: bold; box-shadow: inset 0 0 0 1px var(--accent-color); }
.dashboard-calendar-day-event { background-color: var(--accent-solid); color: #fff; }
a.dashboard-calendar-day-event:hover { opacity: .85; }

/* Eigene Notizbox: ".ui.form" auf dem Wrapper (siehe
   dashboardPersonalNoteWidget()) übernimmt bereits Schriftart und
   Hell-/Dunkelmodus-Theming des Textarea - hier nur noch Größe/
   Verhalten sowie der dezente "gespeichert"-Statustext. */
.dashboard-note-textarea { min-height: 120px; resize: vertical; }
.dashboard-note-status {
    font-size: 11px;
    opacity: 0;
    transition: opacity .3s ease;
    margin-top: 4px;
    min-height: 14px;
}

/* ---- Crew-Verzeichnis "/meine-einsaetze/{id}/crew" (Runde 81, Toby:
   "gestalte diese Liste etwas schöner!") - ersetzt die bisherige schlichte
   ".ui relaxed divided list" durch ein Karten-Raster, ähnlich der bereits
   etablierten Kachel-Optik anderer Übersichten (z.B. .dashboard-stat-tile),
   aber mit eigenen Klassen, da hier zusätzlich Avatar + mehrzeilige
   Dienst-Liste je Karte unterzubringen sind. */
.crew-directory-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 14px;
    margin-top: 10px;
}
.crew-directory-card {
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.crew-directory-card:hover {
    border-color: var(--accent-color);
    box-shadow: 0 2px 10px rgba(0, 0, 0, .08);
}
.crew-directory-card.is-self {
    border-left: 4px solid var(--accent-color);
}
.crew-directory-card-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}
.crew-directory-avatar {
    width: 46px;
    height: 46px;
    border-radius: 50%;
    object-fit: cover;
    flex: none;
}
.crew-directory-name-wrap {
    flex: 1 1 auto;
    min-width: 0;
}
.crew-directory-name {
    font-weight: 600;
    color: var(--text-color);
    overflow-wrap: anywhere;
}
.crew-directory-badges {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 4px;
}
.crew-directory-cert-btn { flex: none; }
.crew-directory-shifts {
    display: flex;
    flex-direction: column;
    gap: 4px;
    border-top: 1px solid var(--border-color);
    padding-top: 8px;
}
.crew-directory-shift {
    font-size: 12px;
    color: var(--muted-text);
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.crew-directory-shift-date { font-weight: 600; }
.crew-directory-shift-position { color: var(--text-color); }
.crew-directory-contact {
    border-top: 1px solid var(--border-color);
    padding-top: 8px;
    margin-top: 0;
}

/* ---- Ernährungsform-Überblick auf der Einteilungsseite (Runde 82,
   Toby: "aus supervisor Sicht ... schnell einen Überblick") - kompakte
   Zähler-Kacheln analog zu .crew-directory-card (gleicher neutraler
   Hintergrund), aber deutlich kleiner, da hier nur eine Zahl + ein Label
   je Kategorie nötig sind. */
.diet-overview-tiles {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.diet-overview-tile {
    display: flex;
    align-items: baseline;
    gap: 6px;
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--accent-color);
    border-radius: 6px;
    padding: 6px 12px;
}
.diet-overview-tile-count {
    font-size: 18px;
    font-weight: 700;
    color: var(--text-color);
}
.diet-overview-tile-label {
    font-size: 12px;
    color: var(--muted-text);
}
.diet-overview-tile-muted { border-left-color: var(--muted-text); }
.dashboard-note-status.visible { opacity: .7; }

/* ---- Ernährungsvorlieben / Anmerkungen: getaggte Einzelliste (Runde 82,
   Nachtrag - Toby entschied sich nach Rückfrage für "Option 1" seiner
   Tester statt getrennter Textabschnitte je Kategorie). Jede Zeile ist ein
   eigener Chip mit farbiger Kategorie-Kennzeichnung (Randfarbe + Textfarbe
   analog zu .diet-overview-tile) statt eines einzelnen Freitextfelds. */
.dietary-item-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 16px;
}
.dietary-item-chip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    background-color: rgba(127, 127, 127, .05);
    border: 1px solid var(--border-color);
    border-left: 4px solid var(--muted-text);
    border-radius: 6px;
    padding: 8px 10px;
}
.dietary-item-category {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--muted-text);
}
.dietary-tag-schwere_allergie { border-left-color: var(--danger-color); }
.dietary-tag-schwere_allergie .dietary-item-category { color: var(--danger-color); }
.dietary-tag-unvertraeglichkeit { border-left-color: var(--warning-color); }
.dietary-tag-unvertraeglichkeit .dietary-item-category { color: #a06f00; }
.dietary-tag-lebensmittelempfindlichkeit { border-left-color: var(--accent-color); }
.dietary-tag-lebensmittelempfindlichkeit .dietary-item-category { color: var(--accent-color); }
.dietary-tag-sensorik_textur { border-left-color: #a333c8; }
.dietary-tag-sensorik_textur .dietary-item-category { color: #a333c8; }
.dietary-tag-sonstiges { border-left-color: var(--muted-text); }
.dietary-item-name {
    font-weight: 600;
    color: var(--text-color);
}
.dietary-item-note {
    font-size: 12px;
    color: var(--muted-text);
    font-style: italic;
}
.dietary-item-remove-form {
    margin-left: auto;
}
.dietary-item-remove-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
    color: var(--muted-text);
    padding: 2px 6px;
}
.dietary-item-remove-btn:hover {
    color: var(--danger-color);
}
/* Runde 139: Ernährungseinträge bearbeitbar (details/summary ohne JS).
   Grafikfehler-Fix (Toby-Screenshot): das Bearbeitungsformular lief mit den
   Semantic-"three fields" aus dem Chip heraus (Felder überlappten, rechts
   abgeschnitten) - jetzt eigenes Grid, das exakt die Chip-Breite nutzt und
   mobil einspaltig wird. */
.dietary-item-edit-toggle {
    margin-left: auto;
    min-width: 0;
}
.dietary-item-edit-toggle[open] {
    flex: 0 0 100%;
    max-width: 100%;
    order: 10;
    margin-left: 0;
}
.dietary-item-edit-toggle + .dietary-item-remove-form {
    margin-left: 0;
}
/* Bearbeiten offen: das Löschen-"x" bleibt in der ersten Zeile rechts. */
.dietary-item-chip:has(> .dietary-item-edit-toggle[open]) > .dietary-item-remove-form {
    margin-left: auto;
}
.dietary-item-edit-btn {
    cursor: pointer;
    list-style: none;
    color: var(--muted-text);
    padding: 2px 6px;
    display: inline-block;
}
.dietary-item-edit-btn::-webkit-details-marker { display: none; }
.dietary-item-edit-btn:hover { color: var(--accent-color); }
.dietary-item-edit-form {
    margin-top: 8px;
    border-top: 1px dashed var(--border-color);
    padding-top: 10px;
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}
.dietary-item-edit-fields {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0 12px;
}
.dietary-item-edit-fields .field {
    min-width: 0;
    margin: 0 0 12px !important;
    align-self: start;
}
.dietary-item-edit-fields .field > label {
    display: block;
    margin: 0 0 4px;
}
.dietary-item-edit-form > button {
    margin-top: 4px;
}
.dietary-item-edit-fields input,
.dietary-item-edit-fields select,
.dietary-item-edit-fields .ui.dropdown {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
}
@media (max-width: 700px) {
    .dietary-item-edit-fields {
        grid-template-columns: minmax(0, 1fr);
    }
}
.dietary-item-add-form {
    border-top: 1px solid var(--border-color);
    padding-top: 12px;
}
.dietary-legacy-note {
    margin-top: 14px;
    padding-top: 10px;
    border-top: 1px dashed var(--border-color);
}

/* ---- Organigramm (Runde 86) ---- */
.orgchart {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 24px;
}
.orgchart-tier {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 20px;
    width: 100%;
}
.orgchart-connector {
    width: 2px;
    height: 28px;
    background: var(--border-color);
    margin: 4px 0;
}
.orgchart-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    width: 180px;
    margin: 0 !important;
    padding: 18px 14px;
}
.orgchart-avatar {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    margin-bottom: 10px;
}
.orgchart-name {
    font-weight: 600;
}
.orgchart-role {
    font-size: 12px;
    opacity: .7;
    margin: 2px 0 4px 0;
}
/* Runde 99 (Toby: "welche Position er betreut ... im Organigramm
   eingefügt werden") - dezenter als .orgchart-role, damit die
   Rollenbezeichnung (Supervisor/Systemadministrator) weiterhin der
   auffälligste Text unter dem Namen bleibt. */
.orgchart-positions {
    font-size: 11px;
    opacity: .75;
    margin: 0 0 12px 0;
    line-height: 1.4;
}

/* ---- Beta-Kennzeichnung (Runde 87, Toby: "Bau irgendwo im Register, im
   Login und im Dashboard ein, dass man sieht, dass es eine Beta-Version
   ist") - ein kleines Label neben der jeweiligen Seitenüberschrift, bewusst
   dezent statt aufdringlich, in der bereits im Projekt etablierten
   Warnfarbe (--warning-color, sonst z.B. für den "wartend"-Status
   verwendet), damit es sich als Hinweis und nicht als Fehler/Problem
   liest. */
.beta-badge {
    display: inline-block;
    vertical-align: middle;
    margin-left: 10px;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--warning-color);
    color: #000;
    font-size: 11px;
    font-weight: bold;
    letter-spacing: .05em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Runde 89 (Toby: "könnte man dem user die möglichkeit geben, die farbe
   von blau in eine andere zu ändern?"): Farbkreis-Auswahl im Profil
   (siehe templates/crewler/profile.php, Abschnitt "Einstellungen") - ein
   verstecktes Radio-Input je Farbe plus ein klickbares <label> als runde
   Farbfläche, damit man die tatsächliche Farbe sieht statt nur einen
   Textnamen aus einem Dropdown zu lesen (anders als beim danebenstehenden
   theme_pref-Dropdown, wo es nichts Vergleichbares zu "sehen" gibt).
   Die Farbe selbst kommt INLINE über style="" aus dem Template (die
   Palette lebt serverseitig in AccentColor.php, nicht hier im CSS - so
   bleibt es EINE Quelle der Wahrheit). */
.accent-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 6px;
}
.accent-swatch-option {
    position: relative;
}
.accent-swatch-option input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}
.accent-swatch-option label {
    display: block;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    cursor: pointer;
    border: 2px solid var(--border-color);
    box-sizing: border-box;
    transition: transform .1s ease, border-color .1s ease;
}
.accent-swatch-option label:hover {
    transform: scale(1.08);
}
.accent-swatch-option input[type="radio"]:checked + label {
    border-color: var(--text-color);
    box-shadow: 0 0 0 2px var(--bg-color), 0 0 0 4px var(--text-color);
}
.accent-swatch-option input[type="radio"]:focus-visible + label {
    outline: 2px solid var(--text-color);
    outline-offset: 2px;
}

/* Runde 139: Profil-Sperre während der Einteilung (<fieldset disabled>) -
   das Fieldset selbst soll optisch unsichtbar bleiben. */
.profile-lock-fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.profile-lock-fieldset[disabled] {
  opacity: .55;
}
.license-box {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(128, 128, 128, .25);
}

/* Runde 139 Nachtrag: Führerschein-Modal */
.license-modal-content { text-align: center; }
.license-modal-media { max-width: 100%; max-height: 70vh; border: 0; }
iframe.license-modal-media { width: 100%; height: 70vh; }

/* ---- Runde 141: Filterleiste der Crew-Einteilung ---- */
.assignment-slot[hidden],
.assignment-day[hidden],
.assignment-filter [hidden],
#assignment-filter-empty[hidden] { display: none !important; }
.assignment-filter { margin-top: 14px; }
.assignment-filter-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
}
.assignment-filter-count {
    font-size: 13px;
    color: var(--muted-text);
    margin-right: auto;
}
.assignment-filter-hint { font-size: 12px; opacity: .8; margin: 4px 0 12px; }
.assignment-filter-group {
    display: flex;
    align-items: flex-start;
    gap: 8px 12px;
    margin-top: 10px;
}
.assignment-filter-label {
    flex: 0 0 84px;
    padding-top: 6px;
    font-size: 13px;
    font-weight: 700;
}
.assignment-filter-chips { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; }
.assignment-filter-chip {
    font: inherit;
    font-size: 13px;
    line-height: 1.2;
    padding: 6px 12px;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    background: transparent;
    color: var(--text-color);
    cursor: pointer;
    transition: background-color .12s, border-color .12s;
}
.assignment-filter-chip:hover { border-color: var(--accent-color); }
.assignment-filter-chip:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
.assignment-filter-chip[aria-pressed="true"] {
    background: var(--accent-solid);
    border-color: var(--accent-solid);
    color: #fff;
    font-weight: 700;
}
.assignment-filter-chip-n {
    display: inline-block;
    margin-left: 4px;
    font-size: 11px;
    opacity: .7;
}
.assignment-filter-search { max-width: 320px; width: 100%; }
@media (max-width: 600px) {
    .assignment-filter-group { flex-direction: column; gap: 4px; }
    .assignment-filter-label { flex: none; padding-top: 0; }
    .assignment-filter-chips { width: 100%; }
}

/* ---- Runde 142: Schichtplan-Raster der Crew-Einteilung ---- */
.sg-head { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 10px; }
.sg-head-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.sg-lock-pill { cursor: pointer; border: 0; font: inherit; font-weight: 700; margin: 0; }

.sg-summary { margin-top: 14px; }
.sg-summary-text { font-size: 14px; margin-bottom: 8px; }
.sg-progress { height: 8px; border-radius: 999px; background: rgba(127, 127, 127, .25); overflow: hidden; }
.sg-progress span { display: block; height: 100%; background: var(--success-color); border-radius: 999px; }
.sg-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 10px; font-size: 12px; color: var(--muted-text); }
.sg-legend span { display: inline-flex; align-items: center; gap: 6px; }
.sg-dot { display: inline-block; width: 12px; height: 12px; border-radius: 3px; border-left: 4px solid; }
.sg-dot.is-empty,   .sg-tile.is-empty   { border-color: var(--danger-color);  background-color: rgba(219, 40, 40, .14); }
.sg-dot.is-partial, .sg-tile.is-partial { border-color: var(--warning-color); background-color: rgba(242, 192, 55, .22); }
.sg-dot.is-full,    .sg-tile.is-full    { border-color: var(--success-color); background-color: rgba(33, 186, 69, .16); }

/* Filter als aufklappbarer Streifen */
details.assignment-filter > summary {
    list-style: none; cursor: pointer; display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; font-weight: 700;
}
details.assignment-filter > summary::-webkit-details-marker { display: none; }
details.assignment-filter > summary::after { content: "▾"; margin-left: auto; opacity: .6; }
details.assignment-filter[open] > summary::after { content: "▴"; }
details.assignment-filter .assignment-filter-count { margin-right: 0; font-weight: 400; }
.sg-filter-badge {
    display: inline-block; min-width: 20px; padding: 1px 6px; text-align: center; border-radius: 999px;
    background: var(--accent-solid); color: #fff; font-size: 12px;
}

.sg-layout { display: block; margin-top: 14px; }
.sg-grid-col { min-width: 0; }
.sg-wrap { padding: 0 !important; overflow-x: auto; margin: 0 !important; }
.sg-table { border-collapse: separate; border-spacing: 0; width: 100%; }
.sg-table th, .sg-table td { padding: 8px; vertical-align: top; border-bottom: 1px solid var(--border-color); }
.sg-table tbody tr:last-child th, .sg-table tbody tr:last-child td { border-bottom: 0; }
.sg-table thead th { text-align: left; font-weight: 400; background: var(--box-bg); position: sticky; top: 0; z-index: 1; }
.sg-dayhead { min-width: 150px; }
.sg-dayhead .availability-weekday { display: block; font-weight: 700; }
.sg-corner, .sg-poshead {
    position: sticky; left: 0; z-index: 2; min-width: 140px; max-width: 200px; background: var(--box-bg);
    border-right: 1px solid var(--border-color); text-align: left;
}
.sg-corner { font-weight: 700; z-index: 3; }
.sg-posname { display: block; font-weight: 700; overflow-wrap: anywhere; }
.sg-sum { display: inline-block; margin-top: 2px; font-size: 12px; color: var(--muted-text); }
.sg-sum.is-full { color: var(--success-color); font-weight: 700; }
.sg-cell { min-width: 150px; }
.sg-cell > .sg-tile + .sg-tile { margin-top: 6px; }
.sg-none { display: block; text-align: center; opacity: .35; padding-top: 6px; }

.sg-tile {
    display: block; width: 100%; text-align: left; font: inherit; color: var(--text-color); cursor: pointer;
    border: 1px solid var(--border-color); border-left-width: 4px; border-radius: 6px; padding: 6px 8px;
    transition: transform .08s, box-shadow .08s;
}
.sg-tile:hover { box-shadow: 0 1px 6px rgba(0, 0, 0, .25); transform: translateY(-1px); }
.sg-tile:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
.sg-tile.is-active { outline: 2px solid var(--accent-color); outline-offset: 1px; box-shadow: 0 0 0 4px rgba(0, 172, 255, .18); }
.sg-tile-top { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; }
.sg-time { font-weight: 700; white-space: nowrap; }
.sg-count { font-weight: 700; white-space: nowrap; }
.sg-names { display: block; margin-top: 2px; font-size: 11px; color: var(--muted-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Seitenpanel */
.sg-panel-col[hidden], .sg-backdrop[hidden], .sg-slot-panel[hidden], .sg-row[hidden], .sg-table [data-col][hidden],
.sg-tile[hidden], #sg-next-open[hidden] { display: none !important; }
.sg-panel-bar { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 12px; }
.sg-panel-box { margin: 0 !important; }
.sg-slot-panel.assignment-slot { border: 0; padding: 0; background: none; }
.sg-slot-panel .assign-form .fields { flex-wrap: nowrap; }

@media (min-width: 1100px) {
    .sg-layout.has-panel { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 16px; align-items: start; }
    .sg-layout.has-panel .sg-panel-col { position: sticky; top: 84px; max-height: calc(100vh - 100px); overflow-y: auto; }
    .sg-backdrop { display: none !important; }
}
@media (max-width: 1099px) {
    .sg-panel-col {
        position: fixed; inset: 0; z-index: 1200; overflow-y: auto; background: var(--bg-color); padding: 12px;
    }
    .sg-panel-col .sg-panel-box { min-height: 100%; }
    .sg-backdrop { position: fixed; inset: 0; z-index: 1190; background: rgba(0, 0, 0, .5); }
    body.sg-panel-open { overflow: hidden; }
    .sg-dayhead, .sg-cell { min-width: 140px; }
}
@media (max-width: 600px) {
    .sg-corner, .sg-poshead { min-width: 96px; max-width: 110px; font-size: 13px; }
}

/* ---- Runde 143: Notiz je Schicht (Crew einteilen) ---- */
.sg-note-box { margin: 4px 0 14px; }
.sg-note-form .field { margin-bottom: 6px !important; }
.sg-note-form label, .sg-note-label { font-weight: 700; font-size: 13px; }
.sg-note-form textarea { font-size: 14px; }
.sg-note-text { font-size: 14px; margin-top: 2px; }
.sg-note-line {
    display: block; margin-top: 3px; font-size: 11px; font-style: italic; color: var(--text-color);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sg-note-line .icon { margin-right: 3px; font-size: 11px; opacity: .75; }
/* Runde 143: lange Namen/Notizen dürfen die Spaltenbreite des Rasters nicht aufblähen */
.sg-names, .sg-note-line { width: 0; min-width: 100%; }
.sg-table thead th.sg-corner { z-index: 4; }
.sg-table tbody th.sg-poshead { z-index: 2; }

/* ---- Runde 144: wichtige Ankündigungen (Systemadmin), angeheftet auf dem Dashboard ---- */
.important-announcements { display: flex; flex-direction: column; gap: 12px; margin: 0 0 18px; }
.important-announcement {
    border: 1px solid var(--danger-color);
    border-left-width: 8px;
    border-radius: 6px;
    padding: 14px 16px;
    background: rgba(219, 40, 40, .10);
    color: var(--text-color);
}
.important-announcement-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-bottom: 8px; }
.important-announcement-badge {
    display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px;
    background: var(--danger-color); color: #fff; font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
}
/* Runde 148: Icon-Glyph der Semantic-Schrift sitzt unter der Textmitte -> per Flex zentrieren und optisch anheben (wie bei .announcement-meta-chip) */
.important-announcement-badge .icon {
    margin: 0; display: inline-flex; align-items: center; justify-content: center;
    flex: none; width: 1.1em; height: 1.1em; line-height: 1;
    position: relative; top: 0.05em;
}
.important-announcement-badge .icon::before { display: block; line-height: 1; }
.important-announcement-title { margin: 0; font-size: 18px; }
.important-announcement-body { font-size: 15px; line-height: 1.5; overflow-wrap: anywhere; }
.important-announcement-foot {
    display: flex; justify-content: space-between; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px;
    font-size: 12px; color: var(--muted-text);
}
.announcement-meta-chip-important { background: var(--danger-color) !important; color: #fff !important; border-color: var(--danger-color) !important; font-weight: 700; }
.announcement-important-form { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin: 6px 0 10px; font-size: 13px; }
.announcement-important-form input[type=date] { padding: 4px 8px; font: inherit; border: 1px solid var(--border-color); border-radius: 4px; background: transparent; color: var(--text-color); }
.important-box { border: 1px solid var(--danger-color); border-left-width: 6px; border-radius: 6px; padding: 12px 14px; margin-bottom: 16px; background: rgba(219, 40, 40, .07); }

/* ---- Runde 145: Notiz je eingeteiltem Helfer (statt je Schicht) ---- */
.sg-assignees { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }
.sg-assignee-head { display: flex; align-items: center; margin-bottom: 4px; }
.sg-assignee-note-form { display: flex; gap: 6px; align-items: center; margin: 0; }
.sg-assignee-note-form input[type="text"] {
    flex: 1; min-width: 0; padding: 6px 10px; font-size: 14px;
    background: var(--input-bg, transparent); color: var(--text-color);
    border: 1px solid var(--border-color, rgba(255,255,255,.2)); border-radius: 4px;
}
.sg-assignee-note-form .button { margin: 0; flex: none; }
.sg-assignee-note-text { font-size: 14px; }
.sg-assignee-note-text .icon { margin-right: 4px; opacity: .75; }
.sg-legacy-note { border-left: 3px solid var(--warning-color); padding-left: 10px; }
.sg-legacy-note form { margin-top: 6px; }
.assign-form input[type="text"] {
    width: 100%; padding: 9px 12px; font-size: 14px;
    background: var(--input-bg, transparent); color: var(--text-color);
    border: 1px solid var(--border-color, rgba(255,255,255,.2)); border-radius: 4px;
}
/* Runde 145 (Folgekorrektur): Zeile 1 = Auswahl + Hinzufügen, Zeile 2 = Notiz über die volle Breite */
.ui.form.assign-form .fields { flex-wrap: wrap !important; gap: 8px 8px; }
.ui.form.assign-form .fields > .field { padding-left: 0 !important; padding-right: 0 !important; }
.ui.form.assign-form .assign-note-field { order: 3; flex: 1 1 100% !important; width: 100% !important; margin: 0 !important; }
.ui.form.assign-form .assign-note-field input[type="text"] { width: 100%; }


/* ---- Runde 150: wichtige Ankündigung minimierbar ---- */
.important-announcement-toggle {
    margin-left: auto; display: inline-flex; align-items: center; gap: 6px; flex: none;
    background: transparent; color: var(--text-color); border: 1px solid var(--danger-color);
    border-radius: 999px; padding: 3px 12px 3px 8px; font: inherit; font-size: 12px; cursor: pointer;
}
.important-announcement-toggle:hover, .important-announcement-toggle:focus-visible { background: rgba(219, 40, 40, .25); }
.important-announcement-toggle .icon {
    margin: 0; display: inline-flex; align-items: center; justify-content: center;
    width: 1em; height: 1em; line-height: 1; position: relative; top: 0.05em;
}
.important-announcement-toggle .icon::before { display: block; line-height: 1; }
.important-announcement-until-short { display: none; font-size: 12px; color: var(--muted-text); }
.important-announcement.is-collapsed { padding-top: 9px; padding-bottom: 9px; }
.important-announcement.is-collapsed .important-announcement-head { margin-bottom: 0; }
.important-announcement.is-collapsed .important-announcement-title {
    font-size: 16px; min-width: 0; flex: 1 1 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.important-announcement.is-collapsed .important-announcement-until-short { display: inline; }
.important-announcement-content[hidden] { display: none; }
@media (max-width: 600px) {
    .important-announcement.is-collapsed .important-announcement-until-short { display: none; }
    .important-announcement-toggle-label { display: none; }
    .important-announcement-toggle { padding: 4px 8px; }
}
