/* =============================================================================
   SCHULUNGSPORTAL · DESIGN-SYSTEM
   -----------------------------------------------------------------------------
   Aufbau:
     1. Tokens werden separat geladen: assets/css/tokens.css
     2. Reset & Basis-Elemente
     3. App-Shell (Sidebar, Topbar, Content)
     4. Navigation
     5. Suche (Topbar-Trigger + Spotlight)
     6. Komponenten-Primitives (.ui-*)
     7. Utilities
     8. Datenansichten (Admin-Tabellen)
    8b. Gemeinsame View-Bausteine
     9. Responsive
    10. Print
   -----------------------------------------------------------------------------
   Dark Mode laeuft ueber die Klasse .dark-mode am <html>-Element. Alle
   bisherigen Variablennamen bleiben erhalten, damit bestehende Views
   unveraendert weiterlaufen.
   ============================================================================= */

/* =============================================================================
   2. RESET & BASIS-ELEMENTE
   ============================================================================= */
html, body, input, button, select, textarea { font-family: var(--font-stack) !important; }
html { -webkit-text-size-adjust: 100%; }

/* Basis – gilt auf jeder Seite, auch auf den eigenstaendigen (Login,
   Registrierung, Nutzungsbedingungen, Meeting-Raum). */
body {
    margin: 0;
    padding: 0;
    background-color: var(--bg-app);
    color: var(--text-primary);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    letter-spacing: -0.005em;
    transition: background-color var(--duration-slow) var(--ease), color var(--duration-slow) var(--ease);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Shell-Layout – nur dort, wo Seitenleiste und Topbar tatsaechlich stehen.
   Diese Regeln hingen frueher direkt an <body>. Dadurch konnten die
   eigenstaendigen Seiten das Design-System gar nicht laden, ohne dass ihre
   eigene Zentrierung zerbrochen waere – und genau deshalb brachte jede von
   ihnen ihre eigenen Buttons, Felder und Farben mit. */
body.app-shell {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    width: 100vw;
    overflow-x: hidden;
    overflow-y: auto;
}

/* Dezenter Hintergrund – feines Halbton-Punktraster, das von links (fast
   unsichtbar) nach rechts (deutlicher, groessere Punkte) einlaeuft, ganz
   wie eine Rastertonung im Druck. Sitzt als eigenes ::before-Element fix
   hinter dem gesamten Inhalt, NICHT als background-image direkt am body:
   ein mask-image auf body wuerde sonst auch Text und Karten ausblenden,
   nicht nur den Hintergrund.

   Der Groesseneffekt (kleine Punkte links, groessere rechts) kommt ohne
   Bilddatei aus: drei identische Punktraster uebereinander, jedes mit
   eigenem Punktradius, jedes ueber eine eigene mask-image-Ebene erst ab
   einer anderen Stelle eingeblendet. CSS erlaubt fuer mask-image dieselbe
   Mehrfachebenen-Syntax wie fuer background-image – Ebene 1 der Maske
   gehoert zu Ebene 1 des Hintergrunds usw. So wachsen die Punkte in drei
   Stufen an, statt nur heller/dunkler zu werden – das war der Unterschied
   zur ersten Fassung, die nur die Deckkraft veraendert hat.

   Bewusst als reines CSS-Muster statt Bilddatei: bleibt bei jeder
   Bildschirmgroesse und jedem Zoom gestochen scharf, es gibt keine Datei zu
   pflegen oder auszuliefern.

   Die Punktfarbe ist --border-strong – derselbe neutrale Graublau-Ton, den
   auch Eingabefelder und Checkboxen als Rahmenfarbe verwenden. Bewusst
   NICHT --accent-color/--accent-border: das kraeftige Markenblau war als
   Flaechenfarbe zu praesent und zog zu viel Aufmerksamkeit auf sich, wo
   die Flaeche eigentlich zurueckhaltend bleiben soll. --border-strong ist
   in beiden Farbschemata hinterlegt, das Muster passt sich damit
   automatisch an den Dark Mode an. Die Deckkraft bleibt niedrig: der Farbschleier auf den
   Flaechen wurde beim Redesign bewusst entfernt (siehe --bg-app-tint in
   tokens.css), weil er Weiss auf Weiss schwer unterscheidbar machte – ein
   Punktraster mit viel Zwischenraum, nicht eine Flaechenfarbe, verletzt das
   nicht, muss aber trotzdem zurueckhaltend bleiben.

   Liegt an <body>, nicht an .mac-main-content: dadurch gilt es fuer jede
   Seite, auch die eigenstaendigen ohne .app-shell (Anmeldung, Registrierung,
   Nutzungsbedingungen, Besprechungsraum). Die Seitenleiste hat eine eigene
   deckende Flaechenfarbe (--bg-sidebar) und liegt mit z-index: var(--z-sidebar)
   darueber – das Muster scheint dort nicht durch. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
        radial-gradient(circle, var(--border-strong) 0.4px, transparent 0.75px),
        radial-gradient(circle, var(--border-strong) 0.7px, transparent 1.1px),
        radial-gradient(circle, var(--border-strong) 1.1px, transparent 1.6px);
    background-size: 20px 20px;
    /* Feste Pixel-Distanzen statt Prozent: bei Prozent lag die ruhige,
       punktfreie Zone am linken Rand proportional zur Fensterbreite – auf
       einem normal breiten Bildschirm (nicht dem 1600px-Testfenster) war
       davon kaum noch etwas uebrig, das Muster stand von der ersten
       Bildschirmspalte an in voller Staerke und fiel dadurch ueber
       Fliesstext. Mit festen Distanzen bleibt der ruhige Bereich immer
       gleich breit, unabhaengig von der Fensterbreite. */
    /* Die feinste Ebene beginnt am linken Bildschirmrand statt bei 260px.
       Die ruhige Zone lag genau ueber der Seitenleiste – solange die eine
       eigene Flaeche hatte, war das gleichgueltig, jetzt scheint der Grund
       durch und das Raster soll dort schon anfangen. Es baut sich ueber die
       Breite der Leiste sanft auf und steht am Beginn des Inhalts. Die
       beiden groeberen Ebenen bleiben unveraendert, damit sich der
       Inhaltsbereich nicht mitaendert. */
    -webkit-mask-image:
        linear-gradient(100deg, transparent 0, #000 420px, #000 100%),
        linear-gradient(100deg, transparent 0, transparent 620px, #000 980px, #000 100%),
        linear-gradient(100deg, transparent 0, transparent 980px, #000 1340px, #000 100%);
    mask-image:
        linear-gradient(100deg, transparent 0, #000 420px, #000 100%),
        linear-gradient(100deg, transparent 0, transparent 620px, #000 980px, #000 100%),
        linear-gradient(100deg, transparent 0, transparent 980px, #000 1340px, #000 100%);
    opacity: 0.32;
}

h1, h2, h3, h4 { letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); }
img, svg, video { max-width: 100%; }
::selection { background: var(--accent-soft); color: var(--text-primary); }
[hidden] { display: none !important; }

/* Fokus nur bei Tastaturbedienung – konsistent ueber die gesamte App */
/* Fokus nur bei Tastaturbedienung. Der Ring liegt aussen und bekommt einen
   Versatz, damit er auch auf gefuellten Flaechen (Primaerbutton, aktiver
   Menuepunkt) sichtbar bleibt und nicht mit deren Farbe verschmilzt. */
*:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}
/* Auf farbigen Flaechen zusaetzlich ein heller Innenring, damit der Fokus
   auf jedem Untergrund Kontrast hat. */
.ui-btn--primary:focus-visible,
.mac-btn-primary:focus-visible,
.ios-btn-primary:focus-visible,
.btn-approve:focus-visible,
.nav-link.active:focus-visible {
    box-shadow: 0 0 0 2px var(--bg-card);
}

/* Skip-Link fuer Screenreader- und Tastaturnutzung */
.skip-link {
    position: absolute;
    left: var(--space-4);
    top: -100px;
    z-index: var(--z-modal);
    background: var(--accent-color);
    color: var(--text-on-accent);
    padding: 10px 18px;
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    box-shadow: var(--shadow-md);
    transition: top var(--duration-base) var(--ease);
}
.skip-link:focus { top: var(--space-4); }

/* Scrollbars */
* { scrollbar-width: thin; scrollbar-color: var(--border-heavy) transparent; }
::-webkit-scrollbar { width: 12px; height: 12px; -webkit-appearance: none; }
::-webkit-scrollbar-track { background: transparent; margin: 4px; }
::-webkit-scrollbar-thumb {
    background: var(--border-heavy);
    border-radius: var(--radius-pill);
    border: 3.5px solid transparent;
    background-clip: padding-box;
    min-height: 44px;
    transition: background var(--duration-base) var(--ease);
}
::-webkit-scrollbar-thumb:hover { background: var(--accent-color); background-clip: padding-box; }

/* =============================================================================
   3. APP-SHELL
   ============================================================================= */
.mac-app-wrapper {
    display: flex;
    flex: 1;
    width: 100%;
    position: relative;
    min-height: 0;
}

.main-container {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    position: relative;
    height: 100%;
}

.mac-main-content {
    flex: 1;
    overflow-y: auto;
    position: relative;
    padding: clamp(20px, 2.6vw, 36px) var(--gutter) var(--space-12);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    min-height: 0;
    -webkit-overflow-scrolling: touch;
    scroll-behavior: smooth;
}

/* Markenzeichen (Sidebar + Mobile-Header) */
/* War ein blaues Feld mit weissem Kappen-Symbol (--accent-gradient +
   SVG). Jetzt das echte Vereinslogo – ein bereits farbiges, rundes
   Abzeichen mit eigenem Rand. Ein zusaetzlicher Farbchip dahinter wuerde
   nur mit den Logofarben konkurrieren, deshalb kein background mehr:
   das Logo fuellt die Flaeche direkt aus, rund statt eckig, weil es
   selbst schon rund ist. */
.brand-mark {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    overflow: hidden;
    box-shadow: var(--shadow-accent);
}
.brand-mark img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Das Zeichen in der Kopfzeile des Handys ist ein Link. Es misst 56px und
   erfuellt die Mindestgroesse fuer Beruehrung damit von selbst; der Rest
   sorgt nur dafuer, dass es sich nicht wie Text verhaelt. */
a.brand-mark-link { text-decoration: none; -webkit-tap-highlight-color: transparent; }
a.brand-mark-link:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }

/* Datum, Uhrzeit und Anwesenheit in der Kopfzeile des Handys. Eine schmale
   Zeile unter dem Seitentitel – nebeneinander waere auf 375px kein Platz.
   Sie erscheint nur dort, wo die obere Leiste fehlt; sonst staende dasselbe
   zweimal auf dem Schirm. */
.mobile-header-status { display: none; }
@media (max-width: 768px) {
    .mobile-header-status {
        /* Eigene Zeile ueber die volle Breite. Im Textblock neben Logo, Suche
           und Menue blieben ihr auf 375px rund 190 Pixel, und sie brach um –
           die Kopfzeile wurde 114 statt 89 Pixel hoch. Als eigene Zeile passt
           sie mit 343 Pixeln bequem in eine. */
        flex: 1 0 100%;
        display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
        margin-top: 4px;
        font-size: var(--text-xs);
        /* --text-secondary und nicht --text-muted: Die Zeile steht auf dem
           durchscheinenden Punktraster. Gemessen kam --text-muted dort auf
           2,9:1, weit unter den 4,5 aus tokens.css. Mit --text-secondary sind
           es 5,0:1 im ungueltigsten Fall. Die Trennpunkte bleiben blass – sie
           tragen keine Auskunft, sondern nur den Rhythmus. */
        color: var(--text-secondary);
        font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
    }
    .mobile-header-trenner { color: var(--text-muted); opacity: .7; }
    .mobile-anwesend { display: inline-flex; align-items: center; gap: 5px; }
    /* Derselbe Punkt wie in der oberen Leiste, nur kleiner. Die Farbe steuert
       .anwesend-punkt selbst – grau, solange niemand da ist. */
    .mobile-anwesend .anwesend-punkt { width: 7px; height: 7px; }
}

/* Sprechblase fuer die eingeklappte Seitenleiste. Sie steht fix im Fenster
   und haengt am <body>, weil der Navigationsbereich senkrecht rollt und alles
   abschneidet, was seitlich herausragt – siehe views/layouts/main.php.

   Der Akzent, wie beim aktiven Menuepunkt – die Leiste spricht damit eine
   Sprache. Ueber --accent-color und nicht ueber einen festen Blauwert: Das
   Token wechselt im Dunkelschema von #1b62d6 auf das etwas hellere #2971df,
   damit die Blase auf dunklem Grund nicht leuchtet. */
.seiten-hinweis {
    position: fixed; z-index: 200; pointer-events: none;
    left: 0; top: 0;
    transform: translateY(-50%) translateX(-4px);
    opacity: 0;
    transition: opacity var(--duration-base, .14s) var(--ease), transform var(--duration-base, .14s) var(--ease);
    background: var(--accent-color); color: var(--text-on-accent);
    padding: 7px 11px; border-radius: var(--radius-md);
    font-size: var(--text-sm); font-weight: 650; line-height: 1.2;
    white-space: nowrap; box-shadow: var(--shadow-lg);
}
.seiten-hinweis.sichtbar { opacity: 1; transform: translateY(-50%) translateX(0); }
/* Auf Handybreiten gibt es kein Einklappen und damit nichts zu erklaeren. */
@media (max-width: 768px) { .seiten-hinweis { display: none; } }
@media (prefers-reduced-motion: reduce) { .seiten-hinweis { transition: none; } }

/* --- Mobile-Header --- */
.mobile-header {
    display: none;
    /* Umbruch erlaubt, damit die Statuszeile eine eigene Zeile bekommt. */
    flex-wrap: wrap;
    /* Dieselbe Leiste wie .top-bar, nur die Fassung fuers Handy – also auch
       ohne eigene Flaeche. Sie steht statisch im Fluss und scrollt mit dem
       Inhalt weg, es zieht nichts hinter ihr vorbei. */
    background: transparent;
    padding: var(--space-3) var(--space-4);
    padding-top: max(var(--space-3), env(safe-area-inset-top));
    border-bottom: 1px solid var(--border-heavy);
    align-items: center;
    gap: var(--space-3);
    z-index: var(--z-header);
    flex-shrink: 0;
    transition: background var(--duration-slow) var(--ease);
}
.mobile-header-brand { display: flex; align-items: center; gap: var(--space-3); min-width: 0; flex: 1; }
.mobile-header-meta { display: flex; flex-direction: column; min-width: 0; }
.mobile-header-eyebrow {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--accent-text);
}
.mobile-header-title {
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: var(--tracking-tight);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.mobile-menu-btn {
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    cursor: pointer;
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    -webkit-tap-highlight-color: transparent;
    border-radius: var(--radius-md);
    flex-shrink: 0;
    transition: background var(--duration-base) var(--ease), transform var(--duration-base) var(--ease);
}
.mobile-menu-btn:active { transform: scale(0.94); background: var(--bg-hover); }

.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    background: var(--overlay-bg);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: var(--z-overlay);
    opacity: 0;
    transition: opacity var(--duration-slow) var(--ease);
}
.sidebar-overlay.active { display: block; opacity: 1; }

/* --- Sidebar --- */
/* Die Seitenleiste als dunkle Flaeche – die uebliche Form eines Dashboards
   und die einzige, die Rahmen und Inhalt sauber trennt: Der Inhaltsbereich ist
   hell, die Leiste dunkel, und man sieht auf einen Blick, was Bedienung ist und
   was Inhalt.

   Umgesetzt ueber die TOKENS, nicht ueber Einzelregeln: Die Leiste definiert
   --text-secondary, --bg-hover und die uebrigen fuer ihren eigenen Bereich neu,
   und jede Regel darin – Menuepunkte, Ueberschriften, Knoepfe, Trennlinien –
   nimmt die neuen Werte von selbst an. Sonst muesste jede einzelne davon
   angefasst und bei jeder kuenftigen Ergaenzung daran gedacht werden.

   Der Verlauf ist laut tokens.css der Wortmarke vorbehalten und erscheint nie
   auf Bedienelementen. Er traegt hier eine ganze Flaeche, kein Bedienelement –
   dieselbe Ausnahme wie auf der Anmeldeseite. */
.mac-sidebar {
    width: var(--sidebar-width);
    /* Gar keine eigene Flaeche: Der Grund der Seite scheint durch. Dahinter
       liegt body::before mit dem Halbton-Punktraster, das dadurch unter der
       Leiste weiterlaeuft statt an ihrer Kante aufzuhoeren. Beide Schemata
       stimmen von selbst, weil die Farbe vom body kommt.

       Auf dem Handy ist die Leiste eine Schublade ueber dem Inhalt – dort
       bekommt sie weiter unten wieder eine deckende Flaeche, sonst laege der
       Inhalt sichtbar dahinter. */
    background: transparent;
    position: relative;
    /* --border-heavy statt --border-color: Solange die Leiste eine eigene
       Flaeche hatte, trug die Kante sich selbst. Auf gemeinsamem Grund ist
       diese Linie das Einzige, was Navigation und Inhalt trennt, und
       --border-color kam dort auf 1,2:1 – praktisch unsichtbar. */
    border-right: 1px solid var(--border-heavy);
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    z-index: var(--z-sidebar);
    transition: width var(--duration-slow) var(--ease), transform var(--duration-slow) var(--ease),
                background var(--duration-slow) var(--ease), border-color var(--duration-slow) var(--ease);
}

/* Die Hoehe kommt aus derselben Variablen wie die der Kopfzeile. Beide
   Bloecke liegen nebeneinander am oberen Rand, ihre Unterkanten bilden EINE
   durchgehende Linie – vorher endete der Markenblock bei 97px und die
   Kopfzeile bei 65px, also zwei Striche auf verschiedener Hoehe. Mit der
   gemeinsamen Variablen koennen sie nicht mehr auseinanderlaufen.
   Deshalb height statt senkrechter Polsterung: Die Polsterung haette die
   Hoehe wieder vom Inhalt abhaengig gemacht. Und bewusst OHNE border-box –
   das Projekt rechnet durchgehend mit content-box, und .top-bar tut es
   auch. Mit border-box waere der Markenblock genau einen Pixel kuerzer
   geworden und die Linien haetten sich wieder um einen Pixel verfehlt. */
.sidebar-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: var(--topbar-height);
    padding: 0 var(--space-4);
    border-bottom: 1px solid var(--border-heavy);
    flex-shrink: 0;
    text-decoration: none;
    color: inherit;
    overflow: hidden;
}
/* 56px passten in den frueheren 97px-Block, in 64px nicht mehr – das Zeichen
   haette oben und unten die Linien beruehrt. Nur in der Leiste verkleinert;
   im Kopf des Handys bleibt es, wie es war. */
.mac-sidebar .brand-mark { width: 44px; height: 44px; }
.brand-text { display: flex; flex-direction: column; min-width: 0; overflow: hidden; }
.brand-title {
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.035em;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.brand-sub {
    font-size: var(--text-2xs);
    font-weight: 700;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mac-sidebar-nav {
    flex: 1;
    padding: var(--space-4) var(--space-3);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    -webkit-overflow-scrolling: touch;
}

.sidebar-collapse-wrapper {
    /* Dieselbe Staerke wie die uebrigen Begrenzungen der Huelle, sonst faellt
       sie als duennere Linie aus der Reihe. */
    border-top: 1px solid var(--border-heavy);
    padding: var(--space-3);
    background: var(--bg-sidebar);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    transition: background var(--duration-slow) var(--ease), border-color var(--duration-slow) var(--ease);
}
.user-profile-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-md);
    background: var(--bg-subtle);
    border: 1px solid var(--border-color);
}
.user-info {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    overflow: hidden;
    text-decoration: none;
    flex: 1;
    border-radius: var(--radius-sm);
    min-width: 0;
}
.user-info:hover .user-name { color: var(--accent-text); }
.user-avatar {
    width: 36px;
    height: 36px;
    border-radius: var(--radius-md);
    background: var(--accent-gradient);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 700;
    color: var(--text-on-accent);
    text-transform: uppercase;
    flex-shrink: 0;
    object-fit: cover;
}
.user-name {
    font-size: var(--text-sm);
    font-weight: 650;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color var(--duration-base) var(--ease);
}

.logout-btn {
    color: var(--danger-color);
    width: 34px;
    height: 34px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--duration-base) var(--ease), transform var(--duration-base) var(--ease);
    background: transparent;
    text-decoration: none;
    flex-shrink: 0;
    cursor: pointer;
}
.logout-btn:hover { background: var(--danger-soft); }
.logout-btn:active { transform: scale(0.92); }

.action-buttons-container { display: flex; flex-direction: column; gap: var(--space-2); }
.collapse-btn {
    background: transparent;
    border: 1px solid var(--border-color);
    color: var(--text-secondary);
    cursor: pointer;
    padding: 9px var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    border-radius: var(--radius-md);
    transition: background var(--duration-base) var(--ease), color var(--duration-base) var(--ease),
                border-color var(--duration-base) var(--ease), transform var(--duration-base) var(--ease);
    font-size: var(--text-sm);
    font-weight: 600;
    -webkit-tap-highlight-color: transparent;
}
.collapse-btn:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--border-heavy); }
.collapse-btn:active { transform: scale(0.98); background: var(--bg-hover); }
.collapse-btn svg { transition: transform var(--duration-slow) var(--ease); flex-shrink: 0; }

/* --- Eingeklappte Sidebar --- */
.mac-sidebar.collapsed { width: var(--sidebar-width-collapsed); }
.mac-sidebar.collapsed .sidebar-brand { justify-content: center; padding: 0 var(--space-2); }
.mac-sidebar.collapsed .brand-text { display: none; }
.mac-sidebar.collapsed .nav-heading { display: none !important; }
.mac-sidebar.collapsed .nav-text,
.mac-sidebar.collapsed .collapse-text { display: none; }
.mac-sidebar.collapsed .mac-sidebar-nav { padding: var(--space-4) var(--space-2); }
.mac-sidebar.collapsed .nav-link { justify-content: center; padding: var(--space-3) 0; }
.mac-sidebar.collapsed .nav-link svg { margin: 0; }
/* Der Zaehler bleibt eingeklappt SICHTBAR – er wandert nur ans Sinnbild.

   Vorher stand hier display:none. Damit verschwand die einzige Anzeige, dass
   etwas auf Bearbeitung wartet, sobald jemand die Leiste einklappte – und
   eingeklappt startet sie nach jeder Anmeldung. Ein offener Zugangsantrag war
   so nur zu sehen, wenn man die Leiste eigens aufzog.

   Als Pille neben dem Sinnbild geht es nicht: Eingeklappt ist die Leiste
   72 Pixel breit, davon nimmt der Menuepunkt nach Abzug der Polsterung rund
   56. Der Zaehler liegt deshalb ueber der oberen rechten Ecke des Sinnbilds,
   wie an einer App auf dem Telefon.

   Die Masse sind vom Sinnbild abgeleitet, nicht erfunden: Es ist 19 Pixel
   gross, der Zaehler 16 – klein genug, um daneben nicht zu erdruecken, gross
   genug fuer eine zweistellige Zahl in --text-2xs (11px). */
.mac-sidebar.collapsed .nav-badge {
    position: absolute;
    top: 50%;
    left: 50%;
    /* Auf die obere rechte Ecke, nicht auf das Sinnbild.

       Die Werte sind eingemessen, nicht geschaetzt: Der Menuepunkt ist
       eingeklappt 45 Pixel breit, das Sinnbild 19 davon (mittig, also von 21
       bis 40) – rechts daneben bleiben nur 13 Pixel. Ein Zaehler passt dort
       nicht ohne Ueberlappung; die Frage ist nur, wie viel.

       Der erste Anlauf war 24 Pixel breit und verdeckte 8 Pixel des
       Sinnbilds – fast die Haelfte seiner Breite – und ragte zugleich 4
       Pixel ueber die blaue Flaeche des aktiven Punktes hinaus. Jetzt sind
       es 18 Pixel Breite und rund 4 Pixel Ueberlappung: genug Beruehrung,
       dass der Zaehler zum Sinnbild gehoert, wenig genug, dass das Sinnbild
       erkennbar bleibt. */
    transform: translate(4px, -17px);
    margin-left: 0;
    min-width: 12px;
    height: 16px;
    padding: 0 3px;
    font-size: var(--text-2xs);
    /* Gegen den Grund der Leiste abgesetzt, damit der Zaehler nicht mit dem
       Sinnbild verschwimmt. Auf dem aktiven Menuepunkt uebernimmt die Regel
       weiter unten – dort ist der Ring weiss und voll deckend, weil Rot auf
       Azur exakt dieselbe Helligkeit hat (1,0:1). */
    box-shadow: 0 0 0 2px var(--bg-app);
}
.mac-sidebar.collapsed .user-name { display: none; }
.mac-sidebar.collapsed .logout-btn { display: none; }
.mac-sidebar.collapsed .user-profile-row { justify-content: center; background: transparent; border-color: transparent; padding: 0; }
.mac-sidebar.collapsed .user-info { flex: 0 0 auto; justify-content: center; }
.mac-sidebar.collapsed .sidebar-collapse-wrapper { padding: var(--space-3) var(--space-2); gap: var(--space-3); }
.mac-sidebar.collapsed .collapse-btn { padding: var(--space-3) 0; justify-content: center; }
.mac-sidebar.collapsed #sidebarCollapseBtn svg { transform: rotate(180deg); margin: 0; }

/* =============================================================================
   4. NAVIGATION
   ============================================================================= */
.nav-heading {
    font-size: var(--text-2xs);
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    /* Etwas enger als --tracking-wide: bei 0.08em brach "Kalender & Termine"
       in der Seitenleiste auf zwei Zeilen um. */
    letter-spacing: 0.055em;
    /* 14px statt 24px Abstand nach oben. Bei sechs Gruppen sind das 60 Pixel,
       die der Navigation fehlten. Der Abstand trennt die Gruppen weiterhin
       deutlich – er tat es vorher nur doppelt so aufwendig. */
    margin: 14px 0 var(--space-2) var(--space-3);
    white-space: nowrap;
}
.nav-heading:first-child { margin-top: 2px; }

.nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    /* 8px statt 10px senkrecht: Die Zeile ist damit 38 statt 42 Pixel hoch.
       Gemessen auf einem 900 Pixel hohen Fenster waren von 22 Menuepunkten
       neun sichtbar – die gesamte Verwaltung lag unter der Kante. Vier Pixel
       je Zeile klingen nach nichts und sind bei 22 Zeilen 88 Pixel.
       Nicht weiter: Bei 36 Pixeln faellt die Zeile unter das Mindestmass fuer
       Tippziele, das tokens.css mit --tap-target vorgibt. */
    padding: 8px var(--space-3);
    border-radius: var(--radius-md);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -0.012em;
    transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease),
                transform var(--duration-fast) var(--ease), box-shadow var(--duration-fast) var(--ease);
    margin-bottom: 2px;
    cursor: grab;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}
.nav-link:hover { background: var(--bg-hover); color: var(--text-primary); }
.nav-link:hover svg { color: var(--text-primary); }
.nav-link:active { cursor: grabbing; transform: scale(0.985); }
/* Aktiver Menuepunkt: eine Flaeche, kein Verlauf. Der Verlauf lag hier
   direkt neben der Wortmarke und liess beide um Aufmerksamkeit konkurrieren. */
/* Der aktive Punkt: helle Fuellung, dunkle Schrift. Die staerkste Umkehr, die
   auf dunkler Flaeche zur Verfuegung steht – und ohne Blau, weder in der
   Fuellung noch in der Schrift. */
/* Der aktive Punkt traegt wieder den Akzent. --accent-color und nicht ein
   fester Blauwert: Das Token wechselt im Dunkelschema von #1b62d6 auf das
   etwas hellere #2971df, damit es auf dunklem Grund nicht leuchtet.
   Dazwischen lag eine Fassung in --text-primary/--bg-app, als die Leiste
   ohne Blau auskommen sollte. */
.nav-link.active { background: var(--accent-color); color: var(--text-on-accent); font-weight: 700; box-shadow: var(--shadow-sm); }
.nav-link.active svg { color: var(--text-on-accent); }
.nav-link svg {
    color: var(--text-muted);
    width: 19px;
    height: 19px;
    flex-shrink: 0;
    stroke-width: 2;
    transition: color var(--duration-fast) var(--ease);
}
.nav-link.dragging { opacity: 0.5; background: var(--bg-hover); box-shadow: var(--shadow-md); }
.nav-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Die Gruppenueberschrift als Schalter. Sie sieht aus wie vorher – nur der
   Pfeil kommt dazu, und beim Ueberfahren zeigt sie, dass sie anklickbar ist.
   Die Gruppe darunter baut das Skript in views/layouts/main.php zur Laufzeit,
   damit im Markup nichts umgestellt werden muss. */
.nav-heading-knopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    width: calc(100% - var(--space-3));
    margin: 14px 0 var(--space-2) var(--space-3);
    padding: 2px 0;
    border: 0;
    background: none;
    cursor: pointer;
    font-family: inherit;
    color: var(--text-muted);
    text-align: left;
    border-radius: var(--radius-xs);
    transition: color var(--duration-fast) var(--ease);
}
.nav-heading-knopf > span {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.055em;
    white-space: nowrap;
}
.nav-heading-knopf:hover { color: var(--text-secondary); }
.nav-heading-knopf:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.nav-pfeil {
    width: 13px; height: 13px; flex: 0 0 auto;
    margin-right: var(--space-2);
    opacity: 0.65;
    transition: transform var(--duration-fast) var(--ease);
}
/* Zugeklappt zeigt der Pfeil nach rechts – die Richtung, in die sich die
   Gruppe oeffnen wuerde. */
.nav-heading-knopf[aria-expanded="false"] .nav-pfeil { transform: rotate(-90deg); }

/* Eingeklappte Seitenleiste: Dort gibt es keine Ueberschriften, also auch
   nichts zum Zuklappen – und die Gruppe muss offen sein, sonst waeren die
   Symbole weg. */
.mac-sidebar.collapsed .nav-heading-knopf { display: none; }
.mac-sidebar.collapsed .nav-gruppe { display: block !important; }

/* Zaehler-Badge: zeigt, wie viele neue Elemente es gibt (statt eines reinen
   "NEU", das den Menuetext verdraengt hat). */
.nav-badge {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    background: var(--danger-color);
    color: var(--on-danger);
    font-size: 11px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    border-radius: var(--radius-pill);
    line-height: 1;
    flex-shrink: 0;
}
/* Auf dem aktiven, blau gefuellten Menuepunkt wird der Zaehler abgedunkelt
   statt aufgehellt: eine weisse Auflage hellt das Blau so weit auf, dass die
   weisse Ziffer darauf nur noch 3,6:1 erreicht. Abgedunkelt sind es 8,0:1. */
.nav-link.active .nav-badge {
    background: rgba(0, 0, 0, 0.22);
    color: var(--text-on-accent);
    box-shadow: none;
}

/* =============================================================================
   5. TOPBAR & SUCHE
   ============================================================================= */
.top-bar {
    height: var(--topbar-height);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
    padding: 0 var(--gutter);
    flex-shrink: 0;
    z-index: 100;
    /* --border-heavy wie die rechte Kante der Seitenleiste: Die beiden Linien
       stossen in einer Ecke aneinander und duerfen nicht unterschiedlich
       schwer sein. Auf gemeinsamem Grund kam --border-color auf 1,2:1. */
    border-bottom: 1px solid var(--border-heavy);
    /* Ohne eigene Flaeche, wie die Seitenleiste – der Grund der Seite samt
       Punktraster laeuft durch.

       Die Milchglasfassung (--header-bg mit blur) war hier ohnehin ohne
       Wirkung: Die Leiste steht statisch in einer Flex-Spalte, der Inhalt
       scrollt in .mac-main-content DARUNTER in einem eigenen Kasten. Es zieht
       also nie etwas hinter ihr vorbei, das man haette weichzeichnen koennen –
       geblieben war nur die weisse Platte. Auf dem Handy uebernimmt
       .mobile-header, die weiter ihre deckende Flaeche behaelt: die liegt
       tatsaechlich ueber dem scrollenden Inhalt. */
    background: transparent;
}

.page-heading { display: flex; flex-direction: column; min-width: 0; }
.page-eyebrow {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--accent-text);
}
.page-title {
    margin: 0;
    font-size: var(--text-xl);
    line-height: var(--leading-tight);
    font-weight: 700;
    letter-spacing: -0.035em;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.top-bar-actions { display: flex; align-items: center; gap: var(--space-3); flex-shrink: 0; }

/* Der Sucheinstieg war ein blasser 280px-Knopf, der neben den Seitenaktionen
   unterging. Er ist jetzt breiter, hat eine ruhige Eingabefeld-Anmutung und
   eine eingefaerbte Lupe – so liest er sich als das, was er ist: das Suchfeld
   des Portals, nicht ein weiterer Knopf. */
.search-trigger {
    background: var(--bg-input);
    border: 1px solid var(--border-control);
    color: var(--text-muted);
    border-radius: var(--radius-md);
    padding: 0 var(--space-2) 0 var(--space-4);
    min-height: var(--tap-target);
    font-family: inherit;
    font-size: var(--text-sm);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    cursor: pointer;
    transition: border-color var(--duration-base) var(--ease), color var(--duration-base) var(--ease),
                box-shadow var(--duration-base) var(--ease), background var(--duration-base) var(--ease);
    width: clamp(240px, 26vw, 380px);
    max-width: 100%;
    white-space: nowrap;
}
.search-trigger:hover {
    border-color: var(--accent-color);
    color: var(--text-primary);
    background: var(--bg-card);
}
.search-trigger:hover .search-trigger-content svg { color: var(--accent-color); }
.search-trigger-content { display: flex; align-items: center; gap: 10px; overflow: hidden; }
.search-trigger-content span { text-overflow: ellipsis; overflow: hidden; font-weight: 500; }
.search-trigger-content svg {
    flex-shrink: 0;
    width: 17px;
    height: 17px;
    stroke-width: 2.3;
    color: var(--accent-text);
    transition: color var(--duration-base) var(--ease);
}

/* Sucheinstieg im mobilen Kopf. Unter 768px ist die Topbar ausgeblendet –
   ohne diesen Knopf gaebe es auf dem Telefon ueberhaupt keinen Weg zur Suche. */
.mobile-search-btn {
    display: none;
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    cursor: pointer;
    width: 42px;
    height: 42px;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--duration-base) var(--ease), transform var(--duration-base) var(--ease);
}
.mobile-search-btn:active { transform: scale(0.94); background: var(--bg-hover); }
.search-shortcut {
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    padding: 3px 8px;
    border-radius: 7px;
    font-size: 12px;
    font-family: var(--font-mono);
    font-weight: 600;
    color: var(--text-secondary);
    letter-spacing: 0.5px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* --- Spotlight --- */
.spotlight-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    z-index: var(--z-modal);
    align-items: flex-start;
    justify-content: center;
    padding: 14vh var(--space-5) var(--space-5);
    opacity: 0;
    transition: opacity var(--duration-base) var(--ease);
}
.spotlight-overlay.active { display: flex; opacity: 1; }
.spotlight-container {
    background: var(--modal-bg);
    backdrop-filter: blur(30px) saturate(180%);
    -webkit-backdrop-filter: blur(30px) saturate(180%);
    width: 100%;
    max-width: 620px;
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    border: 1px solid var(--border-color);
    overflow: hidden;
    transform: scale(0.96) translateY(-8px);
    transition: transform var(--duration-base) var(--ease);
}
.spotlight-overlay.active .spotlight-container { transform: scale(1) translateY(0); }

.spotlight-input-wrapper {
    display: flex;
    align-items: center;
    padding: var(--space-4) var(--space-6);
    border-bottom: 1px solid var(--border-color);
}
.spotlight-input-wrapper svg { color: var(--accent-text); width: 22px; height: 22px; flex-shrink: 0; }
.spotlight-input {
    border: none;
    background: transparent;
    flex: 1;
    font-size: var(--text-xl);
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--text-primary);
    padding: 0 var(--space-4);
    outline: none;
}
.spotlight-input::placeholder { color: var(--text-muted); }

.spotlight-results { max-height: 420px; overflow-y: auto; padding: var(--space-2); }
.spotlight-item {
    display: flex;
    align-items: center;
    padding: 10px var(--space-3);
    gap: var(--space-3);
    cursor: pointer;
    text-decoration: none;
    color: var(--text-primary);
    border-radius: var(--radius-md);
    transition: background var(--duration-fast) var(--ease);
}
.spotlight-item:hover,
.spotlight-item.selected { background: var(--accent-color); color: var(--text-on-accent); outline: none; }
.spotlight-item:hover .spot-desc,
.spotlight-item.selected .spot-desc { color: rgba(255, 255, 255, 0.82); }
.spotlight-item:hover svg,
.spotlight-item.selected svg { color: var(--text-on-accent); }

.spot-icon {
    width: 34px;
    height: 34px;
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    flex-shrink: 0;
}
.spotlight-item:hover .spot-icon,
.spotlight-item.selected .spot-icon { background: rgba(255, 255, 255, 0.22); }
.spot-details { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.spot-title { font-size: 14.5px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.spot-desc { font-size: 12px; color: var(--text-secondary); margin-top: 1px; }
.spot-empty { padding: var(--space-8); text-align: center; color: var(--text-muted); font-size: var(--text-sm); font-weight: 500; }

/* Ueberschrift je Trefferart (Ordner / Dateien / Personen) */
.spot-group {
    padding: var(--space-3) var(--space-3) var(--space-1);
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
}
.spot-group:first-child { padding-top: var(--space-2); }

/* Pfeil am Zeilenende: macht sichtbar, dass ein Treffer anklickbar ist und
   irgendwo hinfuehrt. Vorher sah die Liste aus wie reine Anzeige. */
.spot-go { flex-shrink: 0; opacity: 0; color: currentColor; transition: opacity var(--duration-fast) var(--ease); }
.spotlight-item:hover .spot-go,
.spotlight-item.selected .spot-go { opacity: 0.85; }
.spotlight-footer {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: 10px var(--space-6);
    border-top: 1px solid var(--border-color);
    font-size: var(--text-xs);
    color: var(--text-muted);
    font-weight: 500;
}
.spotlight-footer kbd {
    font-family: var(--font-mono);
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-xs);
    padding: 1px 5px;
    margin-right: 4px;
    font-size: var(--text-2xs);
}

/* --- Globale Wartungsmeldung --- */
#globalSystemMessage {
    display: none;
    position: sticky;
    top: 0;
    z-index: var(--z-banner);
    padding: var(--space-3) var(--space-5);
    font-size: var(--text-sm);
    font-weight: 650;
    letter-spacing: -0.01em;
    text-align: center;
    color: var(--text-on-accent);
    box-shadow: var(--shadow-md);
    animation: slideDownMsg var(--duration-slow) var(--ease);
}
@keyframes slideDownMsg {
    from { transform: translateY(-100%); }
    to { transform: translateY(0); }
}

/* =============================================================================
   6. KOMPONENTEN-PRIMITIVES
   Wiederverwendbare Bausteine fuer neue und schrittweise migrierte Views.
   ============================================================================= */

/* --- Seitenkopf innerhalb einer View --- */
.ui-page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-6);
}
.ui-page-header h1, .ui-page-header h2 { margin: 0 0 2px; font-size: var(--text-2xl); font-weight: 700; }
.ui-page-header p { margin: 0; color: var(--text-secondary); font-size: var(--text-sm); }

/* --- Karte --- */
.ui-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-6);
}
.ui-card--flush { padding: 0; overflow: hidden; }
.ui-card__header {
    padding: var(--space-4) var(--space-6);
    border-bottom: 1px solid var(--border-color);
    font-weight: 650;
}
.ui-card__body { padding: var(--space-6); }

/* --- Buttons --- */
.ui-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 10px var(--space-4);
    min-height: var(--tap-target);
    border-radius: var(--radius-md);
    border: 1px solid var(--border-color);
    background: var(--bg-card);
    color: var(--text-primary);
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--duration-base) var(--ease), border-color var(--duration-base) var(--ease),
                box-shadow var(--duration-base) var(--ease), transform var(--duration-base) var(--ease);
}
.ui-btn:active { transform: scale(0.98); }
.ui-btn:disabled, .ui-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; transform: none; }
.ui-btn svg { width: 16px; height: 16px; flex-shrink: 0; }

/* Primaeraktion: gedeckte Flaeche, keine Aufhellung per filter.
   brightness() verschiebt auch den Kontrast des Labels – der Hover-Zustand
   bekommt deshalb einen eigenen, geprueften Farbwert. */
.ui-btn--primary { background: var(--accent-color); color: var(--text-on-accent); box-shadow: var(--shadow-xs); }
.ui-btn--primary:hover { background: var(--accent-hover); }
.ui-btn--primary:active { background: var(--accent-active); }
.ui-btn--secondary { background: transparent; border-color: var(--border-color); color: var(--text-primary); }
.ui-btn--secondary:hover { background: var(--bg-hover); border-color: var(--border-heavy); }
.ui-btn--ghost { background: transparent; color: var(--text-secondary); }
.ui-btn--ghost:hover { background: var(--bg-hover); color: var(--text-primary); }
.ui-btn--danger { background: var(--danger-color); color: var(--on-danger); }
.ui-btn--danger:hover { background: var(--danger-hover); }
/* Kleine Buttons unterschreiten das 44px-Ziel bewusst – sie sind fuer dichte
   Tabellenzeilen gedacht. Damit sie trotzdem sicher treffbar bleiben, sorgt
   .action-group fuer den noetigen Abstand zwischen zwei Zielen. */
.ui-btn--sm { padding: 6px var(--space-3); min-height: 32px; font-size: var(--text-xs); border-radius: var(--radius-sm); }
.ui-btn--lg { padding: 13px var(--space-6); font-size: var(--text-base); }
.ui-btn--icon { padding: 0; width: var(--tap-target); height: var(--tap-target); }

/* --- Formularfelder --- */
.ui-field { display: flex; flex-direction: column; gap: 6px; }
.ui-label { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.ui-input, .ui-select, .ui-textarea {
    width: 100%;
    padding: 10px var(--space-3);
    min-height: var(--tap-target);
    border-radius: var(--radius-md);
    border: 1px solid var(--border-control);
    background: var(--bg-input);
    color: var(--text-primary);
    font-size: var(--text-sm);
    transition: border-color var(--duration-base) var(--ease), box-shadow var(--duration-base) var(--ease);
    box-sizing: border-box;
}
.ui-input:focus, .ui-select:focus, .ui-textarea:focus {
    outline: none;
    border-color: var(--accent-color);
    box-shadow: 0 0 0 3px var(--focus-ring-soft);
}
.ui-input::placeholder, .ui-textarea::placeholder { color: var(--text-muted); }
.ui-input:disabled, .ui-select:disabled, .ui-textarea:disabled {
    background: var(--bg-subtle); color: var(--text-muted); cursor: not-allowed;
}
.ui-hint { font-size: var(--text-xs); color: var(--text-muted); }

/* --- Badges & Chips --- */
.ui-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.02em;
    background: var(--bg-input);
    color: var(--text-secondary);
}
.ui-badge--accent { background: var(--accent-soft); color: var(--accent-text); }
.ui-badge--success { background: var(--success-soft); color: var(--success-color); }
.ui-badge--warning { background: var(--warning-soft); color: var(--warning-color); }
.ui-badge--danger { background: var(--danger-soft); color: var(--danger-color); }
.ui-badge--info { background: var(--info-soft); color: var(--info-color); }

/* --- Hinweisboxen --- */
.ui-alert {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--border-color);
    background: var(--bg-subtle);
    font-size: var(--text-sm);
    color: var(--text-secondary);
}
.ui-alert--accent { background: var(--accent-soft); border-color: transparent; color: var(--text-primary); }
.ui-alert--success { background: var(--success-soft); border-color: transparent; }
.ui-alert--warning { background: var(--warning-soft); border-color: transparent; }
.ui-alert--danger { background: var(--danger-soft); border-color: transparent; }

/* --- Tabellen --- */
.ui-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.ui-table th {
    text-align: left;
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border-color);
    white-space: nowrap;
}
.ui-table td { padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border-color); }
.ui-table tbody tr:last-child td { border-bottom: none; }
.ui-table tbody tr:hover { background: var(--bg-subtle); }
.ui-table-wrap { overflow-x: auto; border-radius: var(--radius-lg); border: 1px solid var(--border-color); background: var(--bg-card); }

/* =============================================================================
   Tabellen, die sich der Fensterbreite anpassen
   -----------------------------------------------------------------------------
   Zwei Stufen, je nachdem wie eng es wird:

   1. Bis hinunter zur Kartenbreite bleibt die Tabelle eine Tabelle und
      bekommt bei Bedarf eine waagrechte Bildlaufleiste. Wichtig ist dabei
      das min-width am <table>: ohne das quetscht der Browser die Spalten
      immer weiter zusammen, bis Knoepfe auf wenige Pixel schrumpfen (in der
      Teilnehmerliste gemessen: von 28px blieben 13px uebrig) und Texte in
      Einzelbuchstaben umbrechen. Lieber scrollen als unlesbar.

   2. Unter 760px wird jede Zeile zu einer Karte. Die Spaltenueberschrift
      wandert dabei vor den jeweiligen Wert – dafuer traegt jede Zelle ein
      data-label. Zellen ohne data-label (Auswahlkaestchen, Aktionsspalten)
      bleiben ohne Beschriftung.

   Dieses Muster gab es vorher dreimal einzeln in den Ansichten
   (admin_invitations, event_participants, activity), jedes Mal etwas
   anders. Ab hier steht es an einer Stelle; die Ansichten setzen nur noch
   die Klasse.
   ============================================================================= */
.ui-tabelle-anpassend { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Mindestbreite je Tabelle einstellbar: 640px passen fuer die breiten
   Verwaltungslisten, waeren fuer eine zweispaltige Tabelle in einer schmalen
   Seitenspalte aber zu viel und wuerden dort unnoetig Bildlauf erzwingen.
   Solche Ansichten setzen --tabelle-mindestbreite auf einen kleineren Wert
   oder 0. */
.ui-tabelle-anpassend > table { min-width: var(--tabelle-mindestbreite, 640px); }

@media (max-width: 760px) {
    /* Kein Scrollen mehr noetig, sobald die Zeilen zu Karten werden. */
    .ui-tabelle-anpassend { overflow-x: visible; }
    .ui-tabelle-anpassend > table { min-width: 0; }

    .ui-tabelle-anpassend thead { display: none; }
    .ui-tabelle-anpassend table,
    .ui-tabelle-anpassend tbody,
    .ui-tabelle-anpassend tr,
    .ui-tabelle-anpassend td { display: block; width: auto; }

    .ui-tabelle-anpassend tr {
        position: relative;
        margin-bottom: var(--space-3);
        padding: var(--space-2) 0;
        border: 1px solid var(--border-color);
        border-radius: var(--radius-lg);
        background: var(--bg-card);
    }
    .ui-tabelle-anpassend tr:last-child { margin-bottom: 0; }

    .ui-tabelle-anpassend td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: var(--space-4);
        padding: 7px var(--space-4);
        border-bottom: none;
        text-align: right;
        /* !important ist hier kein Notnagel, sondern noetig: mehrere Ansichten
           tragen white-space: nowrap als INLINE-Stil an einzelnen Zellen
           (sinnvoll in der Tabellenansicht, damit Datumsangaben nicht
           umbrechen). In der Kartenansicht ist genau das schaedlich – die
           Zeile ragt dann aus der Karte heraus. Gemessen: "geschlossen
           20.08.2026 • 10:14" stand 62px ueber dem Rand. Ein Inline-Stil
           laesst sich nur so ueberstimmen. */
        white-space: normal !important;
    }
    /* Lange Dateinamen ohne Leerzeichen sprengen sonst die Karte. */
    .ui-tabelle-anpassend td > * { min-width: 0; overflow-wrap: anywhere; }
    .ui-tabelle-anpassend td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-size: var(--text-2xs);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--text-muted);
        text-align: left;
    }
    /* Zellen ohne data-label bekommen keine leere Beschriftungsspalte,
       sondern nehmen die volle Breite ein. */
    .ui-tabelle-anpassend td:not([data-label]) { justify-content: flex-end; }
    .ui-tabelle-anpassend td:not([data-label])::before { content: none; }

    /* Eine Zelle ohne Beschriftung UND ohne Bedienelement traegt in der
       Kartenansicht nichts bei – sie erzeugt nur eine leere Zeile. Typischer
       Fall: eine Aktionsspalte, die je nach Zeile mal einen Knopf enthaelt
       und mal nicht.
       :has() wird von allen Browsern unterstuetzt, die auch die uebrigen
       hier verwendeten Merkmale koennen; wo es fehlt, bleibt die leere Zeile
       stehen – unschoen, aber nichts geht kaputt. */
    .ui-tabelle-anpassend td:not([data-label]):not(:has(button)):not(:has(a)):not([colspan]) {
        display: none;
    }

    /* Eine festgehaltene Spalte ergibt in der Kartenansicht keinen Sinn –
       es gibt keinen waagrechten Bildlauf mehr, an dem sie haengen koennte. */
    .ui-tabelle-anpassend td[style*="sticky"],
    .ui-tabelle-anpassend .tn-spalte-aktion { position: static; box-shadow: none; }

    /* Leerzeilen ("keine Eintraege") sollen nicht wie eine Karte aussehen. */
    .ui-tabelle-anpassend tr:has(td[colspan]) { border: none; background: transparent; }
    .ui-tabelle-anpassend td[colspan] { justify-content: center; text-align: center; }
    .ui-tabelle-anpassend td[colspan]::before { content: none; }
}

/* --- "NEU"-Kennzeichnung ---------------------------------------------------
   Wird an Dateien, Ordnern, Schulungsterminen und Zugangsanträgen verwendet.
   Lag vorher nur in views/dashboard.php; ab drei Verwendungen gehört sie hierher,
   damit die Kennzeichnung überall gleich aussieht. */
.new-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 8px;
    padding: 2px 7px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.06em;
    vertical-align: middle;
    white-space: nowrap;
    background: var(--danger-color);
    color: var(--on-danger, #fff);
    /* Steht die Marke in einem Flex-Bereich (Titelzeile der Dateiliste,
       Terminkarte), wuerde sie sonst wie jedes andere Kind mitgeschrumpft.
       Weil sie zugleich nicht umbrechen darf, ragt sie dann ueber den Rand
       und wird vom overflow:hidden des Bereichs abgeschnitten – gemessen:
       bei 260px Breite blieb von "NEUE INHALTE" nur "NEUE", bei 160px war
       sie ganz weg. Schrumpfen soll der Name, nicht die Marke. */
    flex: 0 0 auto;
}
.new-badge--content {
    background: var(--accent-soft);
    color: var(--accent-text, var(--accent-color));
}

/* --- Leerzustand --- */
.ui-empty { text-align: center; padding: var(--space-12) var(--space-6); color: var(--text-muted); }
.ui-empty svg { width: 40px; height: 40px; margin-bottom: var(--space-3); opacity: 0.5; }
.ui-empty h3 { margin: 0 0 4px; font-size: var(--text-lg); color: var(--text-primary); }
.ui-empty p { margin: 0; font-size: var(--text-sm); }

/* =============================================================================
   7. UTILITIES
   ============================================================================= */
.ui-stack { display: flex; flex-direction: column; gap: var(--space-4); }
.ui-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.ui-grid { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.ui-divider { height: 1px; background: var(--border-color); border: 0; margin: var(--space-6) 0; }
.ui-muted { color: var(--text-secondary); }
.ui-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* =============================================================================
   8. DATENANSICHTEN (Admin-Tabellen)
   -----------------------------------------------------------------------------
   Benutzerliste, Einladungen, Zugangsantraege, System-Protokoll und
   Sicherheits-Codes waren jeweils eigenstaendig gestaltet (.apple-table,
   .inv-table, .ios-table, .mac-btn, .ios-btn-primary, .pending-card ...).
   Hier liegt der gemeinsame Standard – die Views bringen nur noch ihre
   wirklich seitenspezifischen Regeln mit.
   ============================================================================= */

/* --- Seitencontainer --- */
.admin-container,
.pending-container,
.log-container,
.ios-container,
.data-container {
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
    padding-bottom: max(var(--space-10), env(safe-area-inset-bottom));
    color: var(--text-primary);
}

/* --- Seitenkopf innerhalb der View --- */
.mac-header,
.pending-header,
.ios-header,
.data-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}
.mac-title,
.pending-title,
.ios-title,
.data-header h1,
.data-header h2 {
    margin: 0 0 4px;
    font-size: var(--text-2xl);
    font-weight: 700;
    letter-spacing: var(--tracking-tight);
    color: var(--text-primary);
}
.mac-subtitle,
.pending-subtitle,
.ios-subtitle,
.data-header p {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-secondary);
    max-width: 68ch;
}

/* --- Karten --- */
.mac-card,
.maintenance-card,
.barometer-card,
.ios-form-card,
.data-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-6);
    margin-bottom: var(--space-6);
}
/* Der Aussenabstand stammt aus der Zeit, in der Karten immer untereinander
   standen. In einem Raster erzeugt er ungleich hohe Kacheln, weil er die
   letzte Reihe anders behandelt als die uebrigen. Innerhalb eines Rasters
   uebernimmt deshalb dessen gap den Abstand. */
.ui-grid > .mac-card,
.ui-grid > .data-card,
.ui-grid > .ios-form-card,
.ui-grid > .maintenance-card,
.ui-grid > .barometer-card,
[class$="-grid"] > .mac-card,
[class$="-grid"] > .data-card,
[class$="-grid"] > .widget-card,
[class$="-grid"] > .ios-form-card { margin-bottom: 0; }

.mac-card:last-child,
.data-card:last-child,
.ios-form-card:last-child { margin-bottom: 0; }

.card-header-title {
    margin: 0 0 var(--space-4);
    font-size: var(--text-lg);
    font-weight: 700;
    letter-spacing: var(--tracking-tight);
    color: var(--text-primary);
}

/* --- Tabellenrahmen: scrollt horizontal statt Spalten zu quetschen --- */
.table-container,
.inv-table-container,
.ios-table-container,
.data-table-wrap {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
}

/* --- Tabelle --- */
.apple-table,
.inv-table,
.ios-table,
.data-table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
    font-size: var(--text-sm);
    color: var(--text-primary);
}
.apple-table th,
.inv-table th,
.ios-table th,
.data-table th {
    padding: var(--space-3) var(--space-5);
    background: var(--bg-card);
    box-shadow: inset 0 -1px 0 var(--border-color);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
}
.apple-table td,
.inv-table td,
.ios-table td,
.data-table td {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border-color);
    vertical-align: middle;
    color: var(--text-primary);
}
.apple-table tbody tr:last-child td,
.inv-table tbody tr:last-child td,
.ios-table tbody tr:last-child td,
.data-table tbody tr:last-child td { border-bottom: none; }

.apple-table tbody tr,
.inv-table tbody tr,
.ios-table tbody tr,
.data-table tbody tr { transition: background var(--duration-fast) var(--ease); }
.apple-table tbody tr:hover,
.inv-table tbody tr:hover,
.ios-table tbody tr:hover,
.data-table tbody tr:hover { background: var(--bg-subtle); }

/* --- Sortierbare Spaltenkoepfe ---------------------------------------------
   Der Kopf ist ein echter <button> im <th>, kein klickbares <th>: nur so ist
   die Spalte per Tabulator erreichbar und meldet sich der Vorlesesoftware als
   bedienbar. Die Sortierrichtung steht als aria-sort an der Zelle. */
.sortier-kopf {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0;
    background: none;
    border: 0;
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
    white-space: nowrap;
}
.sortier-kopf:hover { color: var(--text-primary); }
.sortier-kopf.aktiv { color: var(--accent-text); }

/* Der Pfeil ist im Ruhezustand blass angedeutet, damit erkennbar bleibt, dass
   die Spalte ueberhaupt sortierbar ist – aber nicht so kraeftig, dass alle
   Spalten gleichzeitig nach "sortiert" aussehen. */
.sortier-pfeil::before {
    content: "↕";
    font-size: 11px;
    opacity: 0.45;
}
th[aria-sort="ascending"]  .sortier-pfeil::before { content: "↑"; opacity: 1; }
th[aria-sort="descending"] .sortier-pfeil::before { content: "↓"; opacity: 1; }

/* Zahlen und Aktionen rechtsbuendig, monospaced Ziffern */
.data-table .num,
.apple-table .num,
.col-num { text-align: right; font-variant-numeric: tabular-nums; }

/* --- Statusabzeichen: ein Aussehen, semantische Toenungen --- */
.role-badge,
.status-badge,
.ios-badge,
.pending-badge,
.log-badge,
.data-badge,
.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.03em;
    line-height: 1.5;
    white-space: nowrap;
    background: var(--bg-input);
    color: var(--text-secondary);
    border: 0;
}
/* Toenungen – Klassennamen der bestehenden Views */
.role-admin, .badge-red, .status-expired, .badge-expired, .badge-danger {
    background: var(--danger-soft); color: var(--danger-color);
}
.role-trainer, .badge-blue, .status-open, .badge-active, .badge-accent {
    background: var(--accent-soft); color: var(--accent-text);
}
.badge-green, .status-used, .badge-used, .badge-success {
    background: var(--success-soft); color: var(--success-color);
}
.badge-orange, .badge-warning, .pending-badge {
    background: var(--warning-soft); color: var(--warning-color);
}
.badge-purple { background: var(--accent-soft); color: var(--accent-color-2); }
.role-user, .badge-default, .badge-gray {
    background: var(--bg-input); color: var(--text-secondary);
}

/* Tönungen für die Aktivitätsgruppen (models/Activity.php).
   Bewusst keine neuen Farben erfunden, sondern auf die vorhandenen Paare
   abgebildet – die sind bereits auf Kontrast geprüft, in hell wie dunkel.
   Dass sich zwei Gruppen einen Ton teilen, ist unkritisch: Jedes Kennzeichen
   trägt seine Beschriftung, die Farbe hilft nur beim Wiedererkennen. */
.badge-teal   { background: var(--info-soft);   color: var(--info-color); }
.badge-indigo { background: var(--accent-soft); color: var(--accent-color-2); }
.badge-amber  { background: var(--warning-soft); color: var(--warning-color); }
.badge-slate  { background: var(--bg-input);    color: var(--text-secondary); }
.agb-status { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); font-weight: 600; }
.agb-ok { color: var(--success-color); }
.agb-pending { color: var(--warning-color); }

/* --- Buttons --- */
.mac-btn,
.ios-btn-primary,
.btn-action-pill,
.btn-danger-pill,
.btn-approve,
.btn-deny,
.data-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 9px var(--space-4);
    min-height: var(--tap-target);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 650;
    line-height: 1.2;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    box-sizing: border-box;
    transition: background var(--duration-base) var(--ease), border-color var(--duration-base) var(--ease),
                box-shadow var(--duration-base) var(--ease), transform var(--duration-base) var(--ease);
}
.mac-btn svg,
.ios-btn-primary svg,
.btn-action-pill svg,
.btn-danger-pill svg,
.btn-approve svg,
.btn-deny svg { width: 16px; height: 16px; flex-shrink: 0; }

.mac-btn:active,
.ios-btn-primary:active,
.btn-action-pill:active,
.btn-danger-pill:active,
.btn-approve:active,
.btn-deny:active { transform: scale(0.98); }

/* Primaeraktion */
.mac-btn-primary,
.mac-btn-accent,
.ios-btn-primary,
.btn-approve {
    background: var(--accent-color);
    color: var(--text-on-accent);
    box-shadow: var(--shadow-xs);
}
.mac-btn-primary:hover,
.mac-btn-accent:hover,
.ios-btn-primary:hover,
.btn-approve:hover { background: var(--accent-hover); }
.mac-btn-primary:active,
.mac-btn-accent:active,
.ios-btn-primary:active,
.btn-approve:active { background: var(--accent-active); }

/* Sekundaeraktion */
.mac-btn-secondary,
.btn-action-pill {
    background: transparent;
    color: var(--text-primary);
    border-color: var(--border-color);
}
.mac-btn-secondary:hover,
.btn-action-pill:hover {
    background: var(--bg-hover);
    border-color: var(--border-heavy);
    color: var(--text-primary);
}

/* Gefaehrliche Aktion */
.mac-btn-danger,
.btn-danger-pill,
.btn-deny {
    background: var(--danger-soft);
    color: var(--danger-color);
    border-color: transparent;
}
.mac-btn-danger:hover,
.btn-danger-pill:hover,
.btn-deny:hover { background: var(--danger-color); color: var(--on-danger); border-color: var(--danger-color); }

/* Icon-Button */
.ios-icon-btn,
.data-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-target);
    height: var(--tap-target);
    padding: 0;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-color);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background var(--duration-base) var(--ease), color var(--duration-base) var(--ease),
                border-color var(--duration-base) var(--ease);
}
.ios-icon-btn:hover,
.data-icon-btn:hover { background: var(--bg-hover); color: var(--text-primary); border-color: var(--border-heavy); }
.ios-icon-btn.danger:hover,
.data-icon-btn.danger:hover { background: var(--danger-soft); color: var(--danger-color); border-color: transparent; }

.action-group,
.pending-actions,
.data-actions { display: flex; align-items: center; gap: var(--space-2); justify-content: flex-end; flex-wrap: wrap; }

/* --- Werkzeugleiste, Suche, Auswahlfelder --- */
.mac-toolbar,
.data-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}
.mac-search,
.mac-select,
.ios-select,
.ios-input,
.maintenance-input,
.maintenance-select,
.mac-input,
.mac-textarea,
.data-input {
    padding: 10px var(--space-3);
    min-height: var(--tap-target);
    border-radius: var(--radius-md);
    border: 1px solid var(--border-control);
    background: var(--bg-input);
    color: var(--text-primary);
    font-family: inherit;
    font-size: var(--text-sm);
    outline: none;
    box-sizing: border-box;
    transition: border-color var(--duration-base) var(--ease), box-shadow var(--duration-base) var(--ease);
}
.mac-search:focus,
.mac-select:focus,
.ios-select:focus,
.ios-input:focus,
.maintenance-input:focus,
.maintenance-select:focus,
.mac-input:focus,
.mac-textarea:focus,
.data-input:focus {
    border-color: var(--accent-color);
    box-shadow: 0 0 0 3px var(--focus-ring-soft);
}
/* Groessen, die die Views vorher selbst mitbrachten.
   Die Wunschbreite steckt bereits in der flex-basis (240px). Ein zusaetzliches
   min-width verhindert nur das Schrumpfen – in zweispaltigen Zeilen
   (Vorname / Nachname) ragte das zweite Feld dadurch aus seiner Karte heraus.
   min-width: 0 laesst Flexbox die Spalten korrekt aufteilen. */
.mac-input, .data-input { flex: 1 1 240px; min-width: 0; }
.mac-textarea, .data-textarea { width: 100%; min-height: 100px; resize: vertical; line-height: 1.5; }

/* Tabellen unter die Mindestbreite zu quetschen macht sie unlesbar –
   darunter scrollt der Rahmen horizontal. */
.apple-table, .inv-table, .ios-table, .data-table { min-width: min(640px, 100%); }

/* Zweizeilige Statusabzeichen (z. B. "Offen / bis 24.08.") */
.status-badge { padding: 6px 12px; line-height: 1.35; white-space: normal; text-align: left; }

/* Suchfeld mit vorangestelltem Icon */
.search-box,
.data-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1;
    min-width: 240px;
}
.search-box svg,
.data-search svg {
    position: absolute;
    left: 13px;
    width: 16px;
    height: 16px;
    color: var(--text-muted);
    pointer-events: none;
}
.search-box input,
.data-search input { width: 100%; padding-left: 38px; }

/* Auswahlfelder: eigener Pfeil, deshalb rechts mehr Platz.
   .ui-select fehlte hier bis zum 28.09.2026 – Safari zeichnete es als
   kleines natives Feld, das weder zur Höhe noch zum Rahmen der übrigen
   Eingaben passte. */
.ui-select,
.mac-select,
.ios-select,
.maintenance-select,
.data-select {
    padding-right: 38px;
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
    background-repeat: no-repeat;
    background-position: right 13px center;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23808a9b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

/* Kopfzeile: steht der Beschreibungstext direkt in der Kopfzeile,
   bekommt er eine eigene Zeile statt rechts neben dem Titel zu landen. */
.mac-header > .mac-subtitle,
.pending-header > .pending-subtitle,
.ios-header > .ios-subtitle { flex: 1 0 100%; order: 2; margin-top: -2px; }

.ios-label,
.data-label {
    display: block;
    margin-bottom: 6px;
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

/* --- Hinweisbanner --- */
.status-banner,
.ios-alert,
.data-banner {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-5);
    font-size: var(--text-sm);
    font-weight: 600;
}
.banner-success, .ios-alert-success { background: var(--success-soft); color: var(--success-color); }
.banner-error, .ios-alert-error { background: var(--danger-soft); color: var(--danger-color); }

/* --- Leerzustand --- */
.empty-state-box,
.data-empty {
    text-align: center;
    padding: var(--space-12) var(--space-6);
    background: var(--bg-card);
    border: 1px dashed var(--border-color);
    border-radius: var(--radius-lg);
}
.empty-icon, .data-empty svg { color: var(--text-muted); margin-bottom: var(--space-3); }
.empty-title { font-size: var(--text-lg); font-weight: 700; color: var(--text-primary); margin-bottom: 4px; }
.empty-desc { font-size: var(--text-sm); color: var(--text-secondary); }

/* --- Monospace-Codes (Sicherheits-Codes) --- */
.code-mono {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    font-weight: 650;
    letter-spacing: 0.08em;
    padding: 4px 10px;
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    color: var(--text-primary);
    cursor: pointer;
    transition: background var(--duration-base) var(--ease);
}
.code-mono:hover { background: var(--accent-soft); color: var(--accent-text); }

@media (max-width: 820px) {
    .mac-header,
    .pending-header,
    .ios-header,
    .data-header { flex-direction: column; align-items: stretch; }
    .mac-title,
    .pending-title,
    .ios-title { font-size: var(--text-xl); }
    .action-group,
    .data-actions { justify-content: flex-start; }
}


/* =============================================================================
   8b. GEMEINSAME VIEW-BAUSTEINE
   -----------------------------------------------------------------------------
   Diese Klassen standen bisher in den <style>-Bloecken der einzelnen Views –
   .page-header in 7 Views, .mac-modal in 20, .apple-table in 31, jeweils mit
   leicht abweichenden Werten. Dadurch sah dieselbe Komponente auf jeder Seite
   ein wenig anders aus, und jede Aenderung musste 7- bis 31-mal nachgezogen
   werden. Hier steht jede von ihnen genau einmal.

   Die Klassennamen bleiben unveraendert. Sie sind historisch gewachsen
   (mac-, ios-, apple-, finder-) und beschreiben keine Plattform mehr, sondern
   nur noch eine Rolle. Umbenennen haette jedes Markup und jedes Skript
   angefasst – ein Risiko ohne gestalterischen Gewinn.
   ============================================================================= */

/* --- Seitenkopf ---------------------------------------------------------- */
.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}
/* Der Seitenkopf war frueher eine eigene Karte mit Rahmen und Schatten. Er
   stand damit optisch auf einer Stufe mit dem Inhalt darunter und hat die
   Seite oben schwer gemacht. Jetzt ist er reine Typografie. */
/* Bewusst auf .page-header eingegrenzt: ein ungebundenes h1.page-title haette
   hoehere Spezifitaet als die Topbar-Regel .page-title und deren Titel
   mitvergroessert. Topbar und Seitenkopf sind zwei Ebenen, nicht eine. */
.page-header .page-title,
.page-header h1,
.page-header h2 {
    margin: 0 0 2px;
    font-size: var(--text-2xl);
    font-weight: 700;
    letter-spacing: var(--tracking-tight);
    line-height: var(--leading-tight);
    color: var(--text-primary);
}
.page-subtitle {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-secondary);
    max-width: var(--measure);
}
.page-header > .page-subtitle { flex: 1 0 100%; order: 2; }
.page-header-actions,
.explorer-header-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* --- Buttons: .btn-primary / .btn-secondary ------------------------------ */
.btn-primary,
.btn-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 10px var(--space-4);
    min-height: var(--tap-target);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    box-sizing: border-box;
    transition: background var(--duration-base) var(--ease),
                border-color var(--duration-base) var(--ease),
                color var(--duration-base) var(--ease);
}
.btn-primary svg, .btn-secondary svg { width: 16px; height: 16px; flex-shrink: 0; }
.btn-primary { background: var(--accent-color); color: var(--text-on-accent); }
/* Kein transform beim Hover mehr: der Button sprang unter dem Zeiger weg und
   verschob in Werkzeugleisten die Nachbarn. */
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-active); }
.btn-secondary { background: var(--bg-card); color: var(--text-primary); border-color: var(--border-color); }
.btn-secondary:hover { background: var(--bg-hover); border-color: var(--border-heavy); }
.btn-primary:disabled, .btn-secondary:disabled,
.btn-primary[aria-disabled="true"], .btn-secondary[aria-disabled="true"] {
    opacity: 0.5; cursor: not-allowed;
}

/* --- Karten -------------------------------------------------------------- */
.widget-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-6);
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    transition: border-color var(--duration-base) var(--ease),
                box-shadow var(--duration-base) var(--ease);
}
/* Anklickbare Karten heben sich beim Hover ueber Rahmen und Schatten hervor,
   nicht mehr ueber ein translateY(-4px). Der Sprung liess ganze Raster
   zappeln, sobald der Zeiger darueber lief. */
a.widget-card:hover,
.widget-card[role="button"]:hover,
.widget-card[onclick]:hover { border-color: var(--accent-border); box-shadow: var(--shadow-md); }

.card-title {
    margin: 0 0 var(--space-4);
    font-size: var(--text-lg);
    font-weight: 650;
    letter-spacing: var(--tracking-tight);
    color: var(--text-primary);
}

/* --- Formularfelder ------------------------------------------------------ */
.form-group { margin-bottom: var(--space-5); min-width: 0; }
.form-group > label {
    display: block;
    margin-bottom: 6px;
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

/* --- Modal / Dialog ------------------------------------------------------ */
/* Wird in den Views auf zwei Arten geoeffnet: ueber die Klasse .active und
   ueber style.display = 'flex'. Deshalb steuert hier ausschliesslich display
   die Sichtbarkeit – eine Grundopazitaet von 0 wuerde alle Dialoge unsichtbar
   machen, die nur die Inline-Variante nutzen. */
.mac-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    align-items: center;
    justify-content: center;
    padding: var(--space-5);
    background: var(--overlay-bg);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-sizing: border-box;
}
.mac-modal.active { display: flex; }

.mac-modal-content,
.mac-alert-box {
    background: var(--modal-bg);
    width: 100%;
    max-width: 520px;
    border-radius: var(--radius-xl);
    border: 1px solid var(--border-color);
    box-shadow: var(--shadow-lg);
    max-height: min(90vh, 90dvh);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-sizing: border-box;
}
.mac-alert-box { max-width: 420px; }

/* flex: 1 1 auto laesst laengere Dialoginhalte (z. B. das Anmeldeformular zu
   einem Termin) innerhalb des Dialogs scrollen, statt ihn ueber den
   Bildschirmrand hinauswachsen zu lassen. */
.alert-content {
    padding: var(--space-6);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    flex: 1 1 auto;
}
.alert-title {
    margin: 0 0 var(--space-2);
    font-size: var(--text-lg);
    font-weight: 650;
    letter-spacing: var(--tracking-tight);
    color: var(--text-primary);
}
.alert-text { margin: 0; font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--text-secondary); }

.alert-actions {
    display: flex;
    border-top: 1px solid var(--border-color);
    background: var(--bg-subtle);
    flex-shrink: 0;
}
.alert-btn {
    flex: 1;
    padding: var(--space-4);
    min-height: var(--tap-target);
    background: transparent;
    border: none;
    border-right: 1px solid var(--border-color);
    font-family: inherit;
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--accent-text);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease);
    -webkit-tap-highlight-color: transparent;
}
.alert-btn:last-child { border-right: none; }
.alert-btn:hover { background: var(--bg-hover); }
/* Abbrechen ist die ruhige Option, Loeschen die laute. Vorher waren beide
   gleich gewichtet – man konnte den Unterschied nur am Text erkennen. */
.alert-btn.cancel { color: var(--text-secondary); font-weight: 500; }
.alert-btn.danger, .alert-btn.destructive { color: var(--danger-color); }
.alert-btn.success { color: var(--success-color); }

/* --- Dateiliste / "Finder" ----------------------------------------------- */
.finder-main { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.finder-header {
    padding: var(--space-5) var(--space-6) var(--space-4);
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-card);
    z-index: 10;
}
.finder-content { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.finder-input {
    width: 100%;
    box-sizing: border-box;
    padding: 10px var(--space-4);
    min-height: var(--tap-target);
    background: var(--bg-input);
    border: 1px solid var(--border-control);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--text-sm);
    color: var(--text-primary);
    outline: none;
    -webkit-appearance: none;
    transition: border-color var(--duration-base) var(--ease), box-shadow var(--duration-base) var(--ease);
}
/* Platz für die Lupe.
   Das Feld hatte links 16 px Polsterung, das Symbol sitzt aber bei 12 px und
   ist 16 px breit – der Text begann also genau darunter. Auf jedem Bildschirm
   sichtbar als "⊙Nach Dateien suchen…". */
.search-wrapper .finder-input { padding-left: 38px; }
.finder-input::placeholder { color: var(--text-muted); }
.finder-input:focus { border-color: var(--accent-color); box-shadow: 0 0 0 3px var(--focus-ring-soft); }

/* --- Kleine Bedienelemente in Listen und Werkzeugleisten ------------------ */
.action-pill {
    width: 34px;
    height: 34px;
    border-radius: var(--radius-sm);
    background: transparent;
    border: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    cursor: pointer;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
}
.action-pill:hover { background: var(--bg-hover); color: var(--text-primary); }
.action-pill.danger:hover { background: var(--danger-soft); color: var(--danger-color); }
.action-pill.success:hover { background: var(--success-soft); color: var(--success-color); }

/* Segmentierte Umschalter (Listen-/Kachelansicht, Zeitraum-Filter) */
.mode-switch,
.view-switch {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}
.view-btn,
.seg-btn {
    background: transparent;
    border: none;
    padding: 7px var(--space-3);
    min-height: 34px;
    border-radius: var(--radius-xs);
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
}
.view-btn:hover, .seg-btn:hover { color: var(--text-primary); }
/* Der aktive Zustand wird ueber Flaeche UND Schriftgewicht markiert, nicht nur
   ueber Farbe – sonst ist er fuer farbfehlsichtige Nutzer nicht erkennbar
   (WCAG 1.4.1). */
.view-btn.active, .seg-btn.active {
    background: var(--bg-card);
    color: var(--text-primary);
    font-weight: 700;
    box-shadow: var(--shadow-xs);
}

/* --- Personenzeile (Benutzerliste, Protokoll, Teamgruppen) ---------------- */
.user-pill { display: inline-flex; align-items: center; gap: var(--space-3); min-width: 0; }
.avatar {
    width: 34px;
    height: 34px;
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    color: var(--accent-text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-sm);
    font-weight: 700;
    text-transform: uppercase;
    flex-shrink: 0;
    object-fit: cover;
}

/* --- Layout-Huelle fuer eigenstaendige Seiten ----------------------------- */
.app-container {
    width: 100%;
    max-width: var(--content-max);
    margin: 0 auto;
    padding-bottom: max(var(--space-10), env(safe-area-inset-bottom));
}

/* --- Hilfsklassen, die mehrere Views mitbrachten -------------------------- */
@media (max-width: 768px) {
    .hide-mobile { display: none !important; }
}

/* =============================================================================
   9. RESPONSIVE
   ============================================================================= */
@media (max-width: 768px) {
    body.app-shell { position: relative; overflow-y: auto; }
    .mac-app-wrapper { flex-direction: column; height: 100%; }
    .mobile-header { display: flex; }
    .mac-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        height: 100dvh;
        transform: translateX(-100%);
        box-shadow: var(--shadow-lg);
        width: 288px !important;
        /* Hier liegt die Leiste UEBER dem Inhalt, nicht daneben. Durchsichtig
           wuerde man die Seite durch die Navigation hindurch lesen. */
        background: var(--bg-app);
    }
    .mac-sidebar.open { transform: translateX(0); }

    .top-bar { display: none; }

    .mac-main-content {
        padding: var(--space-4);
        padding-bottom: max(var(--space-6), env(safe-area-inset-bottom));
        overflow-y: auto;
    }

    .sidebar-collapse-wrapper {
        padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
        background: var(--header-bg);
        backdrop-filter: blur(24px);
        -webkit-backdrop-filter: blur(24px);
    }
    #sidebarCollapseBtn { display: none; }
    .mobile-search-btn { display: inline-flex; }
    .spotlight-overlay { padding-top: 10vh; }

    /* iOS zoomt bei Fokus auf Felder mit weniger als 16px – das verhindert es,
       ohne das Pinch-Zoom der Seite zu sperren (WCAG 1.4.4). */
    input, select, textarea { font-size: max(16px, 1em); }
    .ui-page-header h1, .ui-page-header h2 { font-size: var(--text-xl); }
}

/* Zeigegeraete ohne Hover (Touch): Hover-Zustaende nicht kleben lassen */
@media (hover: none) {
    .nav-link:hover { background: transparent; color: var(--text-secondary); }
    .nav-link.active:hover { background: var(--accent-color); color: var(--text-on-accent); }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Hoher Kontrast / erzwungene Farben */
@media (forced-colors: active) {
    .nav-link.active { forced-color-adjust: none; }
}

/* =============================================================================
   10. PRINT
   ============================================================================= */
@media print {
    .mac-sidebar,
    .top-bar,
    .mobile-header,
    .sidebar-overlay,
    .spotlight-overlay,
    #globalSystemMessage,
    .skip-link,
    body::before { display: none !important; }

    body, body.app-shell, .mac-main-content {
        height: auto !important;
        overflow: visible !important;
        background: #fff !important;
        color: #000 !important;
    }
    .mac-main-content { padding: 0 !important; }
    .ui-card, .ui-table-wrap { box-shadow: none !important; border-color: #ddd !important; }
    a[href]::after { content: ""; }
}

/* ===========================================================================
   Mobile: Eingabefelder mindestens 16 px
   ---------------------------------------------------------------------------
   Safari auf dem iPhone zoomt beim Antippen in die Seite hinein, sobald ein
   Eingabefeld eine Schriftgröße UNTER 16 px hat. Die Seite springt dann näher
   heran, und nach dem Tippen bleibt sie verschoben – man muss von Hand wieder
   herauszoomen.

   Gemessen waren betroffen: Dateiliste, E-Mail-Funktionen, Benutzerliste,
   Rechteverwaltung, Protokoll, Teamgruppen und Papierkorb.

   Die naheliegende Abhilfe wäre "maximum-scale=1" in der Viewport-Angabe –
   die schaltet aber das Zoomen der ganzen Seite ab und sperrt damit Menschen
   aus, die zum Lesen vergrößern. Deshalb hier der Weg über die Schriftgröße.
   =========================================================================== */
@media (max-width: 768px) {
    /* !important ist hier bewusst gesetzt, nicht aus Bequemlichkeit.
       Die Feldgrößen stehen in <style>-Blöcken INNERHALB der einzelnen
       Ansichten (.mac-select, .ui-select, .ui-textarea, .maintenance-select …).
       Diese Blöcke stehen im Dokument HINTER dieser Datei und gewinnen damit
       bei gleicher Spezifität. Sie einzeln zu ändern hieße, dieselbe Falle in
       jeder künftigen Ansicht neu aufzustellen – die Regel gehört an eine
       Stelle. Es geht dabei nicht um Geschmack: Unter 16 px zoomt Safari beim
       Antippen ungefragt in die Seite. */
    input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="range"]),
    select,
    textarea {
        font-size: 16px !important;
    }
}

/* --- Anwesenheit in der Kopfzeile -----------------------------------------
   Zeigt, wer gerade im Portal arbeitet. Die Zahl steht immer da, die Namen
   erst auf Klick: Neben Seitentitel und Suche ist kein Platz für eine
   dauerhaft ausgeklappte Liste, und die Zahl allein beantwortet die Frage
   "ist gerade jemand da?" schon. */
/* Datum und Uhrzeit links vom Anwesenheitsanzeiger. Sie tragen dieselbe
   Pillenform wie er und das Suchfeld, damit die rechte Seite der Kopfzeile
   eine Reihe bleibt und nicht ein Text neben zwei Feldern steht.

   Mit Fuellung wie die beiden anderen, obwohl die Uhr kein Bedienelement ist.
   Ohne Fuellung stuende sie auf dem durchscheinenden Punktraster, und das
   Datum kam dort im ungueltigsten Fall auf 2,9:1 – weit unter den 4,5, die
   tokens.css verlangt. Die Alternative waere gewesen, das Datum immer weiter
   abzudunkeln, bis es mit der Uhrzeit um Aufmerksamkeit streitet. Dass hier
   nichts zu druecken ist, sagt stattdessen das Fehlen jeder Reaktion beim
   Ueberfahren. */
.kopf-uhr {
    display: inline-flex; align-items: baseline; gap: var(--space-2);
    padding: 8px 14px; border-radius: var(--radius-pill);
    border: 1px solid var(--border-color); background: var(--bg-card);
    font-size: var(--text-sm); white-space: nowrap; flex: 0 0 auto;
    /* Gleich breite Ziffern – sonst zappelt die Zeile bei jedem
       Minutenwechsel, weil die 1 schmaler ist als die uebrigen Ziffern. */
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}
.kopf-uhr-datum { color: var(--text-muted); }
.kopf-uhr-zeit { color: var(--text-primary); font-weight: 650; }

/* Zuerst weicht das Datum, die Uhrzeit bleibt. Frueher verschwand unter
   1000px die ganze Uhr – unnoetig frueh: Bis 768px steht die obere Leiste
   noch, und die Uhrzeit allein ist schmal. Darunter uebernimmt die Kopfzeile
   des Handys, siehe .mobile-header-status. */
@media (max-width: 1180px) { .kopf-uhr-datum { display: none; } }

.anwesend { position: relative; flex: 0 0 auto; }

.anwesend-knopf {
    display: inline-flex; align-items: center; gap: var(--space-2);
    padding: 8px 14px; border-radius: var(--radius-pill);
    border: 1px solid var(--border-color); background: var(--bg-card);
    font: inherit; font-size: var(--text-sm); font-weight: 600;
    color: var(--text-secondary); cursor: pointer; white-space: nowrap;
    transition: background var(--duration-base) var(--ease), border-color var(--duration-base) var(--ease);
}
.anwesend-knopf:hover { background: var(--bg-hover); border-color: var(--border-heavy); }
.anwesend-knopf:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.anwesend-punkt {
    width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
    background: var(--text-muted);
}
/* Grün nur, wenn wirklich jemand da ist. Ein dauerhaft grüner Punkt neben
   einer Null wäre eine Zusage, die die Zahl gleich wieder zurücknimmt. */
.anwesend--da .anwesend-punkt {
    background: var(--success-color, #34c759);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--success-color, #34c759) 22%, transparent);
}
.anwesend--da .anwesend-zahl { color: var(--text-primary); }
/* Der Punkt in der Kopfzeile des Handys liegt AUSSERHALB von #anwesendBereich
   und wird von .anwesend--da nicht erreicht. Deshalb setzt das Skript
   zusaetzlich eine Marke am body – eine Zustandsangabe, die die ganze Seite
   betrifft, gehoert ohnehin dorthin und nicht an ein einzelnes Element. */
body.anwesend-da .mobile-anwesend .anwesend-punkt {
    background: var(--success-color, #34c759);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--success-color, #34c759) 22%, transparent);
}
body.anwesend-da .mobile-anwesend .js-anwesend-zahl { color: var(--text-secondary); font-weight: 650; }
.anwesend-zahl { font-variant-numeric: tabular-nums; }
.anwesend-wort { color: var(--text-muted); font-weight: 500; }

.anwesend-liste {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 200;
    min-width: 230px; max-width: 300px; max-height: 340px; overflow-y: auto;
    background: var(--bg-card); border: 1px solid var(--border-color);
    border-radius: var(--radius-lg); box-shadow: 0 16px 40px var(--shadow-color);
    padding: var(--space-2);
}
.anwesend-kopf {
    padding: 6px 10px 8px; font-size: var(--text-xs); font-weight: 700;
    text-transform: uppercase; letter-spacing: .5px; color: var(--text-muted);
}
.anwesend-eintrag {
    display: flex; align-items: center; gap: var(--space-2);
    padding: 8px 10px; border-radius: var(--radius-sm);
    font-size: var(--text-sm); color: var(--text-primary); text-decoration: none;
}
a.anwesend-eintrag:hover { background: var(--bg-hover); }
.anwesend-eintrag .anwesend-punkt { background: var(--success-color, #34c759); }
.anwesend-eintrag-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anwesend-selbst { color: var(--text-muted); font-size: var(--text-xs); flex: 0 0 auto; }
.anwesend-leer { padding: 10px; font-size: var(--text-sm); color: var(--text-muted); }

/* Auf dem Telefon steckt die Kopfzeile ohnehin im Mobil-Kopf; dort ist für
   die Anzeige kein Platz. Die Zahl geht nicht verloren – sie steht dann in
   der Personenliste des Chats an jedem Namen. */
@media (max-width: 768px) { .anwesend { display: none; } }

/* Abmelden aus der Anwesenheitsliste. Der Knopf erscheint erst beim
   Überfahren der Zeile: Eine Liste mit einem roten Symbol hinter jedem
   Namen sieht aus, als wäre das Abmelden die Hauptsache – ist es nicht. */
.anwesend-eintrag { position: relative; }
a.anwesend-eintrag-name { color: inherit; text-decoration: none; flex: 1; }
a.anwesend-eintrag-name:hover { color: var(--accent-text); text-decoration: underline; }
.anwesend-eintrag > .anwesend-eintrag-name { flex: 1; }

.anwesend-abmelden {
    flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; padding: 0; border: none; border-radius: var(--radius-sm);
    background: transparent; color: var(--text-muted); cursor: pointer;
    opacity: 0; transition: opacity var(--duration-base) var(--ease), background var(--duration-base) var(--ease);
}
.anwesend-abmelden svg { width: 15px; height: 15px; }
.anwesend-eintrag:hover .anwesend-abmelden,
.anwesend-abmelden:focus-visible { opacity: 1; }
.anwesend-abmelden:hover { background: var(--danger-soft); color: var(--danger-color); }
.anwesend-abmelden:disabled { opacity: .4; cursor: default; }

/* =============================================================================
   Seitenleiste auf der Seitenflaeche
   ============================================================================= */

/* Auf dem durchscheinenden Grund sitzt Text mitunter genau auf einem
   Rasterpunkt. Der dunkelt die Flaeche dort von #f6f8fb auf #e7eaf0 ab, und
   --text-muted fiel damit von 4,6:1 auf 4,1:1 – unter die 4,5, die tokens.css
   verlangt. Eine Stufe tiefer auf der Tintenachse holt 4,9:1 auch auf dem
   Punkt, und der Abstand zu den Menuepunkten (6,2:1) bleibt erhalten.

   Nur im hellen Schema: Dort sind die Punkte dunkler als der Grund. Im
   Dunkelschema sind sie heller und der schlechteste Fall liegt bei 5,9:1 –
   da gibt es nichts zu heben. */
html:not(.dark-mode) .mac-sidebar {
    --text-muted: var(--ink-500);
    --text-tertiary: var(--ink-500);
}

/* Der Fussbereich holt seine Flaeche aus --bg-sidebar, und das ist WEISS –
   neben --bg-app faellt er als hellerer Block auf. Er laesst den Grund der
   Leiste durch. Die zweite Regel deckt die Mobilfassung mit ab, die dort
   --header-bg auftrug. */
.mac-sidebar { --bg-sidebar: transparent; }
.mac-sidebar .sidebar-collapse-wrapper {
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* Das Namenskuerzel trug den blauen Akzentverlauf. Dunkle Tinte traegt
   dieselbe Rolle ohne zweite Farbe – und passt zum aktiven Menuepunkt.
   Nur hier umgestellt; ausserhalb der Leiste bleibt der Akzent. */
.mac-sidebar .user-avatar {
    background: var(--text-primary);
    color: var(--bg-app);
    box-shadow: none;
}

/* Das Konto ist ein Link ohne eigene Farbregel – ohne diese Zeile faerbt der
   Browser ihn im Vorgabeblau. Auch das Ueberfahren darf nicht in den Akzent
   greifen, denn --accent-text ist Azur. */
.mac-sidebar .user-info { color: inherit; text-decoration: none; }
.mac-sidebar .user-info:hover .user-name { color: var(--text-primary); }

/* Der Zaehler bleibt rot: Er ist Status, keine Dekoration.

   Auf dem blauen Feld des aktiven Punktes braucht er aber einen VOLLEN
   weissen Ring, keinen durchscheinenden. Gemessen: Rot #c8262c auf Azur
   #1b62d6 ergibt 1,0:1 – exakt dieselbe Helligkeit. Die beiden trennt allein
   der Farbton, und der faellt bei einer Rot-Blau-Sehschwaeche weg; der
   Zaehler verschwaende dann in der Pille. Der bisherige Ring mit 28 Prozent
   Deckung half nicht (1,7:1). Voll deckend sind es 5,6:1 gegen die Pille und
   gegen den Zaehler, im Dunkelschema 4,6:1 und 2,4:1. */
.mac-sidebar .nav-link.active .nav-badge {
    background: var(--danger-color);
    color: var(--on-danger, #fff);
    box-shadow: 0 0 0 1.5px var(--text-on-accent);
}


/* --- Hinweise auf neue Inhalte (views/partials/hinweise.php) ---
   Stehen auf JEDER Seite über dem Inhalt, deshalb hier und nicht in einem
   Seiten-Stylesheet. Undurchsichtige Karte: Der Inhaltsbereich trägt ein
   Punktraster, und Text auf durchscheinendem Grund müsste auf einem
   Rasterpunkt nachgerechnet werden. */
.hinweis-leiste {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    width: 100%;
    max-width: var(--content-max);
    margin: 0 auto var(--space-6);
}
.hinweis-karte {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-4);
    background: var(--bg-card);
    border: 1px solid var(--accent-border);
    border-left: 4px solid var(--accent-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
}
.hinweis-symbol {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    color: var(--accent-text);
}
.hinweis-symbol svg { width: 18px; height: 18px; }
.hinweis-inhalt { flex: 1; min-width: 0; }
.hinweis-titel {
    margin: 0;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-size: var(--text-base);
    font-weight: 650;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}
.hinweis-text {
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}
.hinweis-aktionen {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.hinweis-aktionen form { margin: 0; }
/* „Ansehen“ ist ein <a>, „Ausblenden“ ein <button> – ohne das zählte beim
   Link das Padding zur Mindesthöhe dazu. */
.hinweis-aktionen .ui-btn { box-sizing: border-box; }
/* Nach der Breite der Leiste, nicht des Fensters: Dieselbe Karte steht auch
   in der schmalen Vorschau der Verwaltung (views/hinweise.php). Ist sie
   schmal, rutschen die Knöpfe unter den Text, statt ihn auf eine Handbreit
   zusammenzudrücken. */
.hinweis-leiste, .hinweis-vorschau-buehne { container-type: inline-size; }
@container (max-width: 560px) {
    .hinweis-karte { flex-wrap: wrap; }
    .hinweis-aktionen { width: 100%; justify-content: flex-end; }
}
/* Rückfall für Browser ohne Container-Abfragen */
@supports not (container-type: inline-size) {
    @media (max-width: 600px) {
        .hinweis-karte { flex-wrap: wrap; }
        .hinweis-aktionen { width: 100%; justify-content: flex-end; }
    }
}
